remove redundant check. Found by PVS-Studio
[freeradius.git] / src / lib / radius.c
index 747797b..245b86c 100644 (file)
@@ -14,7 +14,7 @@
  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-/*
+/**
  * $Id$
  *
  * @file radius.c
@@ -36,8 +36,13 @@ RCSID("$Id$")
 #include       <freeradius-devel/udpfromto.h>
 #endif
 
+/*
+ *     Some messages get printed out only in debugging mode.
+ */
+#define FR_DEBUG_STRERROR_PRINTF if (fr_debug_lvl) fr_strerror_printf
+
 #if 0
-#define VP_TRACE if (fr_debug_flag) printf
+#define VP_TRACE printf
 
 static void VP_HEXDUMP(char const *msg, uint8_t const *data, size_t len)
 {
@@ -50,6 +55,7 @@ static void VP_HEXDUMP(char const *msg, uint8_t const *data, size_t len)
                if ((i & 0x0f) == 0x0f) printf("\n");
        }
        if ((len == 0x0f) || ((len & 0x0f) != 0x0f)) printf("\n");
+       fflush(stdout);
 }
 
 #else
@@ -59,11 +65,6 @@ static void VP_HEXDUMP(char const *msg, uint8_t const *data, size_t len)
 
 
 /*
- *  The RFC says 4096 octets max, and most packets are less than 256.
- */
-#define MAX_PACKET_LEN 4096
-
-/*
  *     The maximum number of attributes which we allow in an incoming
  *     request.  If there are more attributes than this, the request
  *     is rejected.
@@ -151,7 +152,7 @@ void fr_printf_log(char const *fmt, ...)
        va_list ap;
 
        va_start(ap, fmt);
-       if ((fr_debug_flag == 0) || !fr_log_fp) {
+       if ((fr_debug_lvl == 0) || !fr_log_fp) {
                va_end(ap);
                return;
        }
@@ -162,7 +163,7 @@ void fr_printf_log(char const *fmt, ...)
        return;
 }
 
-static char const *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+static char const tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
 
 static void print_hex_data(uint8_t const *ptr, int attrlen, int depth)
 {
@@ -178,13 +179,38 @@ static void print_hex_data(uint8_t const *ptr, int attrlen, int depth)
 }
 
 
-void rad_print_hex(RADIUS_PACKET *packet)
+void rad_print_hex(RADIUS_PACKET const *packet)
 {
        int i;
 
        if (!packet->data || !fr_log_fp) return;
 
-       fprintf(fr_log_fp, "  Code:\t\t%u\n", packet->data[0]);
+       fprintf(fr_log_fp, "  Socket:\t%d\n", packet->sockfd);
+#ifdef WITH_TCP
+       fprintf(fr_log_fp, "  Proto:\t%d\n", packet->proto);
+#endif
+
+       if (packet->src_ipaddr.af == AF_INET) {
+               char buffer[32];
+
+               fprintf(fr_log_fp, "  Src IP:\t%s\n",
+                       inet_ntop(packet->src_ipaddr.af,
+                                 &packet->src_ipaddr.ipaddr,
+                                 buffer, sizeof(buffer)));
+               fprintf(fr_log_fp, "    port:\t%u\n", packet->src_port);
+
+               fprintf(fr_log_fp, "  Dst IP:\t%s\n",
+                       inet_ntop(packet->dst_ipaddr.af,
+                                 &packet->dst_ipaddr.ipaddr,
+                                 buffer, sizeof(buffer)));
+               fprintf(fr_log_fp, "    port:\t%u\n", packet->dst_port);
+       }
+
+       if (packet->data[0] < FR_MAX_PACKET_CODE) {
+               fprintf(fr_log_fp, "  Code:\t\t(%d) %s\n", packet->data[0], fr_packet_codes[packet->data[0]]);
+       } else {
+               fprintf(fr_log_fp, "  Code:\t\t%u\n", packet->data[0]);
+       }
        fprintf(fr_log_fp, "  Id:\t\t%u\n", packet->data[1]);
        fprintf(fr_log_fp, "  Length:\t%u\n", ((packet->data[2] << 8) |
                                   (packet->data[3])));
@@ -245,17 +271,16 @@ void rad_print_hex(RADIUS_PACKET *packet)
        fflush(stdout);
 }
 
-/**
- * @brief Wrapper for sendto which handles sendfromto, IPv6, and all
- *     possible combinations.
+/** Wrapper for sendto which handles sendfromto, IPv6, and all possible combinations
+ *
  */
 static int rad_sendto(int sockfd, void *data, size_t data_len, int flags,
 #ifdef WITH_UDPFROMTO
-                     fr_ipaddr_t *src_ipaddr, int src_port,
+                     fr_ipaddr_t *src_ipaddr, uint16_t src_port,
 #else
-                     UNUSED fr_ipaddr_t *src_ipaddr, UNUSED int src_port,
+                     UNUSED fr_ipaddr_t *src_ipaddr, UNUSED uint16_t src_port,
 #endif
-                     fr_ipaddr_t *dst_ipaddr, int dst_port)
+                     fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
 {
        int rcode;
        struct sockaddr_storage dst;
@@ -313,63 +338,80 @@ void rad_recv_discard(int sockfd)
                        (struct sockaddr *)&src, &sizeof_src);
 }
 
-
-ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, int *src_port,
-                       int *code)
+/** Basic validation of RADIUS packet header
+ *
+ * @note fr_strerror errors are only available if fr_debug_lvl > 0. This is to reduce CPU time
+ *     consumed when discarding malformed packet.
+ *
+ * @param[in] sockfd we're reading from.
+ * @param[out] src_ipaddr of the packet.
+ * @param[out] src_port of the packet.
+ * @param[out] code Pointer to where to write the packet code.
+ * @return
+ *     - -1 on failure.
+ *     - 1 on decode error.
+ *     - >= RADIUS_HDR_LEN on success. This is the packet length as specified in the header.
+ */
+ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, int *code)
 {
        ssize_t                 data_len, packet_len;
        uint8_t                 header[4];
        struct sockaddr_storage src;
        socklen_t               sizeof_src = sizeof(src);
 
-       data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK,
-                           (struct sockaddr *)&src, &sizeof_src);
+       data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK, (struct sockaddr *)&src, &sizeof_src);
        if (data_len < 0) {
                if ((errno == EAGAIN) || (errno == EINTR)) return 0;
                return -1;
        }
 
        /*
-        *      Too little data is available, discard the packet.
+        *      Convert AF.  If unknown, discard packet.
         */
-       if (data_len < 4) {
+       if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, src_port)) {
+               FR_DEBUG_STRERROR_PRINTF("Unknown address family");
                rad_recv_discard(sockfd);
 
                return 1;
+       }
 
-       } else {                /* we got 4 bytes of data. */
-               /*
-                *      See how long the packet says it is.
-                */
-               packet_len = (header[2] * 256) + header[3];
-
-               /*
-                *      The length in the packet says it's less than
-                *      a RADIUS header length: discard it.
-                */
-               if (packet_len < AUTH_HDR_LEN) {
-                       rad_recv_discard(sockfd);
+       /*
+        *      Too little data is available, discard the packet.
+        */
+       if (data_len < 4) {
+               FR_DEBUG_STRERROR_PRINTF("Expected at least 4 bytes of header data, got %zu bytes", data_len);
+invalid:
+               FR_DEBUG_STRERROR_PRINTF("Invalid data from %s: %s",
+                                        fr_inet_ntop(src_ipaddr->af, &src_ipaddr->ipaddr),
+                                        fr_strerror());
+               rad_recv_discard(sockfd);
 
-                       return 1;
+               return 1;
+       }
 
-                       /*
-                        *      Enforce RFC requirements, for sanity.
-                        *      Anything after 4k will be discarded.
-                        */
-               } else if (packet_len > MAX_PACKET_LEN) {
-                       rad_recv_discard(sockfd);
+       /*
+        *      See how long the packet says it is.
+        */
+       packet_len = (header[2] * 256) + header[3];
 
-                       return 1;
-               }
+       /*
+        *      The length in the packet says it's less than
+        *      a RADIUS header length: discard it.
+        */
+       if (packet_len < RADIUS_HDR_LEN) {
+               FR_DEBUG_STRERROR_PRINTF("Expected at least " STRINGIFY(RADIUS_HDR_LEN)  " bytes of packet "
+                                        "data, got %zu bytes", packet_len);
+               goto invalid;
        }
 
        /*
-        *      Convert AF.  If unknown, discard packet.
+        *      Enforce RFC requirements, for sanity.
+        *      Anything after 4k will be discarded.
         */
-       if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, src_port)) {
-               rad_recv_discard(sockfd);
-
-               return 1;
+       if (packet_len > MAX_PACKET_LEN) {
+               FR_DEBUG_STRERROR_PRINTF("Length field value too large, expected maximum of "
+                                        STRINGIFY(MAX_PACKET_LEN) " bytes, got %zu bytes", packet_len);
+               goto invalid;
        }
 
        *code = header[0];
@@ -382,9 +424,8 @@ ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, int *src_port,
 }
 
 
