From 94e003201500a784202436787c47ba84ad1cb6ae Mon Sep 17 00:00:00 2001 From: "Alan T. DeKok" Date: Thu, 24 Sep 2015 21:09:17 -0400 Subject: [PATCH] better implementation of dict_parent --- src/lib/dict.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/src/lib/dict.c b/src/lib/dict.c index e3935ab..569e8fa 100644 --- a/src/lib/dict.c +++ b/src/lib/dict.c @@ -162,6 +162,10 @@ int const fr_attr_shift[MAX_TLV_NEST + 1] = { 0, 8, 16, 24, 29 }; int const fr_attr_mask[MAX_TLV_NEST + 1] = { 0xff, 0xff, 0xff, 0x1f, 0x07 }; +/* + * attr & fr_attr_parent_mask[i] == Nth parent of attr + */ +static unsigned int const fr_attr_parent_mask[MAX_TLV_NEST + 1] = { 0, 0x000000ff, 0x0000ffff, 0x00ffffff, 0x1fffffff }; /* * Create the hash of the name. @@ -1399,15 +1403,65 @@ int dict_str2oid(char const *ptr, unsigned int *pvalue, unsigned int *pvendor, */ static DICT_ATTR const *dict_parent(unsigned int attr, unsigned int vendor) { - if (vendor < FR_MAX_VENDOR) { - return dict_attrbyvalue(attr & 0xff, vendor); + int i; + unsigned int base_vendor; + + /* + * RFC attributes can't be of type "tlv". + */ + if (!vendor) return NULL; + + base_vendor = vendor & (FR_MAX_VENDOR - 1); + + /* + * It's a real vendor. + */ + if (base_vendor != 0) { + DICT_VENDOR const *dv; + + dv = dict_vendorbyvalue(base_vendor); + if (!dv) return NULL; + + /* + * Only standard format attributes can be of type "tlv", + * Except for DHCP. + */ + if ((vendor != 54) && ((dv->type != 1) || (dv->length != 1))) return NULL; + + for (i = MAX_TLV_NEST; i > 0; i--) { + unsigned int parent; + + parent = attr & fr_attr_parent_mask[i]; + + if (parent != attr) return dict_attrbyvalue(parent, vendor); /* not base_vendor */ + } + + /* + * It was a top-level VSA. There's no parent. + * We COULD return the appropriate enclosing VSA + * (26, or 241.26, etc.) but that's not what we + * want. + */ + return NULL; } - if (attr < 256) { - return dict_attrbyvalue((vendor / FR_MAX_VENDOR) & 0xff, 0); + /* + * It's an extended attribute. Return the base Extended-Attr-X + */ + if (attr < 256) return dict_attrbyvalue((vendor / FR_MAX_VENDOR) & 0xff, 0); + + + /* + * Figure out which attribute it is. + */ + for (i = MAX_TLV_NEST; i > 0; i--) { + unsigned int parent; + + parent = attr & fr_attr_parent_mask[i]; + if (parent != attr) return dict_attrbyvalue(parent, vendor); /* not base_vendor */ } - return dict_attrbyvalue(attr & 0xff, vendor); + return NULL; } @@ -1703,7 +1757,7 @@ static int process_attribute(char const* fn, int const line, } /* - * + * Shift the value left. */ value <<= fr_attr_shift[tlv_depth]; value |= block_tlv->attr; -- 2.1.4