Fix spurious soft asserts Fixes #706
[freeradius.git] / src / lib / valuepair.c
index 3810a24..93ba8f8 100644 (file)
@@ -47,7 +47,7 @@ RCSID("$Id$")
 #  endif
 #endif
 
-#define attribute_eq(_x, _y) ((_x && _y) && (_x->da == _y->da) && (_x->tag == _y->tag))
+
 
 /** Free a VALUE_PAIR
  *
@@ -232,6 +232,9 @@ VALUE_PAIR *pairfind(VALUE_PAIR *vp, unsigned int attr, unsigned int vendor, int
        vp_cursor_t     cursor;
        VALUE_PAIR      *i;
 
+       /* List head may be NULL if it contains no VPs */
+       if (!vp) return NULL;
+
        VERIFY_LIST(vp);
 
        for (i = fr_cursor_init(&cursor, &vp);
@@ -499,7 +502,7 @@ void pairvalidate_debug(TALLOC_CTX *ctx, VALUE_PAIR const *failed[2])
                return;
        }
 
-       if (TAG_EQ(filter->tag, list->tag)) {
+       if (!TAG_EQ(filter->tag, list->tag)) {
                fr_strerror_printf("Attribute \"%s\" tag \"%i\" didn't match filter tag \"%i\"",
                                   list->da->name, list->tag, filter->tag);
                return;
@@ -547,16 +550,18 @@ bool pairvalidate(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *l
 
        check = fr_cursor_init(&filter_cursor, &filter);
        match = fr_cursor_init(&list_cursor, &list);
-
-       while (true) {
-               if (!match && !check) goto mismatch;
+       while (match || check) {
+               /*
+                *      Lists are of different lengths
+                */
+               if ((!match && check) || (check && !match)) goto mismatch;
 
                /*
                 *      The lists are sorted, so if the first
                 *      attributes aren't of the same type, then we're
                 *      done.
                 */
-               if (!attribute_eq(check, match)) goto mismatch;
+               if (!ATTRIBUTE_EQ(check, match)) goto mismatch;
 
                /*
                 *      They're of the same type, but don't have the
@@ -565,16 +570,10 @@ bool pairvalidate(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *l
                 *      Note that the RFCs say that for attributes of
                 *      the same type, order is important.
                 */
-               if (!paircmp(check, match)) goto mismatch;
+               if (paircmp(check, match) != 1) goto mismatch;
 
                check = fr_cursor_next(&filter_cursor);
                match = fr_cursor_next(&list_cursor);
-
-               /*
-                *      One list ended earlier than the others, they
-                *      didn't match.
-                */
-               if (!match || !check) break;
        }
 
        return true;
@@ -623,7 +622,7 @@ bool pairvalidate_relaxed(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE
                /*
                 *      Were processing check attributes of a new type.
                 */
-               if (!attribute_eq(last_check, check)) {
+               if (!ATTRIBUTE_EQ(last_check, check)) {
                        /*
                         *      Record the start of the matching attributes in the pair list
                         *      For every other operator we require the match to be present
@@ -642,7 +641,7 @@ bool pairvalidate_relaxed(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE
                 *      Now iterate over all attributes of the same type.
                 */
                for (match = fr_cursor_first(&list_cursor);
-                    attribute_eq(match, check);
+                    ATTRIBUTE_EQ(match, check);
                     match = fr_cursor_next(&list_cursor)) {
                        /*
                         *      This attribute passed the filter
@@ -716,118 +715,6 @@ VALUE_PAIR *paircopyvp(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
        return n;
 }
 
-/** Copy data from one VP to another
- *
- * Allocate a new pair using da, and copy over the value from the specified
- * vp.
- *
- * @todo Should be able to do type conversions.
- *
- * @param[in] ctx for talloc
- * @param[in] da of new attribute to alloc.
- * @param[in] vp to copy data from.
- * @return the new valuepair.
- */
-VALUE_PAIR *paircopyvpdata(TALLOC_CTX *ctx, DICT_ATTR const *da, VALUE_PAIR const *vp)
-{
-       VALUE_PAIR *n;
-
-       if (!vp) return NULL;
-
-       VERIFY_VP(vp);
-
-       /*
-        *      The types have to be identical, OR the "from" VP has
-        *      to be octets.
-        */
-       if (da->type != vp->da->type) {
-               int length;
-               uint8_t *p;
-               VALUE_PAIR const **pvp;
-
-               if (vp->da->type == PW_TYPE_OCTETS) {
-                       /*
-                        *      Decode the data.  It may be wrong!
-                        */
-                       if (rad_data2vp(da->attr, da->vendor, vp->vp_octets, vp->length, &n) < 0) {
-                               return NULL;
-                       }
-
-                       n->type = VT_DATA;
-                       return n;
-               }
-
-               /*
-                *      Else the destination type is octets
-                */
-               switch (vp->da->type) {
-               default:
-                       return NULL; /* can't do it */
-
-               case PW_TYPE_INTEGER:
-               case PW_TYPE_IPADDR:
-               case PW_TYPE_DATE:
-               case PW_TYPE_IFID:
-               case PW_TYPE_IPV6ADDR:
-               case PW_TYPE_IPV6PREFIX:
-               case PW_TYPE_BYTE:
-               case PW_TYPE_SHORT:
-               case PW_TYPE_ETHERNET:
-               case PW_TYPE_SIGNED:
-               case PW_TYPE_INTEGER64:
-               case PW_TYPE_IPV4PREFIX:
-                       break;
-               }
-
-               n = pairalloc(ctx, da);
-               if (!n) return NULL;
-
-               p = talloc_array(n, uint8_t, dict_attr_sizes[vp->da->type][1] + 2);
-
-               pvp = &vp;
-               length = rad_vp2attr(NULL, NULL, NULL, pvp, p, dict_attr_sizes[vp->da->type][1]);
-               if (length < 0) {
-                       pairfree(&n);
-                       return NULL;
-               }
-
-               pairmemcpy(n, p + 2, length - 2);
-               talloc_free(p);
-               return n;
-       }
-
-       n = pairalloc(ctx, da);
-       if (!n) return NULL;
-
-       memcpy(n, vp, sizeof(*n));
-       n->da = da;
-
-       if (n->type == VT_XLAT) {
-               n->value.xlat = talloc_typed_strdup(n, n->value.xlat);
-       }
-
-       if (n->data.ptr) switch (n->da->type) {
-       case PW_TYPE_TLV:
-       case PW_TYPE_OCTETS:
-               n->vp_octets = talloc_memdup(n, vp->vp_octets, n->length);
-               talloc_set_type(n->vp_octets, uint8_t);
-               break;
-
-       case PW_TYPE_STRING:
-               n->vp_strvalue = talloc_memdup(n, vp->vp_strvalue, n->length + 1);      /* NULL byte */
-               talloc_set_type(n->vp_strvalue, char);
-               break;
-
-       default:
-               break;
-       }
-
-       n->next = NULL;
-
-       return n;
-}
-
-
 /** Copy a pairlist.
  *
  * Copy all pairs from 'from' regardless of tag, attribute or vendor.
@@ -1084,14 +971,18 @@ void pairmove(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from)
  * Move pairs of a matching attribute number, vendor number and tag from the
  * the input list to the output list.
  *
+ * @note pairs which are moved have their parent changed to ctx.
+ *
  * @note pairfree should be called on the head of the old list to free unmoved
         attributes (if they're no longer needed).
  *
  * @param[in] ctx for talloc
  * @param[in,out] to destination list.
  * @param[in,out] from source list.
- * @param[in] attr to match, if PW_VENDOR_SPECIFIC and vendor 0, only VSAs will
- *           be copied.  If 0 and 0, all attributes will match
+ * @param[in] attr to match. If attribute PW_VENDOR_SPECIFIC and vendor 0,
+ *     will match (and therefore copy) only VSAs.
+ *     If attribute 0 and vendor 0  will match (and therefore copy) all
+ *     attributes.
  * @param[in] vendor to match.
  * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
  */
@@ -1193,7 +1084,7 @@ void pairfilter(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from, unsigned in
        }
 }
 
-static char const *hextab = "0123456789abcdef";
+static char const hextab[] = "0123456789abcdef";
 
 /** Convert string value to native attribute value
  *
@@ -1205,7 +1096,6 @@ static char const *hextab = "0123456789abcdef";
  */
 int pairparsevalue(VALUE_PAIR *vp, char const *value, size_t inlen)
 {
-       char const      *cs;
        DICT_VALUE      *dval;
        size_t          len;
        char            buffer[256];
@@ -1340,7 +1230,7 @@ int pairparsevalue(VALUE_PAIR *vp, char const *value, size_t inlen)
 
                vp->length = len >> 1;
                p = talloc_array(vp, uint8_t, vp->length);
-               if (fr_hex2bin(p, value + 2, len) != vp->length) {
+               if (fr_hex2bin(p, vp->length, value + 2, len) != vp->length) {
                        talloc_free(p);
                        fr_strerror_printf("Invalid hex data");
                        return -1;
@@ -1385,7 +1275,7 @@ int pairparsevalue(VALUE_PAIR *vp, char const *value, size_t inlen)
                        fr_strerror_printf("No memory");
                        return -1;
                }
-               if (fr_hex2bin(p, value + 2, len) != vp->length) {
+               if (fr_hex2bin(p, vp->length, value + 2, len) != vp->length) {
                        fr_strerror_printf("Invalid hex data in TLV");
                        return -1;
                }
@@ -1394,6 +1284,72 @@ int pairparsevalue(VALUE_PAIR *vp, char const *value, size_t inlen)
        }
                goto finish;
 
+       case PW_TYPE_IPV4_ADDR:
+       {
+               fr_ipaddr_t addr;
+
+               if (fr_pton4(&addr, value, inlen, fr_hostname_lookups, false) < 0) return -1;
+
+               /*
+                *      We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
+                *      print them this way.
+                */
+               if (addr.prefix != 32) {
+                       fr_strerror_printf("Invalid IPv4 mask length \"/%i\".  Only \"/32\" permitted "
+                                          "for non-prefix types", addr.prefix);
+                       return -1;
+               }
+
+               vp->vp_ipaddr = addr.ipaddr.ip4addr.s_addr;
+               vp->length = sizeof(vp->vp_ipaddr);
+       }
+               goto finish;
+
+       case PW_TYPE_IPV4_PREFIX:
+       {
+               fr_ipaddr_t addr;
+
+               if (fr_pton4(&addr, value, inlen, fr_hostname_lookups, false) < 0) return -1;
+
+               vp->vp_ipv4prefix[1] = addr.prefix;
+               memcpy(vp->vp_ipv4prefix + 2, &addr.ipaddr.ip4addr.s_addr, sizeof(vp->vp_ipv4prefix) - 2);
+               vp->length = sizeof(vp->vp_ipv4prefix);
+       }
+               goto finish;
+
+       case PW_TYPE_IPV6_ADDR:
+       {
+               fr_ipaddr_t addr;
+
+               if (fr_pton6(&addr, value, inlen, fr_hostname_lookups, false) < 0) return -1;
+
+               /*
+                *      We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
+                *      print them this way.
+                */
+               if (addr.prefix != 128) {
+                       fr_strerror_printf("Invalid IPv6 mask length \"/%i\".  Only \"/128\" permitted "
+                                          "for non-prefix types", addr.prefix);
+                       return -1;
+               }
+
+               memcpy(&vp->vp_ipv6addr, &addr.ipaddr.ip6addr.s6_addr, sizeof(vp->vp_ipv6addr));
+               vp->length = sizeof(vp->vp_ipv6addr);
+       }
+               goto finish;
+
+       case PW_TYPE_IPV6_PREFIX:
+       {
+               fr_ipaddr_t addr;
+
+               if (fr_pton6(&addr, value, inlen, fr_hostname_lookups, false) < 0) return -1;
+
+               vp->vp_ipv6prefix[1] = addr.prefix;
+               memcpy(vp->vp_ipv6prefix + 2, &addr.ipaddr.ip6addr.s6_addr, sizeof(vp->vp_ipv6prefix) - 2);
+               vp->length = sizeof(vp->vp_ipv6prefix);
+       }
+               goto finish;
+
        default:
                break;
        }
@@ -1414,57 +1370,6 @@ int pairparsevalue(VALUE_PAIR *vp, char const *value, size_t inlen)
        }
 
        switch(vp->da->type) {
-       case PW_TYPE_IPADDR:
-       {
-               char const *p;
-               fr_ipaddr_t ipaddr;
-               char ipv4[16];
-               /*
-                *      FIXME: complain if hostname
-                *      cannot be resolved, or resolve later!
-                */
-               p = NULL;
-
-               /*
-                *      Convert things which are obviously integers to IP addresses
-                *
-                *      We assume the number is the bigendian representation of the
-                *      IP address.
-                */
-               if (is_integer(value)) {
-                       vp->vp_ipaddr = htonl(atol(value));
-                       break;
-               }
-
-               /*
-                *      Certain applications/databases print IPv4 addresses with a
-                *      /32 suffix. Strip it off if the mask is 32, else error out.
-                */
-               p = strchr(value, '/');
-               if (p) {
-                       if ((p[1] != '3') || (p[2] != '2') || (p[3] != '\0')) {
-                               fr_strerror_printf("Invalid IP address suffix \"%s\".  Only '/32' permitted "
-                                                  "for non-prefix types", p);
-                               return -1;
-                       }
-
-                       strlcpy(ipv4, value, sizeof(ipv4));
-                       ipv4[p - value] = '\0';
-                       cs = ipv4;
-               } else {
-                       cs = value;
-               }
-
-               if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
-                       fr_strerror_printf("Failed to find IP address for %s", cs);
-                       return -1;
-               }
-
-               vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
-               vp->length = 4;
-       }
-               break;
-
        case PW_TYPE_BYTE:
        {
                char *p;
@@ -1577,119 +1482,6 @@ int pairparsevalue(VALUE_PAIR *vp, char const *value, size_t inlen)
                vp->length = 8;
                break;
 
-       case PW_TYPE_IPV6ADDR:
-       {
-               fr_ipaddr_t ipaddr;
-
-               if (ip_hton(value, AF_INET6, &ipaddr) < 0) {
-                       fr_strerror_printf("failed to parse IPv6 address "
-                                          "string \"%s\": %s", value, fr_strerror());
-                       return -1;
-               }
-               vp->vp_ipv6addr = ipaddr.ipaddr.ip6addr;
-               vp->length = 16; /* length of IPv6 address */
-       }
-               break;
-
-       case PW_TYPE_IPV6PREFIX:
-       {
-               char const *p;
-               unsigned int prefix;
-               char *eptr;
-
-               p = strchr(value, '/');
-               if (!p || ((p - value) >= 256)) {
-                       fr_strerror_printf("invalid IPv6 prefix string \"%s\"", value);
-                       return -1;
-               }
-
-               /*
-                *      Copy string to temporary buffer if we didn't do it earlier
-                */
-               if (inlen == 0) memcpy(buffer, value, p - value);
-               buffer[p - value] = '\0';
-
-               if (inet_pton(AF_INET6, buffer, vp->vp_ipv6prefix + 2) <= 0) {
-                       fr_strerror_printf("failed to parse IPv6 address string \"%s\"", value);
-                       return -1;
-               }
-
-               prefix = strtoul(p + 1, &eptr, 10);
-               if ((prefix > 128) || *eptr) {
-                       fr_strerror_printf("failed to parse IPv6 address string \"%s\"", value);
-                       return -1;
-               }
-               vp->vp_ipv6prefix[1] = prefix;
-
-               if (prefix < 128) {
-                       struct in6_addr addr;
-
-                       addr = fr_ipaddr_mask6((struct in6_addr *)(&vp->vp_ipv6prefix[2]), prefix);
-                       memcpy(vp->vp_ipv6prefix + 2, &addr, sizeof(addr));
-               }
-               vp->length = 16 + 2;
-       }
-               break;
-
-       case PW_TYPE_IPV4PREFIX:
-       {
-               char *p;
-               unsigned int prefix;
-               char *eptr;
-
-               p = strchr(value, '/');
-
-               /*
-                *      192.0.2.2 is parsed as if it was /32
-                */
-               if (!p) {
-                       vp->vp_ipv4prefix[1] = 32;
-
-                       if (inet_pton(AF_INET, value, vp->vp_ipv4prefix + 2) <= 0) {
-                               fr_strerror_printf("failed to parse IPv4 address string \"%s\"", value);
-                               return -1;
-                       }
-                       vp->length = sizeof(vp->vp_ipv4prefix);
-                       break;
-               }
-
-               /*
-                *      Otherwise parse the prefix
-                */
-               if ((size_t)(p - value) >= sizeof(buffer)) {
-                       fr_strerror_printf("invalid IPv4 prefix string \"%s\"", value);
-                       return -1;
-               }
-
-               /*
-                *      Copy string to temporary buffer if we didn't do it earlier
-                */
-               if (inlen == 0) memcpy(buffer, value, p - value);
-               buffer[p - value] = '\0';
-
-               if (inet_pton(AF_INET, buffer, vp->vp_ipv4prefix + 2) <= 0) {
-                       fr_strerror_printf("failed to parse IPv4 address string \"%s\"", value);
-                       return -1;
-               }
-
-               prefix = strtoul(p + 1, &eptr, 10);
-               if ((prefix > 32) || *eptr) {
-                       fr_strerror_printf("failed to parse IPv4 address string \"%s\"", value);
-                       return -1;
-               }
-               vp->vp_ipv4prefix[1] = prefix;
-
-               if (prefix < 32) {
-                       struct in_addr addr;
-
-                       addr = fr_ipaddr_mask((struct in_addr *)(&vp->vp_ipv4prefix[2]), prefix);
-                       memcpy(vp->vp_ipv4prefix + 2, &addr, sizeof(addr));
-               }
-
-               vp->length = sizeof(vp->vp_ipv4prefix);
-       }
-               break;
-
        case PW_TYPE_ETHERNET:
        {
                char const *c1, *c2, *cp;
@@ -1743,12 +1535,12 @@ int pairparsevalue(VALUE_PAIR *vp, char const *value, size_t inlen)
         *      These are not dynamic da, and will have the same vendor
         *      and attribute as the original.
         */
-       case PW_TYPE_COMBO_IP:
+       case PW_TYPE_IP_ADDR:
        {
                DICT_ATTR const *da;
 
                if (inet_pton(AF_INET6, value, &vp->vp_ipv6addr) > 0) {
-                       da = dict_attrbytype(vp->da->attr, vp->da->vendor, PW_TYPE_IPV6ADDR);
+                       da = dict_attrbytype(vp->da->attr, vp->da->vendor, PW_TYPE_IPV6_ADDR);
                        if (!da) {
                                fr_strerror_printf("Cannot find ipv6addr for %s", vp->da->name);
                                return -1;
@@ -1759,13 +1551,13 @@ int pairparsevalue(VALUE_PAIR *vp, char const *value, size_t inlen)
                        fr_ipaddr_t ipaddr;
 
                        da = dict_attrbytype(vp->da->attr, vp->da->vendor,
-                                            PW_TYPE_IPADDR);
+                                            PW_TYPE_IPV4_ADDR);
                        if (!da) {
                                fr_strerror_printf("Cannot find ipaddr for %s", vp->da->name);
                                return -1;
                        }
 
-                       if (ip_hton(value, AF_INET, &ipaddr) < 0) {
+                       if (ip_hton(&ipaddr, AF_INET, value, false) < 0) {
                                fr_strerror_printf("Failed to find IPv4 address for %s", value);
                                return -1;
                        }
@@ -1914,7 +1706,7 @@ static VALUE_PAIR *pairmake_any(TALLOC_CTX *ctx,
        vp->length = size >> 1;
        data = talloc_array(vp, uint8_t, vp->length);
 
-       if (fr_hex2bin(data, value + 2, size) != vp->length) {
+       if (fr_hex2bin(data, vp->length, value + 2, size) != vp->length) {
                fr_strerror_printf("Invalid hex string");
                talloc_free(vp);
                return NULL;
@@ -2519,19 +2311,19 @@ int8_t paircmp_value(VALUE_PAIR const *one, VALUE_PAIR const *two)
                compare = memcmp(&one->vp_ether, &two->vp_ether, sizeof(one->vp_ether));
                break;
 
-       case PW_TYPE_IPADDR:
+       case PW_TYPE_IPV4_ADDR:
                compare = (int64_t) ntohl(one->vp_ipaddr) - (int64_t) ntohl(two->vp_ipaddr);
                break;
 
-       case PW_TYPE_IPV6ADDR:
+       case PW_TYPE_IPV6_ADDR:
                compare = memcmp(&one->vp_ipv6addr, &two->vp_ipv6addr, sizeof(one->vp_ipv6addr));
                break;
 
-       case PW_TYPE_IPV6PREFIX:
+       case PW_TYPE_IPV6_PREFIX:
                compare = memcmp(&one->vp_ipv6prefix, &two->vp_ipv6prefix, sizeof(one->vp_ipv6prefix));
                break;
 
-       case PW_TYPE_IPV4PREFIX:
+       case PW_TYPE_IPV4_PREFIX:
                compare = memcmp(&one->vp_ipv4prefix, &two->vp_ipv4prefix, sizeof(one->vp_ipv4prefix));
                break;
 
@@ -2543,7 +2335,8 @@ int8_t paircmp_value(VALUE_PAIR const *one, VALUE_PAIR const *two)
         *      None of the types below should be in the REQUEST
         */
        case PW_TYPE_INVALID:           /* We should never see these */
-       case PW_TYPE_COMBO_IP:          /* This should of been converted into IPADDR/IPV6ADDR */
+       case PW_TYPE_IP_ADDR:           /* This should of been converted into IPADDR/IPV6ADDR */
+       case PW_TYPE_IP_PREFIX: /* This should of been converted into IPADDR/IPV6ADDR */
        case PW_TYPE_TLV:
        case PW_TYPE_EXTENDED:
        case PW_TYPE_LONG_EXTENDED:
@@ -2695,12 +2488,12 @@ int8_t paircmp_op(VALUE_PAIR const *a, FR_TOKEN op, VALUE_PAIR const *b)
        if (!a || !b) return -1;
 
        switch (a->da->type) {
-       case PW_TYPE_IPADDR:
+       case PW_TYPE_IPV4_ADDR:
                switch (b->da->type) {
-               case PW_TYPE_IPADDR:            /* IPv4 and IPv4 */
+               case PW_TYPE_IPV4_ADDR:         /* IPv4 and IPv4 */
                        goto cmp;
 
-               case PW_TYPE_IPV4PREFIX:        /* IPv4 and IPv4 Prefix */
+               case PW_TYPE_IPV4_PREFIX:       /* IPv4 and IPv4 Prefix */
                        return paircmp_op_cidr(op, 4, 32, (uint8_t const *) &a->vp_ipaddr,
                                               b->vp_ipv4prefix[1], (uint8_t const *) &b->vp_ipv4prefix + 2);
 
@@ -2710,14 +2503,14 @@ int8_t paircmp_op(VALUE_PAIR const *a, FR_TOKEN op, VALUE_PAIR const *b)
                }
                break;
 
-       case PW_TYPE_IPV4PREFIX:                /* IPv4 and IPv4 Prefix */
+       case PW_TYPE_IPV4_PREFIX:               /* IPv4 and IPv4 Prefix */
                switch (b->da->type) {
-               case PW_TYPE_IPADDR:
+               case PW_TYPE_IPV4_ADDR:
                        return paircmp_op_cidr(op, 4, a->vp_ipv4prefix[1],
                                               (uint8_t const *) &a->vp_ipv4prefix + 2,
                                               32, (uint8_t const *) &b->vp_ipaddr);
 
-               case PW_TYPE_IPV4PREFIX:        /* IPv4 Prefix and IPv4 Prefix */
+               case PW_TYPE_IPV4_PREFIX:       /* IPv4 Prefix and IPv4 Prefix */
                        return paircmp_op_cidr(op, 4, a->vp_ipv4prefix[1],
                                               (uint8_t const *) &a->vp_ipv4prefix + 2,
                                               b->vp_ipv4prefix[1], (uint8_t const *) &b->vp_ipv4prefix + 2);
@@ -2728,12 +2521,12 @@ int8_t paircmp_op(VALUE_PAIR const *a, FR_TOKEN op, VALUE_PAIR const *b)
                }
                break;
 
-       case PW_TYPE_IPV6ADDR:
+       case PW_TYPE_IPV6_ADDR:
                switch (b->da->type) {
-               case PW_TYPE_IPV6ADDR:          /* IPv6 and IPv6 */
+               case PW_TYPE_IPV6_ADDR:         /* IPv6 and IPv6 */
                        goto cmp;
 
-               case PW_TYPE_IPV6PREFIX:        /* IPv6 and IPv6 Preifx */
+               case PW_TYPE_IPV6_PREFIX:       /* IPv6 and IPv6 Preifx */
                        return paircmp_op_cidr(op, 16, 128, (uint8_t const *) &a->vp_ipv6addr,
                                               b->vp_ipv6prefix[1], (uint8_t const *) &b->vp_ipv6prefix + 2);
                        break;
@@ -2744,14 +2537,14 @@ int8_t paircmp_op(VALUE_PAIR const *a, FR_TOKEN op, VALUE_PAIR const *b)
                }
                break;
 
-       case PW_TYPE_IPV6PREFIX:
+       case PW_TYPE_IPV6_PREFIX:
                switch (b->da->type) {
-               case PW_TYPE_IPV6ADDR:          /* IPv6 Prefix and IPv6 */
+               case PW_TYPE_IPV6_ADDR:         /* IPv6 Prefix and IPv6 */
                        return paircmp_op_cidr(op, 16, a->vp_ipv6prefix[1],
                                               (uint8_t const *) &a->vp_ipv6prefix + 2,
                                               128, (uint8_t const *) &b->vp_ipv6addr);
 
-               case PW_TYPE_IPV6PREFIX:        /* IPv6 Prefix and IPv6 */
+               case PW_TYPE_IPV6_PREFIX:       /* IPv6 Prefix and IPv6 */
                        return paircmp_op_cidr(op, 16, a->vp_ipv6prefix[1],
                                               (uint8_t const *) &a->vp_ipv6prefix + 2,
                                               b->vp_ipv6prefix[1], (uint8_t const *) &b->vp_ipv6prefix + 2);
@@ -3070,6 +2863,87 @@ void pairstrncpy(VALUE_PAIR *vp, char const *src, size_t len)
        pairtypeset(vp);
 }
 
+/** Copy data from one VP to another
+ *
+ * Allocate a new pair using da, and copy over the value from the specified vp.
+ *
+ * @todo Should be able to do type conversions.
+ *
+ * @param[in,out] vp to update.
+ * @param[in] da Type of data represented by data.
+ * @param[in] data to copy.
+ * @param[in] len of data to copy.
+ */
+int pairdatacpy(VALUE_PAIR *vp, DICT_ATTR const *da, value_data_t const *data, size_t len)
+{
+       void *old;
+       VERIFY_VP(vp);
+
+       /*
+        *      The da->types have to be identical, OR the "from" da->type has
+        *      to be octets.
+        */
+       if (vp->da->type != da->type) {
+               /*
+                *      Decode the octets buffer using the RADIUS decoder.
+                */
+               if (da->type == PW_TYPE_OCTETS) {
+                       if (data2vp(vp, NULL, NULL, NULL, vp->da, data->octets, len, len, &vp) < 0) return -1;
+                       vp->type = VT_DATA;
+                       return 0;
+               }
+
+               /*
+                *      Else if the destination da->type is octets
+                */
+               if (vp->da->type == PW_TYPE_OCTETS) {
+                       int ret;
+                       uint8_t *buff;
+                       VALUE_PAIR const *pvp = vp;
+
+                       buff = talloc_array(vp, uint8_t, dict_attr_sizes[da->type][1] + 2);
+
+                       ret = rad_vp2rfc(NULL, NULL, NULL, &pvp, buff, dict_attr_sizes[da->type][1]);
+                       if (ret < 0) return -1;
+
+                       pairmemcpy(vp, buff + 2, ret - 2);
+                       talloc_free(buff);
+
+                       return 0;
+               }
+
+               /*
+                *      Fixme...
+                */
+               fr_strerror_printf("Data conversion not supported");
+               return -1;
+       }
+
+       /*
+        *      Clear existing value if there is one
+        */
+       memcpy(&old, &vp->data.ptr, sizeof(old));
+       talloc_free(old);
+
+       switch (vp->da->type) {
+       case PW_TYPE_TLV:
+       case PW_TYPE_OCTETS:
+               pairmemcpy(vp, data->octets, len);
+               break;
+
+       case PW_TYPE_STRING:
+               pairstrncpy(vp, data->strvalue, len);
+               break;
+
+       default:
+               memcpy(&vp->data, data, sizeof(vp->data));
+               break;
+       }
+       vp->length = len;
+
+       return 0;
+}
+
 /** Print data into an "string" data type.
  *
  * @param[in,out] vp to update