-/**
- * @brief wrapper for recvfrom, which handles recvfromto, IPv6, and all
- *     possible combinations.
+/** Wrapper for recvfrom, which handles recvfromto, IPv6, and all possible combinations
+ *
  */
 static ssize_t rad_recvfrom(int sockfd, RADIUS_PACKET *packet, int flags,
                            fr_ipaddr_t *src_ipaddr, uint16_t *src_port,
@@ -397,7 +438,7 @@ static ssize_t rad_recvfrom(int sockfd, RADIUS_PACKET *packet, int flags,
        ssize_t                 data_len;
        uint8_t                 header[4];
        size_t                  len;
-       int                     port;
+       uint16_t                port;
 
        memset(&src, 0, sizeof_src);
        memset(&dst, 0, sizeof_dst);
@@ -432,7 +473,7 @@ static ssize_t rad_recvfrom(int sockfd, RADIUS_PACKET *packet, int flags,
                 *      The length in the packet says it's less than
                 *      a RADIUS header length: discard it.
                 */
-               if (len < AUTH_HDR_LEN) {
+               if (len < RADIUS_HDR_LEN) {
                        recvfrom(sockfd, header, sizeof(header), flags,
                                 (struct sockaddr *)&src, &sizeof_src);
                        return 0;
@@ -493,14 +534,12 @@ static ssize_t rad_recvfrom(int sockfd, RADIUS_PACKET *packet, int flags,
 
 
 #define AUTH_PASS_LEN (AUTH_VECTOR_LEN)
-/**
- * @brief Build an encrypted secret value to return in a reply packet
- *
- *            The secret is hidden by xoring with a MD5 digest
- *            created from the shared secret and the authentication
- *            vector.  We put them into MD5 in the reverse order from
- *            that used when encrypting passwords to RADIUS.
+/** Build an encrypted secret value to return in a reply packet
  *
+ * The secret is hidden by xoring with a MD5 digest created from
+ * the shared secret and the authentication vector.
+ * We put them into MD5 in the reverse order from that used when
+ * encrypting passwords to RADIUS.
  */
 static void make_secret(uint8_t *digest, uint8_t const *vector,
                        char const *secret, uint8_t const *value)
@@ -508,10 +547,10 @@ static void make_secret(uint8_t *digest, uint8_t const *vector,
        FR_MD5_CTX context;
        int          i;
 
-       fr_MD5Init(&context);
-       fr_MD5Update(&context, vector, AUTH_VECTOR_LEN);
-       fr_MD5Update(&context, (uint8_t const *) secret, strlen(secret));
-       fr_MD5Final(digest, &context);
+       fr_md5_init(&context);
+       fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
+       fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
+       fr_md5_final(digest, &context);
 
        for ( i = 0; i < AUTH_VECTOR_LEN; i++ ) {
                digest[i] ^= value[i];
@@ -549,24 +588,24 @@ static void make_passwd(uint8_t *output, ssize_t *outlen,
        }
        *outlen = len;
 
-       fr_MD5Init(&context);
-       fr_MD5Update(&context, (uint8_t const *) secret, strlen(secret));
+       fr_md5_init(&context);
+       fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
        old = context;
 
        /*
         *      Do first pass.
         */
-       fr_MD5Update(&context, vector, AUTH_PASS_LEN);
+       fr_md5_update(&context, vector, AUTH_PASS_LEN);
 
        for (n = 0; n < len; n += AUTH_PASS_LEN) {
                if (n > 0) {
                        context = old;
-                       fr_MD5Update(&context,
+                       fr_md5_update(&context,
                                       passwd + n - AUTH_PASS_LEN,
                                       AUTH_PASS_LEN);
                }
 
-               fr_MD5Final(digest, &context);
+               fr_md5_final(digest, &context);
                for (i = 0; i < AUTH_PASS_LEN; i++) {
                        passwd[i + n] ^= digest[i];
                }
@@ -575,62 +614,59 @@ static void make_passwd(uint8_t *output, ssize_t *outlen,
        memcpy(output, passwd, len);
 }
 
+
 static void make_tunnel_passwd(uint8_t *output, ssize_t *outlen,
                               uint8_t const *input, size_t inlen, size_t room,
                               char const *secret, uint8_t const *vector)
 {
        FR_MD5_CTX context, old;
        uint8_t digest[AUTH_VECTOR_LEN];
-       uint8_t passwd[MAX_STRING_LEN + AUTH_VECTOR_LEN];
-       int     i, n;
-       int     len;
+       size_t  i, n;
+       size_t  encrypted_len;
 
        /*
-        *      Be paranoid.
+        *      The password gets encoded with a 1-byte "length"
+        *      field.  Ensure that it doesn't overflow.
         */
        if (room > 253) room = 253;
 
        /*
-        *      Account for 2 bytes of the salt, and round the room
-        *      available down to the nearest multiple of 16.  Then,
-        *      subtract one from that to account for the length byte,
-        *      and the resulting number is the upper bound on the data
-        *      to copy.
-        *
-        *      We could short-cut this calculation just be forcing
-        *      inlen to be no more than 239.  It would work for all
-        *      VSA's, as we don't pack multiple VSA's into one
-        *      attribute.
-        *
-        *      However, this calculation is more general, if a little
-        *      complex.  And it will work in the future for all possible
-        *      kinds of weird attribute packing.
+        *      Limit the maximum size of the input password.  2 bytes
+        *      are taken up by the salt, and one by the encoded
+        *      "length" field.  Note that if we have a tag, the
+        *      "room" will be 252 octets, not 253 octets.
         */
-       room -= 2;
-       room -= (room & 0x0f);
-       room--;
-
-       if (inlen > room) inlen = room;
+       if (inlen > (room - 3)) inlen = room - 3;
 
        /*
-        *      Length of the encrypted data is password length plus
-        *      one byte for the length of the password.
+        *      Length of the encrypted data is the clear-text
+        *      password length plus one byte which encodes the length
+        *      of the password.  We round up to the nearest encoding
+        *      block.  Note that this can result in the encoding
+        *      length being more than 253 octets.
         */
-       len = inlen + 1;
-       if ((len & 0x0f) != 0) {
-               len += 0x0f;
-               len &= ~0x0f;
+       encrypted_len = inlen + 1;
+       if ((encrypted_len & 0x0f) != 0) {
+               encrypted_len += 0x0f;
+               encrypted_len &= ~0x0f;
        }
-       *outlen = len + 2;      /* account for the salt */
 
        /*
-        *      Copy the password over.
+        *      We need 2 octets for the salt, followed by the actual
+        *      encrypted data.
         */
-       memcpy(passwd + 3, input, inlen);
-       memset(passwd + 3 + inlen, 0, sizeof(passwd) - 3 - inlen);
+       if (encrypted_len > (room - 2)) encrypted_len = room - 2;
+
+       *outlen = encrypted_len + 2;    /* account for the salt */
 
        /*
-        *      Generate salt.  The RFC's say:
+        *      Copy the password over, and zero-fill the remainder.
+        */
+       memcpy(output + 3, input, inlen);
+       memset(output + 3 + inlen, 0, *outlen - 3 - inlen);
+
+       /*
+        *      Generate salt.  The RFCs say:
         *
         *      The high bit of salt[0] must be set, each salt in a
         *      packet should be unique, and they should be random
@@ -638,39 +674,42 @@ static void make_tunnel_passwd(uint8_t *output, ssize_t *outlen,
         *      So, we set the high bit, add in a counter, and then
         *      add in some CSPRNG data.  should be OK..
         */
-       passwd[0] = (0x80 | ( ((salt_offset++) & 0x0f) << 3) |
+       output[0] = (0x80 | ( ((salt_offset++) & 0x0f) << 3) |
                     (fr_rand() & 0x07));
-       passwd[1] = fr_rand();
-       passwd[2] = inlen;      /* length of the password string */
+       output[1] = fr_rand();
+       output[2] = inlen;      /* length of the password string */
 
-       fr_MD5Init(&context);
-       fr_MD5Update(&context, (uint8_t const *) secret, strlen(secret));
+       fr_md5_init(&context);
+       fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
        old = context;
 
-       fr_MD5Update(&context, vector, AUTH_VECTOR_LEN);
-       fr_MD5Update(&context, &passwd[0], 2);
+       fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
+       fr_md5_update(&context, &output[0], 2);
+
+       for (n = 0; n < encrypted_len; n += AUTH_PASS_LEN) {
+               size_t block_len;
 
-       for (n = 0; n < len; n += AUTH_PASS_LEN) {
                if (n > 0) {
                        context = old;
-                       fr_MD5Update(&context,
-                                      passwd + 2 + n - AUTH_PASS_LEN,
+                       fr_md5_update(&context,
+                                      output + 2 + n - AUTH_PASS_LEN,
                                       AUTH_PASS_LEN);
                }
 
-               fr_MD5Final(digest, &context);
+               fr_md5_final(digest, &context);
 
-               for (i = 0; i < AUTH_PASS_LEN; i++) {
-                       passwd[i + 2 + n] ^= digest[i];
+               if ((2 + n + AUTH_PASS_LEN) < room) {
+                       block_len = AUTH_PASS_LEN;
+               } else {
+                       block_len = room - 2 - n;
+               }
+
+               for (i = 0; i < block_len; i++) {
+                       output[i + 2 + n] ^= digest[i];
                }
        }
-       memcpy(output, passwd, len + 2);
 }
 
-extern int fr_attr_max_tlv;
-extern int fr_attr_shift[];
-extern int fr_attr_mask[];
-
 static int do_next_tlv(VALUE_PAIR const *vp, VALUE_PAIR const *next, int nest)
 {
        unsigned int tlv1, tlv2;
@@ -723,10 +762,10 @@ static ssize_t vp2attr_rfc(RADIUS_PACKET const *packet,
                           char const *secret, VALUE_PAIR const **pvp,
                           unsigned int attribute, uint8_t *ptr, size_t room);
 
-/**
- * @brief This is really a sub-function of vp2data_any().  It encodes
- *     the *data* portion of the TLV, and assumes that the encapsulating
- *     attribute has already been encoded.
+/** Encode the *data* portion of the TLV
+ *
+ * This is really a sub-function of vp2data_any().  It encodes the *data* portion
+ * of the TLV, and assumes that the encapsulating attribute has already been encoded.
  */
 static ssize_t vp2data_tlvs(RADIUS_PACKET const *packet,
                            RADIUS_PACKET const *original,
@@ -769,7 +808,7 @@ static ssize_t vp2data_tlvs(RADIUS_PACKET const *packet,
                ptr[1] += len;
 
 #ifndef NDEBUG
-               if ((fr_debug_flag > 3) && fr_log_fp) {
+               if ((fr_debug_lvl > 3) && fr_log_fp) {
                        fprintf(fr_log_fp, "\t\t%02x %02x  ", ptr[0], ptr[1]);
                        print_hex_data(ptr + 2, len, 3);
                }
@@ -783,7 +822,7 @@ static ssize_t vp2data_tlvs(RADIUS_PACKET const *packet,
        }
 
 #ifndef NDEBUG
-       if ((fr_debug_flag > 3) && fr_log_fp) {
+       if ((fr_debug_lvl > 3) && fr_log_fp) {
                DICT_ATTR const *da;
 
                da = dict_attrbyvalue(svp->da->attr & ((1 << fr_attr_shift[nest ]) - 1), svp->da->vendor);
@@ -794,8 +833,8 @@ static ssize_t vp2data_tlvs(RADIUS_PACKET const *packet,
        return ptr - start;
 }
 
-/**
- * @brief Encodes the data portion of an attribute.
+/** Encodes the data portion of an attribute
+ *
  * @return -1 on error, or the length of the data portion.
  */
 static ssize_t vp2data_any(RADIUS_PACKET const *packet,
@@ -828,29 +867,23 @@ static ssize_t vp2data_any(RADIUS_PACKET const *packet,
                                    start, room);
        }
 
-       debug_pair(vp);
-
        /*
         *      Set up the default sources for the data.
         */
-       len = vp->length;
+       len = vp->vp_length;
 
-       switch(vp->da->type) {
+       switch (vp->da->type) {
        case PW_TYPE_STRING:
        case PW_TYPE_OCTETS:
-       case PW_TYPE_TLV:
                data = vp->data.ptr;
-               if (!data) {
-                       fr_strerror_printf("ERROR: Cannot encode NULL data");
-                       return -1;
-               }
+               if (!data) return 0;
                break;
 
        case PW_TYPE_IFID:
-       case PW_TYPE_IPADDR:
-       case PW_TYPE_IPV6ADDR:
-       case PW_TYPE_IPV6PREFIX:
-       case PW_TYPE_IPV4PREFIX:
+       case PW_TYPE_IPV4_ADDR:
+       case PW_TYPE_IPV6_ADDR:
+       case PW_TYPE_IPV6_PREFIX:
+       case PW_TYPE_IPV4_PREFIX:
        case PW_TYPE_ABINARY:
        case PW_TYPE_ETHERNET:  /* just in case */
                data = (uint8_t const *) &vp->data;
@@ -946,8 +979,8 @@ static ssize_t vp2data_any(RADIUS_PACKET const *packet,
                if (room < (18 + lvalue)) return 0;
 
                switch (packet->code) {
-               case PW_CODE_AUTHENTICATION_ACK:
-               case PW_CODE_AUTHENTICATION_REJECT:
+               case PW_CODE_ACCESS_ACCEPT:
+               case PW_CODE_ACCESS_REJECT:
                case PW_CODE_ACCESS_CHALLENGE:
                default:
                        if (!original) {
@@ -959,13 +992,15 @@ static ssize_t vp2data_any(RADIUS_PACKET const *packet,
                        make_tunnel_passwd(ptr + lvalue, &len, data, len,
                                           room - lvalue,
                                           secret, original->vector);
+                       len += lvalue;
                        break;
                case PW_CODE_ACCOUNTING_REQUEST:
                case PW_CODE_DISCONNECT_REQUEST:
                case PW_CODE_COA_REQUEST:
                        ptr[0] = TAG_VALID(vp->tag) ? vp->tag : TAG_NONE;
-                       make_tunnel_passwd(ptr + 1, &len, data, len - 1, room,
+                       make_tunnel_passwd(ptr + 1, &len, data, len, room - 1,
                                           secret, packet->vector);
+                       len += lvalue;
                        break;
                }
                break;
@@ -1042,7 +1077,7 @@ static ssize_t attr_shift(uint8_t const *start, uint8_t const *end,
 
                len -= sublen;
                memmove(ptr + 255 + hdr_len, ptr + 255, sublen);
-               memcpy(ptr + 255, ptr, hdr_len);
+               memmove(ptr + 255, ptr, hdr_len);
                ptr[1] += sublen;
                if (vsa_offset) ptr[vsa_offset] += sublen;
                ptr[flag_offset] |= 0x80;
@@ -1059,8 +1094,7 @@ static ssize_t attr_shift(uint8_t const *start, uint8_t const *end,
 }
 
 
-/**
- * @brief Encode an "extended" attribute.
+/** Encode an "extended" attribute
  */
 int rad_vp2extended(RADIUS_PACKET const *packet,
                    RADIUS_PACKET const *original,
@@ -1144,7 +1178,7 @@ int rad_vp2extended(RADIUS_PACKET const *packet,
        ptr[1] += len;
 
 #ifndef NDEBUG
-       if ((fr_debug_flag > 3) && fr_log_fp) {
+       if ((fr_debug_lvl > 3) && fr_log_fp) {
                int jump = 3;
 
                fprintf(fr_log_fp, "\t\t%02x %02x  ", ptr[0], ptr[1]);
@@ -1175,8 +1209,8 @@ int rad_vp2extended(RADIUS_PACKET const *packet,
 }
 
 
-/**
- * @brief Encode a WiMAX attribute.
+/** Encode a WiMAX attribute
+ *
  */
 int rad_vp2wimax(RADIUS_PACKET const *packet,
                 RADIUS_PACKET const *original,
@@ -1237,7 +1271,7 @@ int rad_vp2wimax(RADIUS_PACKET const *packet,
        ptr[7] += len;
 
 #ifndef NDEBUG
-       if ((fr_debug_flag > 3) && fr_log_fp) {
+       if ((fr_debug_lvl > 3) && fr_log_fp) {
                fprintf(fr_log_fp, "\t\t%02x %02x  %02x%02x%02x%02x (%u)  %02x %02x %02x   ",
                       ptr[0], ptr[1],
                       ptr[2], ptr[3], ptr[4], ptr[5],
@@ -1250,11 +1284,10 @@ int rad_vp2wimax(RADIUS_PACKET const *packet,
        return (ptr + ptr[1]) - start;
 }
 
-/**
- * @brief Encode an RFC format attribute, with the "concat" flag set.
+/** Encode an RFC format attribute, with the "concat" flag set
  *
- *     If there isn't enough room in the packet, the data is
- *     truncated to fit.
+ * If there isn't enough room in the packet, the data is
+ * truncated to fit.
  */
 static ssize_t vp2attr_concat(UNUSED RADIUS_PACKET const *packet,
                              UNUSED RADIUS_PACKET const *original,
@@ -1268,10 +1301,8 @@ static ssize_t vp2attr_concat(UNUSED RADIUS_PACKET const *packet,
 
        VERIFY_VP(vp);
 
-       debug_pair(vp);
-
        p = vp->vp_octets;
-       len = vp->length;
+       len = vp->vp_length;
 
        while (len > 0) {
                if (room <= 2) break;
@@ -1290,7 +1321,7 @@ static ssize_t vp2attr_concat(UNUSED RADIUS_PACKET const *packet,
                memcpy(ptr + 2, p, left);
 
 #ifndef NDEBUG
-               if ((fr_debug_flag > 3) && fr_log_fp) {
+               if ((fr_debug_lvl > 3) && fr_log_fp) {
                        fprintf(fr_log_fp, "\t\t%02x %02x  ", ptr[0], ptr[1]);
                        print_hex_data(ptr + 2, len, 3);
                }
@@ -1306,13 +1337,11 @@ static ssize_t vp2attr_concat(UNUSED RADIUS_PACKET const *packet,
        return ptr - start;
 }
 
-/**
- * @brief Encode an RFC format TLV.
+/** Encode an RFC format TLV.
  *
- *     This could be a standard attribute,
- *     or a TLV data type.  If it's a standard attribute, then
- *     vp->da->attr == attribute.  Otherwise, attribute may be
- *     something else.
+ * This could be a standard attribute, or a TLV data type.
+ * If it's a standard attribute, then vp->da->attr == attribute.
+ * Otherwise, attribute may be something else.
  */
 static ssize_t vp2attr_rfc(RADIUS_PACKET const *packet,
                           RADIUS_PACKET const *original,
@@ -1326,15 +1355,15 @@ static ssize_t vp2attr_rfc(RADIUS_PACKET const *packet,
        ptr[0] = attribute & 0xff;
        ptr[1] = 2;
 
-       if (room > ((unsigned) 255 - ptr[1])) room = 255 - ptr[1];
+       if (room > 255) room = 255;
 
-       len = vp2data_any(packet, original, secret, 0, pvp, ptr + ptr[1], room);
+       len = vp2data_any(packet, original, secret, 0, pvp, ptr + ptr[1], room - ptr[1]);
        if (len <= 0) return len;
 
        ptr[1] += len;
 
 #ifndef NDEBUG
-       if ((fr_debug_flag > 3) && fr_log_fp) {
+       if ((fr_debug_lvl > 3) && fr_log_fp) {
                fprintf(fr_log_fp, "\t\t%02x %02x  ", ptr[0], ptr[1]);
                print_hex_data(ptr + 2, len, 3);
        }
@@ -1344,9 +1373,9 @@ static ssize_t vp2attr_rfc(RADIUS_PACKET const *packet,
 }
 
 
-/**
- * @brief Encode a VSA which is a TLV.  If it's in the RFC format, call
- *     vp2attr_rfc.  Otherwise, encode it here.
+/** Encode a VSA which is a TLV
+ *
+ * If it's in the RFC format, call vp2attr_rfc.  Otherwise, encode it here.
  */
 static ssize_t vp2attr_vsa(RADIUS_PACKET const *packet,
                           RADIUS_PACKET const *original,
@@ -1413,36 +1442,34 @@ static ssize_t vp2attr_vsa(RADIUS_PACKET const *packet,
 
        }
 
-       if (room > ((unsigned) 255 - (dv->type + dv->length))) {
-               room = 255 - (dv->type + dv->length);
-       }
+       if (room > 255) room = 255;
 
        len = vp2data_any(packet, original, secret, 0, pvp,
-                         ptr + dv->type + dv->length, room);
+                         ptr + dv->type + dv->length, room - (dv->type + dv->length));
        if (len <= 0) return len;
 
        if (dv->length) ptr[dv->type + dv->length - 1] += len;
 
 #ifndef NDEBUG
-       if ((fr_debug_flag > 3) && fr_log_fp) {
+       if ((fr_debug_lvl > 3) && fr_log_fp) {
                switch (dv->type) {
                default:
                        break;
 
                case 4:
-                       if ((fr_debug_flag > 3) && fr_log_fp)
+                       if ((fr_debug_lvl > 3) && fr_log_fp)
                                fprintf(fr_log_fp, "\t\t%02x%02x%02x%02x ",
                                        ptr[0], ptr[1], ptr[2], ptr[3]);
                        break;
 
                case 2:
-                       if ((fr_debug_flag > 3) && fr_log_fp)
+                       if ((fr_debug_lvl > 3) && fr_log_fp)
                                fprintf(fr_log_fp, "\t\t%02x%02x ",
                                        ptr[0], ptr[1]);
                break;
 
                case 1:
-                       if ((fr_debug_flag > 3) && fr_log_fp)
+                       if ((fr_debug_lvl > 3) && fr_log_fp)
                                fprintf(fr_log_fp, "\t\t%02x ", ptr[0]);
                        break;
                }
@@ -1474,8 +1501,8 @@ static ssize_t vp2attr_vsa(RADIUS_PACKET const *packet,
 }
 
 
-/**
- * @brief Encode a Vendor-Specific attribute.
+/** Encode a Vendor-Specific attribute
+ *
  */
 int rad_vp2vsa(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
                char const *secret, VALUE_PAIR const **pvp, uint8_t *ptr,
@@ -1486,12 +1513,17 @@ int rad_vp2vsa(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
        VALUE_PAIR const *vp = *pvp;
 
        VERIFY_VP(vp);
+
+       if (vp->da->vendor == 0) {
+               fr_strerror_printf("rad_vp2vsa called with rfc attribute");
+               return -1;
+       }
+
        /*
         *      Double-check for WiMAX format.
         */
        if (vp->da->flags.wimax) {
-               return rad_vp2wimax(packet, original, secret, pvp,
-                                   ptr, room);
+               return rad_vp2wimax(packet, original, secret, pvp, ptr, room);
        }
 
        if (vp->da->vendor > FR_MAX_VENDOR) {
@@ -1513,15 +1545,15 @@ int rad_vp2vsa(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
        lvalue = htonl(vp->da->vendor);
        memcpy(ptr + 2, &lvalue, 4);
 
-       if (room > ((unsigned) 255 - ptr[1])) room = 255 - ptr[1];
+       if (room > 255) room = 255;
 
        len = vp2attr_vsa(packet, original, secret, pvp,
                          vp->da->attr, vp->da->vendor,
-                         ptr + ptr[1], room);
+                         ptr + ptr[1], room - ptr[1]);
        if (len < 0) return len;
 
 #ifndef NDEBUG
-       if ((fr_debug_flag > 3) && fr_log_fp) {
+       if ((fr_debug_lvl > 3) && fr_log_fp) {
                fprintf(fr_log_fp, "\t\t%02x %02x  %02x%02x%02x%02x (%u)  ",
                       ptr[0], ptr[1],
                       ptr[2], ptr[3], ptr[4], ptr[5],
@@ -1536,8 +1568,8 @@ int rad_vp2vsa(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
 }
 
 
-/**
- * @brief Encode an RFC standard attribute 1..255
+/** Encode an RFC standard attribute 1..255
+ *
  */
 int rad_vp2rfc(RADIUS_PACKET const *packet,
               RADIUS_PACKET const *original,
@@ -1562,7 +1594,7 @@ int rad_vp2rfc(RADIUS_PACKET const *packet,
         *      Only CUI is allowed to have zero length.
         *      Thank you, WiMAX!
         */
-       if ((vp->length == 0) &&
+       if ((vp->vp_length == 0) &&
            (vp->da->attr == PW_CHARGEABLE_USER_IDENTITY)) {
                ptr[0] = PW_CHARGEABLE_USER_IDENTITY;
                ptr[1] = 2;
@@ -1577,12 +1609,11 @@ int rad_vp2rfc(RADIUS_PACKET const *packet,
        if (vp->da->attr == PW_MESSAGE_AUTHENTICATOR) {
                if (room < 18) return -1;
 
-               debug_pair(vp);
                ptr[0] = PW_MESSAGE_AUTHENTICATOR;
                ptr[1] = 18;
                memset(ptr + 2, 0, 16);
 #ifndef NDEBUG
-               if ((fr_debug_flag > 3) && fr_log_fp) {
+               if ((fr_debug_lvl > 3) && fr_log_fp) {
                        fprintf(fr_log_fp, "\t\t50 12 ...\n");
                }
 #endif
@@ -1594,7 +1625,7 @@ int rad_vp2rfc(RADIUS_PACKET const *packet,
        /*
         *      EAP-Message is special.
         */
-       if (vp->da->flags.concat && (vp->length > 253)) {
+       if (vp->da->flags.concat && (vp->vp_length > 253)) {
                return vp2attr_concat(packet, original, secret, pvp, vp->da->attr,
                                      ptr, room);
        }
@@ -1647,8 +1678,8 @@ static ssize_t rad_vp2rfctlv(RADIUS_PACKET const *packet,
        return start[1];
 }
 
-/**
- * @brief Parse a data structure into a RADIUS attribute.
+/** Parse a data structure into a RADIUS attribute
+ *
  */
 int rad_vp2attr(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
                char const *secret, VALUE_PAIR const **pvp, uint8_t *start,
@@ -1666,7 +1697,10 @@ int rad_vp2attr(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
         *      RFC format attributes take the fast path.
         */
        if (!vp->da->vendor) {
-               if (vp->da->attr > 255) return 0;
+               if (vp->da->attr > 255) {
+                       *pvp = vp->next;
+                       return 0;
+               }
 
                return rad_vp2rfc(packet, original, secret, pvp,
                                  start, room);
@@ -1691,13 +1725,12 @@ int rad_vp2attr(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
                                    start, room);
        }
 
-       return rad_vp2vsa(packet, original, secret, pvp,
-                         start, room);
+       return rad_vp2vsa(packet, original, secret, pvp, start, room);
 }
 
 
-/**
- * @brief Encode a packet.
+/** Encode a packet
+ *
  */
 int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
               char const *secret)
@@ -1707,38 +1740,18 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
        uint16_t                total_length;
        int                     len;
        VALUE_PAIR const        *reply;
-       char const              *what;
-       char                    ip_src_buffer[INET6_ADDRSTRLEN];
-       char                    ip_dst_buffer[INET6_ADDRSTRLEN];
 
        /*
         *      A 4K packet, aligned on 64-bits.
         */
        uint64_t        data[MAX_PACKET_LEN / sizeof(uint64_t)];
 
-       if (is_radius_code(packet->code)) {
-               what = fr_packet_codes[packet->code];
-       } else {
-               what = "Reply";
-       }
-
-       DEBUG("Sending %s Id %d from %s:%u to %s:%u\n",
-             what, packet->id,
-             inet_ntop(packet->src_ipaddr.af,
-                       &packet->src_ipaddr.ipaddr,
-                       ip_src_buffer, sizeof(ip_src_buffer)),
-             packet->src_port,
-             inet_ntop(packet->dst_ipaddr.af,
-                       &packet->dst_ipaddr.ipaddr,
-                       ip_dst_buffer, sizeof(ip_dst_buffer)),
-             packet->dst_port);
-
        /*
         *      Double-check some things based on packet code.
         */
        switch (packet->code) {
-       case PW_CODE_AUTHENTICATION_ACK:
-       case PW_CODE_AUTHENTICATION_REJECT:
+       case PW_CODE_ACCESS_ACCEPT:
+       case PW_CODE_ACCESS_REJECT:
        case PW_CODE_ACCESS_CHALLENGE:
                if (!original) {
                        fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
@@ -1773,7 +1786,7 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
 
        memcpy(hdr->vector, packet->vector, sizeof(hdr->vector));
 
-       total_length = AUTH_HDR_LEN;
+       total_length = RADIUS_HDR_LEN;
 
        /*
         *      Load up the configuration values for the user
@@ -1795,7 +1808,7 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
         */
        reply = packet->vps;
        while (reply) {
-               size_t last_len;
+               size_t last_len, room;
                char const *last_name = NULL;
 
                VERIFY_VP(reply);
@@ -1813,8 +1826,8 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                         *      attributes with a debug build.
                         */
                        if (reply->da->attr == PW_RAW_ATTRIBUTE) {
-                               memcpy(ptr, reply->vp_octets, reply->length);
-                               len = reply->length;
+                               memcpy(ptr, reply->vp_octets, reply->vp_length);
+                               len = reply->vp_length;
                                reply = reply->next;
                                goto next;
                        }
@@ -1824,10 +1837,24 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                }
 
                /*
+                *      We allow zero-length strings in "unlang", but
+                *      skip them (except for CUI, thanks WiMAX!) on
+                *      all other attributes.
+                */
+               if (reply->vp_length == 0) {
+                       if ((reply->da->vendor != 0) ||
+                           ((reply->da->attr != PW_CHARGEABLE_USER_IDENTITY) &&
+                            (reply->da->attr != PW_MESSAGE_AUTHENTICATOR))) {
+                               reply = reply->next;
+                               continue;
+                       }
+               }
+
+               /*
                 *      Set the Message-Authenticator to the correct
                 *      length and initial value.
                 */
-               if (reply->da->attr == PW_MESSAGE_AUTHENTICATOR) {
+               if (!reply->da->vendor && (reply->da->attr == PW_MESSAGE_AUTHENTICATOR)) {
                        /*
                         *      Cache the offset to the
                         *      Message-Authenticator
@@ -1835,12 +1862,15 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                        packet->offset = total_length;
                        last_len = 16;
                } else {
-                       last_len = reply->length;
+                       last_len = reply->vp_length;
                }
                last_name = reply->da->name;
 
-               len = rad_vp2attr(packet, original, secret, &reply, ptr,
-                                 ((uint8_t *) data) + sizeof(data) - ptr);
+               room = ((uint8_t *) data) + sizeof(data) - ptr;
+
+               if (room <= 2) break;
+
+               len = rad_vp2attr(packet, original, secret, &reply, ptr, room);
                if (len < 0) return -1;
 
                /*
@@ -1888,8 +1918,8 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
 }
 
 
-/**
- * @brief Sign a previously encoded packet.
+/** Sign a previously encoded packet
+ *
  */
 int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
             char const *secret)
@@ -1904,15 +1934,51 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                return -1;
        }
 
-       if (!packet->data || (packet->data_len < AUTH_HDR_LEN) ||
+       if (!packet->data || (packet->data_len < RADIUS_HDR_LEN) ||
            (packet->offset < 0)) {
                fr_strerror_printf("ERROR: You must call rad_encode() before rad_sign()");
                return -1;
        }
 
        /*
+        *      Set up the authentication vector with zero, or with
+        *      the original vector, prior to signing.
+        */
+       switch (packet->code) {
+       case PW_CODE_ACCOUNTING_REQUEST:
+       case PW_CODE_DISCONNECT_REQUEST:
+       case PW_CODE_COA_REQUEST:
+               memset(packet->vector, 0, AUTH_VECTOR_LEN);
+               break;
+
+       case PW_CODE_ACCESS_ACCEPT:
+       case PW_CODE_ACCESS_REJECT:
+       case PW_CODE_ACCESS_CHALLENGE:
+       case PW_CODE_ACCOUNTING_RESPONSE:
+       case PW_CODE_DISCONNECT_ACK:
+       case PW_CODE_DISCONNECT_NAK:
+       case PW_CODE_COA_ACK:
+       case PW_CODE_COA_NAK:
+               if (!original) {
+                       fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
+                       return -1;
+               }
+               memcpy(packet->vector, original->vector, AUTH_VECTOR_LEN);
+               break;
+
+       case PW_CODE_ACCESS_REQUEST:
+       case PW_CODE_STATUS_SERVER:
+       default:
+               break;          /* packet->vector is already random bytes */
+       }
+
+#ifndef NDEBUG
+       if ((fr_debug_lvl > 3) && fr_log_fp) rad_print_hex(packet);
+#endif
+
+       /*
         *      If there's a Message-Authenticator, update it
-        *      now, BEFORE updating the authentication vector.
+        *      now.
         */
        if (packet->offset > 0) {
                uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
@@ -1929,24 +1995,19 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                case PW_CODE_DISCONNECT_NAK:
                case PW_CODE_COA_REQUEST:
                case PW_CODE_COA_ACK:
+               case PW_CODE_COA_NAK:
                        memset(hdr->vector, 0, AUTH_VECTOR_LEN);
                        break;
 
                do_ack:
-               case PW_CODE_AUTHENTICATION_ACK:
-               case PW_CODE_AUTHENTICATION_REJECT:
+               case PW_CODE_ACCESS_ACCEPT:
+               case PW_CODE_ACCESS_REJECT:
                case PW_CODE_ACCESS_CHALLENGE:
-                       if (!original) {
-                               fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
-                               return -1;
-                       }
-                       memcpy(hdr->vector, original->vector,
-                              AUTH_VECTOR_LEN);
+                       memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN);
                        break;
 
-               default:        /* others have vector already set to zero */
+               default:
                        break;
-
                }
 
                /*
@@ -1955,29 +2016,27 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                 *      into the Message-Authenticator
                 *      attribute.
                 */
-               fr_hmac_md5(packet->data, packet->data_len,
-                           (uint8_t const *) secret, strlen(secret),
-                           calc_auth_vector);
+               fr_hmac_md5(calc_auth_vector, packet->data, packet->data_len,
+                           (uint8_t const *) secret, strlen(secret));
                memcpy(packet->data + packet->offset + 2,
                       calc_auth_vector, AUTH_VECTOR_LEN);
-
-               /*
-                *      Copy the original request vector back
-                *      to the raw packet.
-                */
-               memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
        }
 
        /*
+        *      Copy the request authenticator over to the packet.
+        */
+       memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
+
+       /*
         *      Switch over the packet code, deciding how to
         *      sign the packet.
         */
        switch (packet->code) {
                /*
-                *      Request packets are not signed, bur
+                *      Request packets are not signed, but
                 *      have a random authentication vector.
                 */
-       case PW_CODE_AUTHENTICATION_REQUEST:
+       case PW_CODE_ACCESS_REQUEST:
        case PW_CODE_STATUS_SERVER:
                break;
 
@@ -1990,11 +2049,11 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                        uint8_t digest[16];
 
                        FR_MD5_CTX      context;
-                       fr_MD5Init(&context);
-                       fr_MD5Update(&context, packet->data, packet->data_len);
-                       fr_MD5Update(&context, (uint8_t const *) secret,
+                       fr_md5_init(&context);
+                       fr_md5_update(&context, packet->data, packet->data_len);
+                       fr_md5_update(&context, (uint8_t const *) secret,
                                     strlen(secret));
-                       fr_MD5Final(digest, &context);
+                       fr_md5_final(digest, &context);
 
                        memcpy(hdr->vector, digest, AUTH_VECTOR_LEN);
                        memcpy(packet->vector, digest, AUTH_VECTOR_LEN);
@@ -2005,18 +2064,13 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
        return 0;
 }
 
-/**
- * @brief Reply to the request.  Also attach
- *     reply attribute value pairs and any user message provided.
+/** Reply to the request
+ *
+ * Also attach reply attribute value pairs and any user message provided.
  */
 int rad_send(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
             char const *secret)
 {
-       VALUE_PAIR              *reply;
-       char const              *what;
-       char                    ip_src_buffer[128];
-       char                    ip_dst_buffer[128];
-
        /*
         *      Maybe it's a fake packet.  Don't send it.
         */
@@ -2024,12 +2078,6 @@ int rad_send(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                return 0;
        }
 
-       if (is_radius_code(packet->code)) {
-               what = fr_packet_codes[packet->code];
-       } else {
-               what = "Reply";
-       }
-
        /*
         *  First time through, allocate room for the packet
         */
@@ -2053,25 +2101,10 @@ int rad_send(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                 *      If packet->data points to data, then we print out
                 *      the VP list again only for debugging.
                 */
-       } else if (fr_debug_flag) {
-               DEBUG("Sending %s Id %d from %s:%u to %s:%u\n", what,
-                     packet->id,
-                     inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr,
-                               ip_src_buffer, sizeof(ip_src_buffer)),
-                     packet->src_port,
-                     inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr,
-                               ip_dst_buffer, sizeof(ip_dst_buffer)),
-                     packet->dst_port);
-
-               for (reply = packet->vps; reply; reply = reply->next) {
-                       if ((reply->da->vendor == 0) &&
-                           ((reply->da->attr & 0xFFFF) > 0xff)) continue;
-                       debug_pair(reply);
-               }
        }
 
 #ifndef NDEBUG
-       if ((fr_debug_flag > 3) && fr_log_fp) rad_print_hex(packet);
+       if ((fr_debug_lvl > 3) && fr_log_fp) rad_print_hex(packet);
 #endif
 
 #ifdef WITH_TCP
@@ -2100,15 +2133,12 @@ int rad_send(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                          &packet->dst_ipaddr, packet->dst_port);
 }
 
-/**
- * @brief Do a comparison of two authentication digests by comparing
- *     the FULL digest.
+/** Do a comparison of two authentication digests by comparing the FULL digest
  *
- *     Otherwise, the server can be subject to
- *     timing attacks that allow attackers find a valid message
- *     authenticator.
+ * Otherwise, the server can be subject to timing attacks that allow attackers
+ * find a valid message authenticator.
  *
- *     http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf
+ * http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf
  */
 int rad_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
 {
@@ -2123,9 +2153,9 @@ int rad_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
 }
 
 
-/**
- * @brief Validates the requesting client NAS.  Calculates the
- *     Request Authenticator based on the clients private key.
+/** Validates the requesting client NAS
+ *
+ * Calculates the request Authenticator based on the clients private key.
  */
 static int calc_acctdigest(RADIUS_PACKET *packet, char const *secret)
 {
@@ -2143,10 +2173,10 @@ static int calc_acctdigest(RADIUS_PACKET *packet, char const *secret)
        /*
         *  MD5(packet + secret);
         */
-       fr_MD5Init(&context);
-       fr_MD5Update(&context, packet->data, packet->data_len);
-       fr_MD5Update(&context, (uint8_t const *) secret, strlen(secret));
-       fr_MD5Final(digest, &context);
+       fr_md5_init(&context);
+       fr_md5_update(&context, packet->data, packet->data_len);
+       fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
+       fr_md5_final(digest, &context);
 
        /*
         *      Return 0 if OK, 2 if not OK.
@@ -2156,9 +2186,10 @@ static int calc_acctdigest(RADIUS_PACKET *packet, char const *secret)
 }
 
 
-/**
- * @brief Validates the requesting client NAS.  Calculates the
- *     Response Authenticator based on the clients private key.
+/** Validates the requesting client NAS
+ *
+ * Calculates the response Authenticator based on the clients
+ * private key.
  */
 static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original,
                            char const *secret)
@@ -2181,10 +2212,10 @@ static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original,
        /*
         *  MD5(packet + secret);
         */
-       fr_MD5Init(&context);
-       fr_MD5Update(&context, packet->data, packet->data_len);
-       fr_MD5Update(&context, (uint8_t const *) secret, strlen(secret));
-       fr_MD5Final(calc_digest, &context);
+       fr_md5_init(&context);
+       fr_md5_update(&context, packet->data, packet->data_len);
+       fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
+       fr_md5_final(calc_digest, &context);
 
        /*
         *  Copy the packet's vector back to the packet.
@@ -2198,15 +2229,18 @@ static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original,
        return 0;
 }
 
-
-/**
- * @brief Check if a set of RADIUS formatted TLVs are OK.
+/** Check if a set of RADIUS formatted TLVs are OK
+ *
  */
 int rad_tlv_ok(uint8_t const *data, size_t length,
               size_t dv_type, size_t dv_length)
 {
        uint8_t const *end = data + length;
 
+       VP_TRACE("checking TLV %u/%u\n", (unsigned int) dv_type, (unsigned int) dv_length);
+
+       VP_HEXDUMP("tlv_ok", data, length);
+
        if ((dv_length > 2) || (dv_type == 0) || (dv_type > 4)) {
                fr_strerror_printf("rad_tlv_ok: Invalid arguments");
                return -1;
@@ -2240,7 +2274,10 @@ int rad_tlv_ok(uint8_t const *data, size_t length,
                        break;
 
                case 1:
-                       if (data[0] == 0) goto zero;
+                       /*
+                        *      Zero is allowed, because the Colubris
+                        *      people are dumb and use it.
+                        */
                        break;
 
                default:
@@ -2253,7 +2290,7 @@ int rad_tlv_ok(uint8_t const *data, size_t length,
                        return 0;
 
                case 2:
-                       if (data[dv_type + 1] != 0) {
+                       if (data[dv_type] != 0) {
                                fr_strerror_printf("Attribute is longer than 256 octets");
                                return -1;
                        }
@@ -2307,6 +2344,8 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
        bool                    seen_ma = false;
        uint32_t                num_attributes;
        decode_fail_t           failure = DECODE_FAIL_NONE;
+       bool                    eap = false;
+       bool                    non_eap = false;
 
        /*
         *      Check for packets smaller than the packet header.
@@ -2315,12 +2354,12 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
         *
         *      "The minimum length is 20 ..."
         */
-       if (packet->data_len < AUTH_HDR_LEN) {
-               fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: too short (received %zu < minimum %d)",
+       if (packet->data_len < RADIUS_HDR_LEN) {
+               FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: too short (received %zu < minimum %d)",
                           inet_ntop(packet->src_ipaddr.af,
                                     &packet->src_ipaddr.ipaddr,
                                     host_ipaddr, sizeof(host_ipaddr)),
-                                    packet->data_len, AUTH_HDR_LEN);
+                                    packet->data_len, RADIUS_HDR_LEN);
                failure = DECODE_FAIL_MIN_LENGTH_PACKET;
                goto finish;
        }
@@ -2340,7 +2379,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
         */
        if ((hdr->code == 0) ||
            (hdr->code >= FR_MAX_PACKET_CODE)) {
-               fr_strerror_printf("WARNING: Bad RADIUS packet from host %s: unknown packet code %d",
+               FR_DEBUG_STRERROR_PRINTF("Bad RADIUS packet from host %s: unknown packet code %d",
                           inet_ntop(packet->src_ipaddr.af,
                                     &packet->src_ipaddr.ipaddr,
                                     host_ipaddr, sizeof(host_ipaddr)),
@@ -2371,12 +2410,12 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
         *
         *      "The minimum length is 20 ..."
         */
-       if (totallen < AUTH_HDR_LEN) {
-               fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: too short (length %zu < minimum %d)",
+       if (totallen < RADIUS_HDR_LEN) {
+               FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: too short (length %zu < minimum %d)",
                           inet_ntop(packet->src_ipaddr.af,
                                     &packet->src_ipaddr.ipaddr,
                                     host_ipaddr, sizeof(host_ipaddr)),
-                                    totallen, AUTH_HDR_LEN);
+                                    totallen, RADIUS_HDR_LEN);
                failure = DECODE_FAIL_MIN_LENGTH_FIELD;
                goto finish;
        }
@@ -2405,7 +2444,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
         *      i.e. No response to the NAS.
         */
        if (packet->data_len < totallen) {
-               fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: received %zu octets, packet length says %zu",
+               FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: received %zu octets, packet length says %zu",
                           inet_ntop(packet->src_ipaddr.af,
                                     &packet->src_ipaddr.ipaddr,
                                     host_ipaddr, sizeof(host_ipaddr)),
@@ -2442,7 +2481,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
         *      to be vulnerable to this problem.
         */
        attr = hdr->data;
-       count = totallen - AUTH_HDR_LEN;
+       count = totallen - RADIUS_HDR_LEN;
        num_attributes = 0;
 
        while (count > 0) {
@@ -2451,7 +2490,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
                 *      attribute header.
                 */
                if (count < 2) {
-                       fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: attribute header overflows the packet",
+                       FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: attribute header overflows the packet",
                                   inet_ntop(packet->src_ipaddr.af,
                                             &packet->src_ipaddr.ipaddr,
                                             host_ipaddr, sizeof(host_ipaddr)));
@@ -2463,7 +2502,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
                 *      Attribute number zero is NOT defined.
                 */
                if (attr[0] == 0) {
-                       fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: Invalid attribute 0",
+                       FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: Invalid attribute 0",
                                   inet_ntop(packet->src_ipaddr.af,
                                             &packet->src_ipaddr.ipaddr,
                                             host_ipaddr, sizeof(host_ipaddr)));
@@ -2476,7 +2515,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
                 *      fields.  Anything shorter is an invalid attribute.
                 */
                if (attr[1] < 2) {
-                       fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: attribute %u too short",
+                       FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: attribute %u too short",
                                   inet_ntop(packet->src_ipaddr.af,
                                             &packet->src_ipaddr.ipaddr,
                                             host_ipaddr, sizeof(host_ipaddr)),
@@ -2490,7 +2529,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
                 *      attribute, it's a bad packet.
                 */
                if (count < attr[1]) {
-                       fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: attribute %u data overflows the packet",
+                       FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: attribute %u data overflows the packet",
                                   inet_ntop(packet->src_ipaddr.af,
                                             &packet->src_ipaddr.ipaddr,
                                             host_ipaddr, sizeof(host_ipaddr)),
@@ -2512,11 +2551,18 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
                         */
                case PW_EAP_MESSAGE:
                        require_ma = true;
+                       eap = true;
+                       break;
+
+               case PW_USER_PASSWORD:
+               case PW_CHAP_PASSWORD:
+               case PW_ARAP_PASSWORD:
+                       non_eap = true;
                        break;
 
                case PW_MESSAGE_AUTHENTICATOR:
                        if (attr[1] != 2 + AUTH_VECTOR_LEN) {
-                               fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d",
+                               FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d",
                                           inet_ntop(packet->src_ipaddr.af,
                                                     &packet->src_ipaddr.ipaddr,
                                                     host_ipaddr, sizeof(host_ipaddr)),
@@ -2545,7 +2591,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
         *      If not, we complain, and throw the packet away.
         */
        if (count != 0) {
-               fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet",
+               FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet",
                           inet_ntop(packet->src_ipaddr.af,
                                     &packet->src_ipaddr.ipaddr,
                                     host_ipaddr, sizeof(host_ipaddr)));
@@ -2560,7 +2606,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
         */
        if ((fr_max_attributes > 0) &&
            (num_attributes > fr_max_attributes)) {
-               fr_strerror_printf("WARNING: Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
+               FR_DEBUG_STRERROR_PRINTF("Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
                           inet_ntop(packet->src_ipaddr.af,
                                     &packet->src_ipaddr.ipaddr,
                                     host_ipaddr, sizeof(host_ipaddr)),
@@ -2581,7 +2627,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
         *      Message-Authenticator attributes.
         */
        if (require_ma && !seen_ma) {
-               fr_strerror_printf("WARNING: Insecure packet from host %s:  Packet does not contain required Message-Authenticator attribute",
+               FR_DEBUG_STRERROR_PRINTF("Insecure packet from host %s:  Packet does not contain required Message-Authenticator attribute",
                           inet_ntop(packet->src_ipaddr.af,
                                     &packet->src_ipaddr.ipaddr,
                                     host_ipaddr, sizeof(host_ipaddr)));
@@ -2589,6 +2635,15 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
                goto finish;
        }
 
+       if (eap && non_eap) {
+               FR_DEBUG_STRERROR_PRINTF("Bad packet from host %s:  Packet contains EAP-Message and non-EAP authentication attribute",
+                          inet_ntop(packet->src_ipaddr.af,
+                                    &packet->src_ipaddr.ipaddr,
+                                    host_ipaddr, sizeof(host_ipaddr)));
+               failure = DECODE_FAIL_TOO_MANY_AUTH;
+               goto finish;
+       }
+
        /*
         *      Fill RADIUS header fields
         */
@@ -2606,11 +2661,10 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
 }
 
 
-/**
- * @brief Receive UDP client requests, and fill in
- *     the basics of a RADIUS_PACKET structure.
+/** Receive UDP client requests, and fill in the basics of a RADIUS_PACKET structure
+ *
  */
-RADIUS_PACKET *rad_recv(int fd, int flags)
+RADIUS_PACKET *rad_recv(TALLOC_CTX *ctx, int fd, int flags)
 {
        int sock_flags = 0;
        ssize_t data_len;
@@ -2619,7 +2673,7 @@ RADIUS_PACKET *rad_recv(int fd, int flags)
        /*
         *      Allocate the new request data structure
         */
-       packet = rad_alloc(NULL, 0);
+       packet = rad_alloc(ctx, false);
        if (!packet) {
                fr_strerror_printf("out of memory");
                return NULL;
@@ -2638,7 +2692,7 @@ RADIUS_PACKET *rad_recv(int fd, int flags)
         *      Check for socket errors.
         */
        if (data_len < 0) {
-               fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
+               FR_DEBUG_STRERROR_PRINTF("Error receiving packet: %s", fr_syserror(errno));
                /* packet->data is NULL */
                rad_free(&packet);
                return NULL;
@@ -2651,7 +2705,7 @@ RADIUS_PACKET *rad_recv(int fd, int flags)
         *      packet.
         */
        if (packet->data_len > MAX_PACKET_LEN) {
-               fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes");
+               FR_DEBUG_STRERROR_PRINTF("Discarding packet: Larger than RFC limitation of 4096 bytes");
                /* packet->data is NULL */
                rad_free(&packet);
                return NULL;
@@ -2664,7 +2718,7 @@ RADIUS_PACKET *rad_recv(int fd, int flags)
         *      packet->data == NULL
         */
        if ((packet->data_len == 0) || !packet->data) {
-               fr_strerror_printf("Empty packet: Socket is not ready");
+               FR_DEBUG_STRERROR_PRINTF("Empty packet: Socket is not ready");
                rad_free(&packet);
                return NULL;
        }
@@ -2693,57 +2747,24 @@ RADIUS_PACKET *rad_recv(int fd, int flags)
         */
        packet->vps = NULL;
 
-       if (fr_debug_flag) {
-               char src_ipaddr[128];
-               char dst_ipaddr[128];
-
-               if (is_radius_code(packet->code)) {
-                       DEBUG("Received %s Id %d from %s:%d to %s:%d length %d\n",
-                             fr_packet_codes[packet->code],
-                             packet->id,
-                             inet_ntop(packet->src_ipaddr.af,
-                                       &packet->src_ipaddr.ipaddr,
-                                       src_ipaddr, sizeof(src_ipaddr)),
-                             packet->src_port,
-                             inet_ntop(packet->dst_ipaddr.af,
-                                       &packet->dst_ipaddr.ipaddr,
-                                       dst_ipaddr, sizeof(dst_ipaddr)),
-                             packet->dst_port,
-                             (int) packet->data_len);
-               } else {
-                       DEBUG("Received code %d Id %d from %s:%d to %s:%d length %d\n",
-                             packet->code,
-                             packet->id,
-                             inet_ntop(packet->src_ipaddr.af,
-                                       &packet->src_ipaddr.ipaddr,
-                                       src_ipaddr, sizeof(src_ipaddr)),
-                             packet->src_port,
-                             inet_ntop(packet->dst_ipaddr.af,
-                                       &packet->dst_ipaddr.ipaddr,
-                                       dst_ipaddr, sizeof(dst_ipaddr)),
-                             packet->dst_port,
-                             (int) packet->data_len);
-               }
-       }
-
 #ifndef NDEBUG
-       if ((fr_debug_flag > 3) && fr_log_fp) rad_print_hex(packet);
+       if ((fr_debug_lvl > 3) && fr_log_fp) rad_print_hex(packet);
 #endif
 
        return packet;
 }
 
 
-/**
- * @brief Verify the Request/Response Authenticator
- *     (and Message-Authenticator if present) of a packet.
+/** Verify the Request/Response Authenticator (and Message-Authenticator if present) of a packet
+ *
  */
-int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
-              char const *secret)
+int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original, char const *secret)
 {
-       uint8_t                 *ptr;
-       int                     length;
-       int                     attrlen;
+       uint8_t         *ptr;
+       int             length;
+       int             attrlen;
+       int             rcode;
+       char            buffer[32];
 
        if (!packet || !packet->data) return -1;
 
@@ -2751,8 +2772,8 @@ int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
         *      Before we allocate memory for the attributes, do more
         *      sanity checking.
         */
-       ptr = packet->data + AUTH_HDR_LEN;
-       length = packet->data_len - AUTH_HDR_LEN;
+       ptr = packet->data + RADIUS_HDR_LEN;
+       length = packet->data_len - RADIUS_HDR_LEN;
        while (length > 0) {
                uint8_t msg_auth_vector[AUTH_VECTOR_LEN];
                uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
@@ -2788,31 +2809,31 @@ int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
                                break;
 
                        do_ack:
-                       case PW_CODE_AUTHENTICATION_ACK:
-                       case PW_CODE_AUTHENTICATION_REJECT:
+                       case PW_CODE_ACCESS_ACCEPT:
+                       case PW_CODE_ACCESS_REJECT:
                        case PW_CODE_ACCESS_CHALLENGE:
                        case PW_CODE_DISCONNECT_ACK:
                        case PW_CODE_DISCONNECT_NAK:
                        case PW_CODE_COA_ACK:
                        case PW_CODE_COA_NAK:
                                if (!original) {
-                                       fr_strerror_printf("ERROR: Cannot validate Message-Authenticator in response packet without a request packet");
+                                       fr_strerror_printf("Cannot validate Message-Authenticator in response "
+                                                          "packet without a request packet");
                                        return -1;
                                }
                                memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN);
                                break;
                        }
 
-                       fr_hmac_md5(packet->data, packet->data_len,
-                                   (uint8_t const *) secret, strlen(secret),
-                                   calc_auth_vector);
+                       fr_hmac_md5(calc_auth_vector, packet->data, packet->data_len,
+                                   (uint8_t const *) secret, strlen(secret));
                        if (rad_digest_cmp(calc_auth_vector, msg_auth_vector,
                                   sizeof(calc_auth_vector)) != 0) {
-                               char buffer[32];
-                               fr_strerror_printf("Received packet from %s with invalid Message-Authenticator!  (Shared secret is incorrect.)",
-                                          inet_ntop(packet->src_ipaddr.af,
-                                                    &packet->src_ipaddr.ipaddr,
-                                                    buffer, sizeof(buffer)));
+                               fr_strerror_printf("Received packet from %s with invalid Message-Authenticator!  "
+                                                  "(Shared secret is incorrect.)",
+                                                  inet_ntop(packet->src_ipaddr.af,
+                                                            &packet->src_ipaddr.ipaddr,
+                                                            buffer, sizeof(buffer)));
                                /* Silently drop packet, according to RFC 3579 */
                                return -1;
                        } /* else the message authenticator was good */
@@ -2834,14 +2855,13 @@ int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
         *      so can't validate the authenticators.
         */
        if ((packet->code == 0) || (packet->code >= FR_MAX_PACKET_CODE)) {
-               char buffer[32];
                fr_strerror_printf("Received Unknown packet code %d "
-                          "from client %s port %d: Cannot validate Request/Response Authenticator.",
-                          packet->code,
-                          inet_ntop(packet->src_ipaddr.af,
-                                    &packet->src_ipaddr.ipaddr,
-                                    buffer, sizeof(buffer)),
-                          packet->src_port);
+                                  "from client %s port %d: Cannot validate Request/Response Authenticator.",
+                                  packet->code,
+                                  inet_ntop(packet->src_ipaddr.af,
+                                            &packet->src_ipaddr.ipaddr,
+                                            buffer, sizeof(buffer)),
+                                  packet->src_port);
                return -1;
        }
 
@@ -2849,72 +2869,71 @@ int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
         *      Calculate and/or verify Request or Response Authenticator.
         */
        switch (packet->code) {
-               int rcode;
-               char buffer[32];
-
-               case PW_CODE_AUTHENTICATION_REQUEST:
-               case PW_CODE_STATUS_SERVER:
-                       /*
-                        *      The authentication vector is random
-                        *      nonsense, invented by the client.
-                        */
-                       break;
+       case PW_CODE_ACCESS_REQUEST:
+       case PW_CODE_STATUS_SERVER:
+               /*
+                *      The authentication vector is random
+                *      nonsense, invented by the client.
+                */
+               break;
 
-               case PW_CODE_COA_REQUEST:
-               case PW_CODE_DISCONNECT_REQUEST:
-               case PW_CODE_ACCOUNTING_REQUEST:
-                       if (calc_acctdigest(packet, secret) > 1) {
-                               fr_strerror_printf("Received %s packet "
-                                          "from client %s with invalid Request Authenticator!  (Shared secret is incorrect.)",
+       case PW_CODE_COA_REQUEST:
+       case PW_CODE_DISCONNECT_REQUEST:
+       case PW_CODE_ACCOUNTING_REQUEST:
+               if (calc_acctdigest(packet, secret) > 1) {
+                       fr_strerror_printf("Received %s packet "
+                                          "from client %s with invalid Request Authenticator!  "
+                                          "(Shared secret is incorrect.)",
                                           fr_packet_codes[packet->code],
                                           inet_ntop(packet->src_ipaddr.af,
                                                     &packet->src_ipaddr.ipaddr,
                                                     buffer, sizeof(buffer)));
-                               return -1;
-                       }
-                       break;
+                       return -1;
+               }
+               break;
 
-                       /* Verify the reply digest */
-               case PW_CODE_AUTHENTICATION_ACK:
-               case PW_CODE_AUTHENTICATION_REJECT:
-               case PW_CODE_ACCESS_CHALLENGE:
-               case PW_CODE_ACCOUNTING_RESPONSE:
-               case PW_CODE_DISCONNECT_ACK:
-               case PW_CODE_DISCONNECT_NAK:
-               case PW_CODE_COA_ACK:
-               case PW_CODE_COA_NAK:
-                       rcode = calc_replydigest(packet, original, secret);
-                       if (rcode > 1) {
-                               fr_strerror_printf("Received %s packet "
-                                          "from home server %s port %d with invalid Response Authenticator!  (Shared secret is incorrect.)",
+               /* Verify the reply digest */
+       case PW_CODE_ACCESS_ACCEPT:
+       case PW_CODE_ACCESS_REJECT:
+       case PW_CODE_ACCESS_CHALLENGE:
+       case PW_CODE_ACCOUNTING_RESPONSE:
+       case PW_CODE_DISCONNECT_ACK:
+       case PW_CODE_DISCONNECT_NAK:
+       case PW_CODE_COA_ACK:
+       case PW_CODE_COA_NAK:
+               rcode = calc_replydigest(packet, original, secret);
+               if (rcode > 1) {
+                       fr_strerror_printf("Received %s packet "
+                                          "from home server %s port %d with invalid Response Authenticator!  "
+                                          "(Shared secret is incorrect.)",
                                           fr_packet_codes[packet->code],
                                           inet_ntop(packet->src_ipaddr.af,
                                                     &packet->src_ipaddr.ipaddr,
                                                     buffer, sizeof(buffer)),
                                           packet->src_port);
-                               return -1;
-                       }
-                       break;
+                       return -1;
+               }
+               break;
 
-               default:
-                       fr_strerror_printf("Received Unknown packet code %d "
+       default:
+               fr_strerror_printf("Received Unknown packet code %d "
                                   "from client %s port %d: Cannot validate Request/Response Authenticator",
                                   packet->code,
                                   inet_ntop(packet->src_ipaddr.af,
-                                            &packet->src_ipaddr.ipaddr,
-                                                    buffer, sizeof(buffer)),
+                                            &packet->src_ipaddr.ipaddr,
+                                            buffer, sizeof(buffer)),
                                   packet->src_port);
-                       return -1;
+               return -1;
        }
 
        return 0;
 }
 
 
-/**
- * @brief convert a "concatenated" attribute to one long VP.
+/** Convert a "concatenated" attribute to one long VP
+ *
  */
-static ssize_t data2vp_concat(RADIUS_PACKET *packet,
+static ssize_t data2vp_concat(TALLOC_CTX *ctx,
                              DICT_ATTR const *da, uint8_t const *start,
                              size_t const packetlen, VALUE_PAIR **pvp)
 {
@@ -2943,19 +2962,19 @@ static ssize_t data2vp_concat(RADIUS_PACKET *packet,
                if (ptr[0] != attr) break;
        }
 
-       vp = pairalloc(packet, da);
+       vp = fr_pair_afrom_da(ctx, da);
        if (!vp) return -1;
 
-       vp->length = total;
-       vp->vp_octets = p = talloc_array(vp, uint8_t, vp->length);
+       vp->vp_length = total;
+       vp->vp_octets = p = talloc_array(vp, uint8_t, vp->vp_length);
        if (!p) {
-               pairfree(&vp);
+               fr_pair_list_free(&vp);
                return -1;
        }
 
        total = 0;
        ptr = start;
-       while (total < vp->length) {
+       while (total < vp->vp_length) {
                memcpy(p, ptr + 2, ptr[1] - 2);
                p += ptr[1] - 2;
                total += ptr[1] - 2;
@@ -2967,11 +2986,11 @@ static ssize_t data2vp_concat(RADIUS_PACKET *packet,
 }
 
 
-/**
- * @brief convert TLVs to one or more VPs
+/** Convert TLVs to one or more VPs
+ *
  */
-static ssize_t data2vp_tlvs(RADIUS_PACKET *packet,
-                           RADIUS_PACKET const *original,
+ssize_t rad_data2vp_tlvs(TALLOC_CTX *ctx,
+                           RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                            char const *secret, DICT_ATTR const *da,
                            uint8_t const *start, size_t length,
                            VALUE_PAIR **pvp)
@@ -3007,24 +3026,24 @@ static ssize_t data2vp_tlvs(RADIUS_PACKET *packet,
                        my_vendor = da->vendor;
 
                        if (!dict_attr_child(da, &my_attr, &my_vendor)) {
-                               pairfree(&head);
+                               fr_pair_list_free(&head);
                                return -1;
                        }
 
-                       child = dict_attrunknown(my_attr, my_vendor, true);
+                       child = dict_unknown_afrom_fields(ctx, my_attr, my_vendor);
                        if (!child) {
-                               pairfree(&head);
+                               fr_pair_list_free(&head);
                                return -1;
                        }
                }
 
-               tlv_len = data2vp(packet, original, secret, child,
+               tlv_len = data2vp(ctx, packet, original, secret, child,
                                  data + 2, data[1] - 2, data[1] - 2, tail);
                if (tlv_len < 0) {
-                       pairfree(&head);
+                       fr_pair_list_free(&head);
                        return -1;
                }
-               tail = &((*tail)->next);
+               if (*tail) tail = &((*tail)->next);
                data += data[1];
        }
 
@@ -3032,12 +3051,11 @@ static ssize_t data2vp_tlvs(RADIUS_PACKET *packet,
        return length;
 }
 
-/**
- * @brief Convert a top-level VSA to a VP.
+/** Convert a top-level VSA to a VP.
  *
- *     "length" can be LONGER than just this sub-vsa
+ * "length" can be LONGER than just this sub-vsa.
  */
-static ssize_t data2vp_vsa(RADIUS_PACKET *packet,
+static ssize_t data2vp_vsa(TALLOC_CTX *ctx, RADIUS_PACKET *packet,
                           RADIUS_PACKET const *original,
                           char const *secret, DICT_VENDOR *dv,
                           uint8_t const *data, size_t length,
@@ -3047,6 +3065,8 @@ static ssize_t data2vp_vsa(RADIUS_PACKET *packet,
        ssize_t attrlen, my_len;
        DICT_ATTR const *da;
 
+       VP_TRACE("data2vp_vsa: length %u\n", (unsigned int) length);
+
 #ifndef NDEBUG
        if (length <= (dv->type + dv->length)) {
                fr_strerror_printf("data2vp_vsa: Failure to call rad_tlv_ok");
@@ -3095,21 +3115,14 @@ static ssize_t data2vp_vsa(RADIUS_PACKET *packet,
                return -1;
        }
 
-#ifndef NDEBUG
-       if (attrlen <= (ssize_t) (dv->type + dv->length)) {
-               fr_strerror_printf("data2vp_vsa: Failure to call rad_tlv_ok");
-               return -1;
-       }
-#endif
-
        /*
         *      See if the VSA is known.
         */
        da = dict_attrbyvalue(attribute, dv->vendorpec);
-       if (!da) da = dict_attrunknown(attribute, dv->vendorpec, true);
+       if (!da) da = dict_unknown_afrom_fields(ctx, attribute, dv->vendorpec);
        if (!da) return -1;
 
-       my_len = data2vp(packet, original, secret, da,
+       my_len = data2vp(ctx, packet, original, secret, da,
                         data + dv->type + dv->length,
                         attrlen - (dv->type + dv->length),
                         attrlen - (dv->type + dv->length),
@@ -3120,21 +3133,19 @@ static ssize_t data2vp_vsa(RADIUS_PACKET *packet,
 }
 
 
-/**
- * @brief Convert a fragmented extended attr to a VP
+/** Convert a fragmented extended attr to a VP
  *
- *     Format is:
+ * Format is:
  *
- *     attr
- *     length
- *     extended-attr
- *     flag
- *     data...
+ * attr
+ * length
+ * extended-attr
+ * flag
+ * data...
  *
- *     But for the first fragment, we get passed a pointer to the
- *     "extended-attr".
+ * But for the first fragment, we get passed a pointer to the "extended-attr"
  */
-static ssize_t data2vp_extended(RADIUS_PACKET *packet,
+static ssize_t data2vp_extended(TALLOC_CTX *ctx, RADIUS_PACKET *packet,
                                RADIUS_PACKET const *original,
                                char const *secret, DICT_ATTR const *da,
                                uint8_t const *data,
@@ -3202,7 +3213,7 @@ static ssize_t data2vp_extended(RADIUS_PACKET *packet,
 
        VP_HEXDUMP("long-extended fragments", head, fraglen);
 
-       rcode = data2vp(packet, original, secret, da,
+       rcode = data2vp(ctx, packet, original, secret, da,
                        head, fraglen, fraglen, pvp);
        free(head);
        if (rcode < 0) return rcode;
@@ -3210,13 +3221,12 @@ static ssize_t data2vp_extended(RADIUS_PACKET *packet,
        return end - data;
 }
 
-/**
- * @brief Convert a Vendor-Specific WIMAX to vps
+/** Convert a Vendor-Specific WIMAX to vps
  *
- *     Called ONLY for Vendor-Specific
+ * @note Called ONLY for Vendor-Specific
  */
-static ssize_t data2vp_wimax(RADIUS_PACKET *packet,
-                            RADIUS_PACKET const *original,
+static ssize_t data2vp_wimax(TALLOC_CTX *ctx,
+                            RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                             char const *secret, uint32_t vendor,
                             uint8_t const *data,
                             size_t attrlen, size_t packetlen,
@@ -3237,7 +3247,7 @@ static ssize_t data2vp_wimax(RADIUS_PACKET *packet,
        if (!child) return -1;
 
        if ((data[6] & 0x80) == 0) {
-               rcode = data2vp(packet, original, secret, child,
+               rcode = data2vp(ctx, packet, original, secret, child,
                                data + 7, data[5] - 3, data[5] - 3,
                                pvp);
                if (rcode < 0) return -1;
@@ -3301,7 +3311,7 @@ static ssize_t data2vp_wimax(RADIUS_PACKET *packet,
 
        VP_HEXDUMP("wimax fragments", head, fraglen);
 
-       rcode = data2vp(packet, original, secret, child,
+       rcode = data2vp(ctx, packet, original, secret, child,
                        head, fraglen, fraglen, pvp);
        free(head);
        if (rcode < 0) return rcode;
@@ -3310,10 +3320,10 @@ static ssize_t data2vp_wimax(RADIUS_PACKET *packet,
 }
 
 
-/**
- * @brief Convert a top-level VSA to one or more VPs
+/** Convert a top-level VSA to one or more VPs
+ *
  */
-static ssize_t data2vp_vsas(RADIUS_PACKET *packet,
+static ssize_t data2vp_vsas(TALLOC_CTX *ctx, RADIUS_PACKET *packet,
                            RADIUS_PACKET const *original,
                            char const *secret, uint8_t const *data,
                            size_t attrlen, size_t packetlen,
@@ -3324,21 +3334,47 @@ static ssize_t data2vp_vsas(RADIUS_PACKET *packet,
        uint32_t vendor;
        DICT_VENDOR *dv;
        VALUE_PAIR *head, **tail;
+       DICT_VENDOR my_dv;
 
        if (attrlen > packetlen) return -1;
        if (attrlen < 5) return -1; /* vid, value */
        if (data[0] != 0) return -1; /* we require 24-bit VIDs */
 
+       VP_TRACE("data2vp_vsas\n");
+
        memcpy(&vendor, data, 4);
        vendor = ntohl(vendor);
        dv = dict_vendorbyvalue(vendor);
-       if (!dv) return -1;
+       if (!dv) {
+               /*
+                *      RFC format is 1 octet type, 1 octet length
+                */
+               if (rad_tlv_ok(data + 4, attrlen - 4, 1, 1) < 0) {
+                       VP_TRACE("data2vp_vsas: unknown tlvs not OK: %s\n", fr_strerror());
+                       return -1;
+               }
+
+               /*
+                *      It's a known unknown.
+                */
+               memset(&my_dv, 0, sizeof(my_dv));
+               dv = &my_dv;
+
+               /*
+                *      Fill in the fields.  Note that the name is empty!
+                */
+               dv->vendorpec = vendor;
+               dv->type = 1;
+               dv->length = 1;
+
+               goto create_attrs;
+       }
 
        /*
         *      WiMAX craziness
         */
        if ((vendor == VENDORPEC_WIMAX) && dv->flags) {
-               rcode = data2vp_wimax(packet, original, secret, vendor,
+               rcode = data2vp_wimax(ctx, packet, original, secret, vendor,
                                      data, attrlen, packetlen, pvp);
                return rcode;
        }
@@ -3347,12 +3383,16 @@ static ssize_t data2vp_vsas(RADIUS_PACKET *packet,
         *      VSAs should normally be in TLV format.
         */
        if (rad_tlv_ok(data + 4, attrlen - 4,
-                      dv->type, dv->length) < 0) return -1;
+                      dv->type, dv->length) < 0) {
+               VP_TRACE("data2vp_vsas: tlvs not OK: %s\n", fr_strerror());
+               return -1;
+       }
 
        /*
         *      There may be more than one VSA in the
         *      Vendor-Specific.  If so, loop over them all.
         */
+create_attrs:
        data += 4;
        attrlen -= 4;
        packetlen -= 4;
@@ -3363,14 +3403,19 @@ static ssize_t data2vp_vsas(RADIUS_PACKET *packet,
        while (attrlen > 0) {
                ssize_t vsa_len;
 
-               vsa_len = data2vp_vsa(packet, original, secret, dv,
+               vsa_len = data2vp_vsa(ctx, packet, original, secret, dv,
                                      data, attrlen, tail);
                if (vsa_len < 0) {
-                       pairfree(&head);
+                       fr_pair_list_free(&head);
                        fr_strerror_printf("Internal sanity check %d", __LINE__);
                        return -1;
                }
-               tail = &((*tail)->next);
+
+               /*
+                *      Vendors can send zero-length VSAs.
+                */
+               if (*tail) tail = &((*tail)->next);
+
                data += vsa_len;
                attrlen -= vsa_len;
                packetlen -= vsa_len;
@@ -3381,19 +3426,17 @@ static ssize_t data2vp_vsas(RADIUS_PACKET *packet,
        return total;
 }
 
-
-/**
- * @brief Create any kind of VP from the attribute contents.
+/** Create any kind of VP from the attribute contents
  *
- *     "length" is AT LEAST the length of this attribute, as we
- *     expect the caller to have verified the data with
- *     rad_packet_ok().  "length" may be up to the length of the
- *     packet.
+ * "length" is AT LEAST the length of this attribute, as we
+ * expect the caller to have verified the data with
+ * rad_packet_ok().  "length" may be up to the length of the
+ * packet.
  *
  * @return -1 on error, or "length".
  */
-ssize_t data2vp(RADIUS_PACKET *packet,
-               RADIUS_PACKET const *original,
+ssize_t data2vp(TALLOC_CTX *ctx,
+               RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                char const *secret,
                DICT_ATTR const *da, uint8_t const *start,
                size_t const attrlen, size_t const packetlen,
@@ -3404,7 +3447,6 @@ ssize_t data2vp(RADIUS_PACKET *packet,
        ssize_t rcode;
        uint32_t vendor;
        DICT_ATTR const *child;
-       DICT_VENDOR *dv;
        VALUE_PAIR *vp;
        uint8_t const *data = start;
        char *p;
@@ -3487,6 +3529,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
         *      Decrypt the attribute.
         */
        if (secret && packet && (da->flags.encrypt != FLAG_ENCRYPT_NONE)) {
+               VP_TRACE("data2vp: decrypting type %u\n", da->flags.encrypt);
                /*
                 *      Encrypted attributes can only exist for the
                 *      old-style format.  Extended attributes CANNOT
@@ -3516,7 +3559,29 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                                             packet->vector);
                        }
                        buffer[253] = '\0';
-                       datalen = strlen((char *) buffer);
+
+                       /*
+                        *      MS-CHAP-MPPE-Keys are 24 octets, and
+                        *      encrypted.  Since it's binary, we can't
+                        *      look for trailing zeros.
+                        */
+                       if (da->flags.length) {
+                               if (datalen > da->flags.length) {
+                                       datalen = da->flags.length;
+                               } /* else leave datalen alone */
+                       } else {
+                               /*
+                                *      Take off trailing zeros from the END.
+                                *      This allows passwords to have zeros in
+                                *      the middle of a field.
+                                *
+                                *      However, if the password has a zero at
+                                *      the end, it will get mashed by this
+                                *      code.  There's really no way around
+                                *      that.
+                                */
+                               while ((datalen > 0) && (buffer[datalen - 1] == '\0')) datalen--;
+                       }
                        break;
 
                /*
@@ -3559,6 +3624,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
         *      Double-check the length after decrypting the
         *      attribute.
         */
+       VP_TRACE("data2vp: type %u\n", da->type);
        switch (da->type) {
        case PW_TYPE_STRING:
        case PW_TYPE_OCTETS:
@@ -3569,7 +3635,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                break;
 
        case PW_TYPE_INTEGER:
-       case PW_TYPE_IPADDR:
+       case PW_TYPE_IPV4_ADDR:
        case PW_TYPE_DATE:
        case PW_TYPE_SIGNED:
                if (datalen != 4) goto raw;
@@ -3580,11 +3646,11 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                if (datalen != 8) goto raw;
                break;
 
-       case PW_TYPE_IPV6ADDR:
+       case PW_TYPE_IPV6_ADDR:
                if (datalen != 16) goto raw;
                break;
 
-       case PW_TYPE_IPV6PREFIX:
+       case PW_TYPE_IPV6_PREFIX:
                if ((datalen < 2) || (datalen > 18)) goto raw;
                if (data[1] > 128) goto raw;
                break;
@@ -3601,13 +3667,13 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                if (datalen != 6) goto raw;
                break;
 
-       case PW_TYPE_COMBO_IP:
+       case PW_TYPE_COMBO_IP_ADDR:
                if (datalen == 4) {
                        child = dict_attrbytype(da->attr, da->vendor,
-                                               PW_TYPE_IPADDR);
+                                               PW_TYPE_IPV4_ADDR);
                } else if (datalen == 16) {
                        child = dict_attrbytype(da->attr, da->vendor,
-                                            PW_TYPE_IPV6ADDR);
+                                            PW_TYPE_IPV6_ADDR);
                } else {
                        goto raw;
                }
@@ -3615,7 +3681,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                da = child;     /* re-write it */
                break;
 
-       case PW_TYPE_IPV4PREFIX:
+       case PW_TYPE_IPV4_PREFIX:
                if (datalen != 6) goto raw;
                if ((data[1] & 0x3f) > 32) goto raw;
                break;
@@ -3637,7 +3703,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                 *      the current attribute, and we ignore any extra
                 *      data after it.
                 */
-               rcode = data2vp(packet, original, secret, child,
+               rcode = data2vp(ctx, packet, original, secret, child,
                                data + 1, attrlen - 1, attrlen - 1, pvp);
                if (rcode < 0) goto raw;
                return 1 + rcode;
@@ -3650,7 +3716,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                        if ((data[0] != PW_VENDOR_SPECIFIC) ||
                            (datalen < (3 + 4 + 1))) {
                                /* da->attr < 255, da->vendor == 0 */
-                               child = dict_attrunknown(data[0], da->attr * FR_MAX_VENDOR, true);
+                               child = dict_unknown_afrom_fields(ctx, data[0], da->attr * FR_MAX_VENDOR);
                        } else {
                                /*
                                 *      Try to find the VSA.
@@ -3660,7 +3726,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
 
                                if (vendor == 0) goto raw;
 
-                               child = dict_attrunknown(data[7], vendor | (da->attr * FR_MAX_VENDOR), true);
+                               child = dict_unknown_afrom_fields(ctx, data[7], vendor | (da->attr * FR_MAX_VENDOR));
                        }
 
                        if (!child) {
@@ -3675,7 +3741,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                 *
                 */
                if ((data[1] & 0x80) == 0) {
-                       rcode = data2vp(packet, original, secret, child,
+                       rcode = data2vp(ctx, packet, original, secret, child,
                                        data + 2, attrlen - 2, attrlen - 2,
                                        pvp);
                        if (rcode < 0) goto raw;
@@ -3685,7 +3751,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                /*
                 *      This requires a whole lot more work.
                 */
-               return data2vp_extended(packet, original, secret, child,
+               return data2vp_extended(ctx, packet, original, secret, child,
                                        start, attrlen, packetlen, pvp);
 
        case PW_TYPE_EVS:
@@ -3695,18 +3761,21 @@ ssize_t data2vp(RADIUS_PACKET *packet,
 
                memcpy(&vendor, data, 4);
                vendor = ntohl(vendor);
-               dv = dict_vendorbyvalue(vendor);
-               if (!dv) {
-                       child = dict_attrunknown(data[4], da->vendor | vendor, true);
-               } else {
-                       child = dict_attrbyparent(da, data[4], vendor);
-                       if (!child) {
-                               child = dict_attrunknown(data[4], da->vendor | vendor, true);
-                       }
+               vendor |= da->vendor;
+
+               child = dict_attrbyvalue(data[4], vendor);
+               if (!child) {
+                       /*
+                        *      Create a "raw" attribute from the
+                        *      contents of the EVS VSA.
+                        */
+                       da = dict_unknown_afrom_fields(ctx, data[4], vendor);
+                       data += 5;
+                       datalen -= 5;
+                       break;
                }
-               if (!child) goto raw;
 
-               rcode = data2vp(packet, original, secret, child,
+               rcode = data2vp(ctx, packet, original, secret, child,
                                data + 5, attrlen - 5, attrlen - 5, pvp);
                if (rcode < 0) goto raw;
                return 5 + rcode;
@@ -3717,8 +3786,8 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                 *      attribute, OR they've already been grouped
                 *      into a contiguous memory buffer.
                 */
-               rcode = data2vp_tlvs(packet, original, secret, da,
-                                    data, attrlen, pvp);
+               rcode = rad_data2vp_tlvs(ctx, packet, original, secret, da,
+                                        data, attrlen, pvp);
                if (rcode < 0) goto raw;
                return rcode;
 
@@ -3727,7 +3796,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                 *      VSAs can be WiMAX, in which case they don't
                 *      fit into one attribute.
                 */
-               rcode = data2vp_vsas(packet, original, secret,
+               rcode = data2vp_vsas(ctx, packet, original, secret,
                                     data, attrlen, packetlen, pvp);
                if (rcode < 0) goto raw;
                return rcode;
@@ -3739,7 +3808,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                 *      therefore of type "octets", and will be
                 *      handled below.
                 */
-               da = dict_attrunknown(da->attr, da->vendor, true);
+               da = dict_unknown_afrom_fields(ctx, da->attr, da->vendor);
                if (!da) {
                        fr_strerror_printf("Internal sanity check %d", __LINE__);
                        return -1;
@@ -3762,29 +3831,29 @@ ssize_t data2vp(RADIUS_PACKET *packet,
         *      information, decode the actual data.
         */
  alloc_cui:
-       vp = pairalloc(packet, da);
+       vp = fr_pair_afrom_da(ctx, da);
        if (!vp) return -1;
 
-       vp->length = datalen;
+       vp->vp_length = datalen;
        vp->tag = tag;
 
        switch (da->type) {
        case PW_TYPE_STRING:
-               p = talloc_array(vp, char, vp->length + 1);
-               memcpy(p, data, vp->length);
-               p[vp->length] = '\0';
+               p = talloc_array(vp, char, vp->vp_length + 1);
+               memcpy(p, data, vp->vp_length);
+               p[vp->vp_length] = '\0';
                vp->vp_strvalue = p;
                break;
 
        case PW_TYPE_OCTETS:
-               pairmemcpy(vp, data, vp->length);
+               fr_pair_value_memcpy(vp, data, vp->vp_length);
                break;
 
        case PW_TYPE_ABINARY:
-               if (vp->length > sizeof(vp->vp_filter)) {
-                       vp->length = sizeof(vp->vp_filter);
+               if (vp->vp_length > sizeof(vp->vp_filter)) {
+                       vp->vp_length = sizeof(vp->vp_filter);
                }
-               memcpy(vp->vp_filter, data, vp->length);
+               memcpy(vp->vp_filter, data, vp->vp_length);
                break;
 
        case PW_TYPE_BYTE:
@@ -3811,36 +3880,36 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                break;
 
        case PW_TYPE_ETHERNET:
-               memcpy(&vp->vp_ether, data, 6);
+               memcpy(vp->vp_ether, data, 6);
                break;
 
-       case PW_TYPE_IPADDR:
+       case PW_TYPE_IPV4_ADDR:
                memcpy(&vp->vp_ipaddr, data, 4);
                break;
 
        case PW_TYPE_IFID:
-               memcpy(&vp->vp_ifid, data, 8);
+               memcpy(vp->vp_ifid, data, 8);
                break;
 
-       case PW_TYPE_IPV6ADDR:
+       case PW_TYPE_IPV6_ADDR:
                memcpy(&vp->vp_ipv6addr, data, 16);
                break;
 
-       case PW_TYPE_IPV6PREFIX:
+       case PW_TYPE_IPV6_PREFIX:
                /*
                 *      FIXME: double-check that
-                *      (vp->vp_octets[1] >> 3) matches vp->length + 2
+                *      (vp->vp_octets[1] >> 3) matches vp->vp_length + 2
                 */
-               memcpy(&vp->vp_ipv6prefix, data, vp->length);
-               if (vp->length < 18) {
-                       memset(((uint8_t *)vp->vp_ipv6prefix) + vp->length, 0,
-                              18 - vp->length);
+               memcpy(vp->vp_ipv6prefix, data, vp->vp_length);
+               if (vp->vp_length < 18) {
+                       memset(((uint8_t *)vp->vp_ipv6prefix) + vp->vp_length, 0,
+                              18 - vp->vp_length);
                }
                break;
 
-       case PW_TYPE_IPV4PREFIX:
+       case PW_TYPE_IPV4_PREFIX:
                /* FIXME: do the same double-check as for IPv6Prefix */
-               memcpy(&vp->vp_ipv4prefix, data, vp->length);
+               memcpy(vp->vp_ipv4prefix, data, vp->vp_length);
 
                /*
                 *      /32 means "keep all bits".  Otherwise, mask
@@ -3866,7 +3935,7 @@ ssize_t data2vp(RADIUS_PACKET *packet,
                break;
 
        default:
-               pairfree(&vp);
+               fr_pair_list_free(&vp);
                fr_strerror_printf("Internal sanity check %d", __LINE__);
                return -1;
        }
@@ -3877,11 +3946,11 @@ ssize_t data2vp(RADIUS_PACKET *packet,
 }
 
 
-/**
- * @brief Create a "normal" VALUE_PAIR from the given data.
+/** Create a "normal" VALUE_PAIR from the given data
+ *
  */
-ssize_t rad_attr2vp(RADIUS_PACKET *packet,
-                   RADIUS_PACKET const *original,
+ssize_t rad_attr2vp(TALLOC_CTX *ctx,
+                   RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                    char const *secret,
                    uint8_t const *data, size_t length,
                    VALUE_PAIR **pvp)
@@ -3896,14 +3965,18 @@ ssize_t rad_attr2vp(RADIUS_PACKET *packet,
        }
 
        da = dict_attrbyvalue(data[0], 0);
-       if (!da) da = dict_attrunknown(data[0], 0, true);
+       if (!da) {
+               VP_TRACE("attr2vp: unknown attribute %u\n", data[0]);
+               da = dict_unknown_afrom_fields(ctx, data[0], 0);
+       }
        if (!da) return -1;
 
        /*
         *      Pass the entire thing to the decoding function
         */
        if (da->flags.concat) {
-               return data2vp_concat(packet, da, data, length, pvp);
+               VP_TRACE("attr2vp: concat attribute\n");
+               return data2vp_concat(ctx, da, data, length, pvp);
        }
 
        /*
@@ -3912,35 +3985,14 @@ ssize_t rad_attr2vp(RADIUS_PACKET *packet,
         *      attributes may have the "continuation" bit set, and
         *      will thus be more than one attribute in length.
         */
-       rcode = data2vp(packet, original, secret, da,
+       rcode = data2vp(ctx, packet, original, secret, da,
                        data + 2, data[1] - 2, length - 2, pvp);
        if (rcode < 0) return rcode;
 
        return 2 + rcode;
 }
 
-
-/**
- * @brief Converts data in network byte order to a VP
- * @return -1 on error, or the length of the data read
- */
-ssize_t  rad_data2vp(unsigned int attribute, unsigned int vendor,
-                    uint8_t const *data, size_t length,
-                    VALUE_PAIR **pvp)
-{
-       DICT_ATTR const *da;
-
-       if (!data || (length == 0) || !pvp) return -1;
-
-       da = dict_attrbyvalue(attribute, vendor);
-       if (!da) da = dict_attrunknown(attribute, vendor, true);
-       if (!da) return -1;
-
-       return data2vp(NULL, NULL, NULL, da,
-                      data, length, length, pvp);
-}
-
-fr_thread_local_setup(uint8_t *, rad_vp2data_buff);
+fr_thread_local_setup(uint8_t *, rad_vp2data_buff)
 
 /** Converts vp_data to network byte order
  *
@@ -3982,10 +4034,9 @@ ssize_t rad_vp2data(uint8_t const **out, VALUE_PAIR const *vp)
 
        VERIFY_VP(vp);
 
-       switch(vp->da->type) {
+       switch (vp->da->type) {
        case PW_TYPE_STRING:
        case PW_TYPE_OCTETS:
-       case PW_TYPE_TLV:
                memcpy(out, &vp->data.ptr, sizeof(*out));
                break;
 
@@ -3993,13 +4044,14 @@ ssize_t rad_vp2data(uint8_t const **out, VALUE_PAIR const *vp)
         *      All of these values are at the same location.
         */
        case PW_TYPE_IFID:
-       case PW_TYPE_IPADDR:
-       case PW_TYPE_IPV6ADDR:
-       case PW_TYPE_IPV6PREFIX:
-       case PW_TYPE_IPV4PREFIX:
+       case PW_TYPE_IPV4_ADDR:
+       case PW_TYPE_IPV6_ADDR:
+       case PW_TYPE_IPV6_PREFIX:
+       case PW_TYPE_IPV4_PREFIX:
        case PW_TYPE_ABINARY:
        case PW_TYPE_ETHERNET:
-       case PW_TYPE_COMBO_IP:
+       case PW_TYPE_COMBO_IP_ADDR:
+       case PW_TYPE_COMBO_IP_PREFIX:
        {
                void const *p = &vp->data;
                memcpy(out, &p, sizeof(*out));
@@ -4007,18 +4059,18 @@ ssize_t rad_vp2data(uint8_t const **out, VALUE_PAIR const *vp)
        }
 
        case PW_TYPE_BOOLEAN:
-               buffer[0] = vp->vp_integer & 0x01;
+               buffer[0] = vp->vp_byte & 0x01;
                *out = buffer;
                break;
 
        case PW_TYPE_BYTE:
-               buffer[0] = vp->vp_integer & 0xff;
+               buffer[0] = vp->vp_byte & 0xff;
                *out = buffer;
                break;
 
        case PW_TYPE_SHORT:
-               buffer[0] = (vp->vp_integer >> 8) & 0xff;
-               buffer[1] = vp->vp_integer & 0xff;
+               buffer[0] = (vp->vp_short >> 8) & 0xff;
+               buffer[1] = vp->vp_short & 0xff;
                *out = buffer;
                break;
 
@@ -4053,6 +4105,7 @@ ssize_t rad_vp2data(uint8_t const **out, VALUE_PAIR const *vp)
        case PW_TYPE_LONG_EXTENDED:
        case PW_TYPE_EVS:
        case PW_TYPE_VSA:
+       case PW_TYPE_TLV:
        case PW_TYPE_TIMEVAL:
        case PW_TYPE_MAX:
                fr_strerror_printf("Cannot get data for VALUE_PAIR type %i", vp->da->type);
@@ -4061,11 +4114,11 @@ ssize_t rad_vp2data(uint8_t const **out, VALUE_PAIR const *vp)
        /* Don't add default */
        }
 
-       return vp->length;
+       return vp->vp_length;
 }
 
-/**
- * @brief Calculate/check digest, and decode radius attributes.
+/** Calculate/check digest, and decode radius attributes
+ *
  * @return -1 on decoding error, 0 on success
  */
 int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
@@ -4082,7 +4135,7 @@ int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
         */
        hdr = (radius_packet_t *)packet->data;
        ptr = hdr->data;
-       packet_length = packet->data_len - AUTH_HDR_LEN;
+       packet_length = packet->data_len - RADIUS_HDR_LEN;
 
        head = NULL;
        tail = &head;
@@ -4097,17 +4150,16 @@ int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
                /*
                 *      This may return many VPs
                 */
-               my_len = rad_attr2vp(packet, original, secret,
+               my_len = rad_attr2vp(packet, packet, original, secret,
                                     ptr, packet_length, &vp);
                if (my_len < 0) {
-                       pairfree(&head);
+                       fr_pair_list_free(&head);
                        return -1;
                }
 
                *tail = vp;
                while (vp) {
                        num_attributes++;
-                       debug_pair(vp);
                        tail = &(vp->next);
                        vp = vp->next;
                }
@@ -4122,8 +4174,8 @@ int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
                    (num_attributes > fr_max_attributes)) {
                        char host_ipaddr[128];
 
-                       pairfree(&head);
-                       fr_strerror_printf("WARNING: Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
+                       fr_pair_list_free(&head);
+                       fr_strerror_printf("Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
                                   inet_ntop(packet->src_ipaddr.af,
                                             &packet->src_ipaddr.ipaddr,
                                             host_ipaddr, sizeof(host_ipaddr)),
@@ -4139,7 +4191,7 @@ int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
         *      Merge information from the outside world into our
         *      random pool.
         */
-       fr_rand_seed(packet->data, AUTH_HDR_LEN);
+       fr_rand_seed(packet->data, RADIUS_HDR_LEN);
 
        /*
         *      There may be VP's already in the packet.  Don't
@@ -4155,16 +4207,15 @@ int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
 }
 
 
-/**
- * @brief Encode password.
+/** Encode password
  *
- *     We assume that the passwd buffer passed is big enough.
- *     RFC2138 says the password is max 128 chars, so the size
- *     of the passwd buffer must be at least 129 characters.
- *     Preferably it's just MAX_STRING_LEN.
+ * We assume that the passwd buffer passed is big enough.
+ * RFC2138 says the password is max 128 chars, so the size
+ * of the passwd buffer must be at least 129 characters.
+ * Preferably it's just MAX_STRING_LEN.
  *
- *     int *pwlen is updated to the new length of the encrypted
- *     password - a multiple of 16 bytes.
+ * int *pwlen is updated to the new length of the encrypted
+ * password - a multiple of 16 bytes.
  */
 int rad_pwencode(char *passwd, size_t *pwlen, char const *secret,
                 uint8_t const *vector)
@@ -4200,8 +4251,8 @@ int rad_pwencode(char *passwd, size_t *pwlen, char const *secret,
         */
        secretlen = strlen(secret);
 
-       fr_MD5Init(&context);
-       fr_MD5Update(&context, (uint8_t const *) secret, secretlen);
+       fr_md5_init(&context);
+       fr_md5_update(&context, (uint8_t const *) secret, secretlen);
        old = context;          /* save intermediate work */
 
        /*
@@ -4210,14 +4261,14 @@ int rad_pwencode(char *passwd, size_t *pwlen, char const *secret,
         */
        for (n = 0; n < len; n += AUTH_PASS_LEN) {
                if (n == 0) {
-                       fr_MD5Update(&context, vector, AUTH_PASS_LEN);
-                       fr_MD5Final(digest, &context);
+                       fr_md5_update(&context, vector, AUTH_PASS_LEN);
+                       fr_md5_final(digest, &context);
                } else {
                        context = old;
-                       fr_MD5Update(&context,
+                       fr_md5_update(&context,
                                     (uint8_t *) passwd + n - AUTH_PASS_LEN,
                                     AUTH_PASS_LEN);
-                       fr_MD5Final(digest, &context);
+                       fr_md5_final(digest, &context);
                }
 
                for (i = 0; i < AUTH_PASS_LEN; i++) {
@@ -4228,8 +4279,8 @@ int rad_pwencode(char *passwd, size_t *pwlen, char const *secret,
        return 0;
 }
 
-/**
- * @brief Decode password.
+/** Decode password
+ *
  */
 int rad_pwdecode(char *passwd, size_t pwlen, char const *secret,
                 uint8_t const *vector)
@@ -4256,8 +4307,8 @@ int rad_pwdecode(char *passwd, size_t pwlen, char const *secret,
         */
        secretlen = strlen(secret);
 
-       fr_MD5Init(&context);
-       fr_MD5Update(&context, (uint8_t const *) secret, secretlen);
+       fr_md5_init(&context);
+       fr_md5_update(&context, (uint8_t const *) secret, secretlen);
        old = context;          /* save intermediate work */
 
        /*
@@ -4265,20 +4316,20 @@ int rad_pwdecode(char *passwd, size_t pwlen, char const *secret,
         */
        for (n = 0; n < pwlen; n += AUTH_PASS_LEN) {
                if (n == 0) {
-                       fr_MD5Update(&context, vector, AUTH_VECTOR_LEN);
-                       fr_MD5Final(digest, &context);
+                       fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
+                       fr_md5_final(digest, &context);
 
                        context = old;
                        if (pwlen > AUTH_PASS_LEN) {
-                               fr_MD5Update(&context, (uint8_t *) passwd,
+                               fr_md5_update(&context, (uint8_t *) passwd,
                                             AUTH_PASS_LEN);
                        }
                } else {
-                       fr_MD5Final(digest, &context);
+                       fr_md5_final(digest, &context);
 
                        context = old;
                        if (pwlen > (n + AUTH_PASS_LEN)) {
-                               fr_MD5Update(&context, (uint8_t *) passwd + n,
+                               fr_md5_update(&context, (uint8_t *) passwd + n,
                                             AUTH_PASS_LEN);
                        }
                }
@@ -4294,17 +4345,15 @@ int rad_pwdecode(char *passwd, size_t pwlen, char const *secret,
 }
 
 
-/**
- * @brief Encode Tunnel-Password attributes when sending them out on the wire.
+/** Encode Tunnel-Password attributes when sending them out on the wire
  *
- *     int *pwlen is updated to the new length of the encrypted
- *     password - a multiple of 16 bytes.
+ * int *pwlen is updated to the new length of the encrypted
+ * password - a multiple of 16 bytes.
  *
- *      This is per RFC-2868 which adds a two char SALT to the initial intermediate
- *      value MD5 hash.
+ * This is per RFC-2868 which adds a two char SALT to the initial intermediate
+ * value MD5 hash.
  */
-int rad_tunnel_pwencode(char *passwd, size_t *pwlen, char const *secret,
-                       uint8_t const *vector)
+ssize_t rad_tunnel_pwencode(char *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
 {
        uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 3];
        unsigned char   digest[AUTH_VECTOR_LEN];
@@ -4317,14 +4366,15 @@ int rad_tunnel_pwencode(char *passwd, size_t *pwlen, char const *secret,
        if (len > 127) len = 127;
 
        /*
-        * Shift the password 3 positions right to place a salt and original
-        * length, tag will be added automatically on packet send
+        *      Shift the password 3 positions right to place a salt and original
+        *      length, tag will be added automatically on packet send.
         */
-       for (n=len ; n>=0 ; n--) passwd[n+3] = passwd[n];
+       for (n = len ; n >= 0 ; n--) passwd[n + 3] = passwd[n];
        salt = passwd;
        passwd += 2;
+
        /*
-        * save original password length as first password character;
+        *      save original password length as first password character;
         */
        *passwd = len;
        len += 1;
@@ -4379,27 +4429,25 @@ int rad_tunnel_pwencode(char *passwd, size_t *pwlen, char const *secret,
        return 0;
 }
 
-/**
- * @brief Decode Tunnel-Password encrypted attributes.
+/** Decode Tunnel-Password encrypted attributes
  *
- *      Defined in RFC-2868, this uses a two char SALT along with the
- *      initial intermediate value, to differentiate it from the
- *      above.
+ * Defined in RFC-2868, this uses a two char SALT along with the
+ * initial intermediate value, to differentiate it from the
+ * above.
  */
-int rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, char const *secret,
-                       uint8_t const *vector)
+ssize_t rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
 {
        FR_MD5_CTX  context, old;
        uint8_t         digest[AUTH_VECTOR_LEN];
        int             secretlen;
-       unsigned        i, n, len, reallen;
+       size_t          i, n, encrypted_len, reallen;
 
-       len = *pwlen;
+       encrypted_len = *pwlen;
 
        /*
         *      We need at least a salt.
         */
-       if (len < 2) {
+       if (encrypted_len < 2) {
                fr_strerror_printf("tunnel password is too short");
                return -1;
        }
@@ -4414,21 +4462,21 @@ int rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, char const *secret,
         *      more data.  So the 'data_len' field may be wrong,
         *      but that's ok...
         */
-       if (len <= 3) {
+       if (encrypted_len <= 3) {
                passwd[0] = 0;
                *pwlen = 0;
                return 0;
        }
 
-       len -= 2;               /* discount the salt */
+       encrypted_len -= 2;             /* discount the salt */
 
        /*
         *      Use the secret to setup the decryption digest
         */
        secretlen = strlen(secret);
 
-       fr_MD5Init(&context);
-       fr_MD5Update(&context, (uint8_t const *) secret, secretlen);
+       fr_md5_init(&context);
+       fr_md5_update(&context, (uint8_t const *) secret, secretlen);
        old = context;          /* save intermediate work */
 
        /*
@@ -4436,15 +4484,25 @@ int rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, char const *secret,
         *
         *       b(1) = MD5(secret + vector + salt)
         */
-       fr_MD5Update(&context, vector, AUTH_VECTOR_LEN);
-       fr_MD5Update(&context, passwd, 2);
+       fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
+       fr_md5_update(&context, passwd, 2);
 
        reallen = 0;
-       for (n = 0; n < len; n += AUTH_PASS_LEN) {
-               int base = 0;
+       for (n = 0; n < encrypted_len; n += AUTH_PASS_LEN) {
+               size_t base;
+               size_t block_len = AUTH_PASS_LEN;
+
+               /*
+                *      Ensure we don't overflow the input on MD5
+                */
+               if ((n + 2 + AUTH_PASS_LEN) > *pwlen) {
+                       block_len = *pwlen - n - 2;
+               }
 
                if (n == 0) {
-                       fr_MD5Final(digest, &context);
+                       base = 1;
+
+                       fr_md5_final(digest, &context);
 
                        context = old;
 
@@ -4454,43 +4512,38 @@ int rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, char const *secret,
                         *      'data_len' field.  Ensure it's sane.
                         */
                        reallen = passwd[2] ^ digest[0];
-                       if (reallen >len) {
+                       if (reallen > encrypted_len) {
                                fr_strerror_printf("tunnel password is too long for the attribute");
                                return -1;
                        }
 
-                       fr_MD5Update(&context, passwd + 2, AUTH_PASS_LEN);
+                       fr_md5_update(&context, passwd + 2, block_len);
 
-                       base = 1;
                } else {
-                       fr_MD5Final(digest, &context);
+                       base = 0;
+
+                       fr_md5_final(digest, &context);
 
                        context = old;
-                       fr_MD5Update(&context, passwd + n + 2, AUTH_PASS_LEN);
+                       fr_md5_update(&context, passwd + n + 2, block_len);
                }
 
-               for (i = base; i < AUTH_PASS_LEN; i++) {
+               for (i = base; i < block_len; i++) {
                        passwd[n + i - 1] = passwd[n + i + 2] ^ digest[i];
                }
        }
 
-       /*
-        *      See make_tunnel_password, above.
-        */
-       if (reallen > 239) reallen = 239;
-
        *pwlen = reallen;
        passwd[reallen] = 0;
 
        return reallen;
 }
 
-/**
- * @brief Encode a CHAP password
+/** Encode a CHAP password
  *
- *     @bug FIXME: might not work with Ascend because
- *     we use vp->length, and Ascend gear likes
- *     to send an extra '\0' in the string!
+ * @bug FIXME: might not work with Ascend because
+ * we use vp->vp_length, and Ascend gear likes
+ * to send an extra '\0' in the string!
  */
 int rad_chap_encode(RADIUS_PACKET *packet, uint8_t *output, int id,
                    VALUE_PAIR *password)
@@ -4519,18 +4572,18 @@ int rad_chap_encode(RADIUS_PACKET *packet, uint8_t *output, int id,
        *ptr++ = id;
 
        i++;
-       memcpy(ptr, password->vp_strvalue, password->length);
-       ptr += password->length;
-       i += password->length;
+       memcpy(ptr, password->vp_strvalue, password->vp_length);
+       ptr += password->vp_length;
+       i += password->vp_length;
 
        /*
         *      Use Chap-Challenge pair if present,
         *      Request Authenticator otherwise.
         */
-       challenge = pairfind(packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY);
+       challenge = fr_pair_find_by_num(packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY);
        if (challenge) {
-               memcpy(ptr, challenge->vp_strvalue, challenge->length);
-               i += challenge->length;
+               memcpy(ptr, challenge->vp_strvalue, challenge->vp_length);
+               i += challenge->vp_length;
        } else {
                memcpy(ptr, packet->vector, AUTH_VECTOR_LEN);
                i += AUTH_VECTOR_LEN;
@@ -4543,10 +4596,9 @@ int rad_chap_encode(RADIUS_PACKET *packet, uint8_t *output, int id,
 }
 
 
-/**
- * @brief Seed the random number generator.
+/** Seed the random number generator
  *
- *     May be called any number of times.
+ * May be called any number of times.
  */
 void fr_rand_seed(void const *data, size_t size)
 {
@@ -4597,8 +4649,8 @@ void fr_rand_seed(void const *data, size_t size)
 }
 
 
-/**
- * @brief Return a 32-bit random number.
+/** Return a 32-bit random number
+ *
  */
 uint32_t fr_rand(void)
 {
@@ -4625,10 +4677,10 @@ uint32_t fr_rand(void)
  *
  * @param ctx the context in which the packet is allocated. May be NULL if
  *     the packet is not associated with a REQUEST.
- * @param newvector if true a new request authenticator will be generated.
+ * @param new_vector if true a new request authenticator will be generated.
  * @return a new RADIUS_PACKET or NULL on error.
  */
-RADIUS_PACKET *rad_alloc(TALLOC_CTX *ctx, int newvector)
+RADIUS_PACKET *rad_alloc(TALLOC_CTX *ctx, bool new_vector)
 {
        RADIUS_PACKET   *rp;
 
@@ -4640,7 +4692,7 @@ RADIUS_PACKET *rad_alloc(TALLOC_CTX *ctx, int newvector)
        rp->id = -1;
        rp->offset = -1;
 
-       if (newvector) {
+       if (new_vector) {
                int i;
                uint32_t hash, base;
 
@@ -4672,7 +4724,7 @@ RADIUS_PACKET *rad_alloc_reply(TALLOC_CTX *ctx, RADIUS_PACKET *packet)
 
        if (!packet) return NULL;
 
-       reply = rad_alloc(ctx, 0);
+       reply = rad_alloc(ctx, false);
        if (!reply) return NULL;
 
        /*
@@ -4698,8 +4750,8 @@ RADIUS_PACKET *rad_alloc_reply(TALLOC_CTX *ctx, RADIUS_PACKET *packet)
 }
 
 
-/**
- * @brief Free a RADIUS_PACKET
+/** Free a RADIUS_PACKET
+ *
  */
 void rad_free(RADIUS_PACKET **radius_packet_ptr)
 {
@@ -4710,7 +4762,7 @@ void rad_free(RADIUS_PACKET **radius_packet_ptr)
 
        VERIFY_PACKET(radius_packet);
 
-       pairfree(&radius_packet->vps);
+       fr_pair_list_free(&radius_packet->vps);
 
        talloc_free(radius_packet);
        *radius_packet_ptr = NULL;
@@ -4727,7 +4779,7 @@ RADIUS_PACKET *rad_copy_packet(TALLOC_CTX *ctx, RADIUS_PACKET const *in)
 {
        RADIUS_PACKET *out;
 
-       out = rad_alloc(ctx, 0);
+       out = rad_alloc(ctx, false);
        if (!out) return NULL;
 
        /*
@@ -4743,7 +4795,7 @@ RADIUS_PACKET *rad_copy_packet(TALLOC_CTX *ctx, RADIUS_PACKET const *in)
        out->data = NULL;
        out->data_len = 0;
 
-       out->vps = paircopy(out, in->vps);
+       out->vps = fr_pair_list_copy(out, in->vps);
        out->offset = 0;
 
        return out;