# sub-option to be present in option 63 encoding. Each of them is
# simply a type length pair with length set to zero....
#
-ATTRIBUTE NWIP-Does-Not-Exist .1 bool encode=exists
-ATTRIBUTE NWIP-Exist-In-Options-Area .2 bool encode=exists
-ATTRIBUTE NWIP-Exist-In-Same-File .3 bool encode=exists
-ATTRIBUTE NWIP-Exist-But-Too-Big .4 bool encode=exists
+ATTRIBUTE NWIP-Does-Not-Exist .1 bool exists
+ATTRIBUTE NWIP-Exist-In-Options-Area .2 bool exists
+ATTRIBUTE NWIP-Exist-In-Same-File .3 bool exists
+ATTRIBUTE NWIP-Exist-But-Too-Big .4 bool exists
# Also from RFC2242:
#
##############################################################################
# Rapid Commit
-ATTRIBUTE Rapid-Commit 80 bool encode=exists
+ATTRIBUTE Rapid-Commit 80 bool exists
# If this attribute exists, then the reply is sent to the relay agent on the UDP
# source port, and not to port 67.
#
-ATTRIBUTE Remember-Relay-Port 82.19 bool encode=exists
-
+ATTRIBUTE Remember-Relay-Port 82.19 bool exists
uint8_t eth_bcast[ETH_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+FR_DICT_ATTR_FLAG_FUNC(fr_dhcpv4_attr_flags_t, dns_label)
+FR_DICT_ATTR_FLAG_FUNC(fr_dhcpv4_attr_flags_t, exists)
+
+static int dict_flag_prefix(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
+{
+ static fr_table_num_sorted_t const table[] = {
+ { L("bits"), DHCPV4_FLAG_PREFIX_BITS },
+ { L("split"), DHCPV4_FLAG_PREFIX_SPLIT }
+ };
+ static size_t table_len = NUM_ELEMENTS(table);
+
+ fr_dhcpv4_attr_flags_t *flags = fr_dict_attr_ext(*da_p, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC);
+ fr_dhcpv4_attr_flags_prefix_t flag;
+
+ flag = fr_table_value_by_str(table, value, DHCPV4_FLAG_PREFIX_INVALID);
+ if (flag == DHCPV4_FLAG_PREFIX_INVALID) {
+ fr_strerror_printf("Unknown prefix type '%s'", value);
+ return -1;
+ }
+ flags->prefix = flag;
+
+ return 0;
+}
+
+static fr_dict_flag_parser_t const dhcpv4_flags[] = {
+ { L("dns_label"), { .func = dict_flag_dns_label } },
+ { L("exists"), { .func = dict_flag_exists } },
+ { L("prefix"), { .func = dict_flag_prefix } }
+};
+
int8_t fr_dhcpv4_attr_cmp(void const *a, void const *b)
{
fr_pair_t const *my_a = a, *my_b = b;
PAIR_VERIFY(c);
if (c->da->dict != dict || c->da->flags.internal) continue;
- if (c->vp_type == FR_TYPE_BOOL && da_is_bool_exists(c->da) && !c->vp_bool) continue;
+ if (c->vp_type == FR_TYPE_BOOL && fr_dhcpv4_flag_exists(c->da) && !c->vp_bool) continue;
break;
}
fprintf(fp, "\n");
}
-static fr_table_num_ordered_t const subtype_table[] = {
- { L("dns_label"), FLAG_ENCODE_DNS_LABEL },
- { L("encode=dns_label"), FLAG_ENCODE_DNS_LABEL },
- { L("prefix=split"), FLAG_ENCODE_SPLIT_PREFIX },
- { L("prefix=bits"), FLAG_ENCODE_BITS_PREFIX },
- { L("encode=exists"), FLAG_ENCODE_BOOL_EXISTS },
-};
-
static bool attr_valid(fr_dict_attr_t *da)
{
/*
*/
if (da->flags.extra || !da->flags.subtype) return true;
- if ((da->type != FR_TYPE_STRING) && (da->flags.subtype == FLAG_ENCODE_DNS_LABEL)) {
+ if ((da->type != FR_TYPE_STRING) && (fr_dhcpv4_flag_dns_label(da))) {
fr_strerror_const("The 'dns_label' flag can only be used with attributes of type 'string'");
return false;
}
if ((da->type != FR_TYPE_IPV4_PREFIX) &&
- ((da->flags.subtype == FLAG_ENCODE_SPLIT_PREFIX) || (da->flags.subtype == FLAG_ENCODE_BITS_PREFIX))) {
+ (fr_dhcpv4_flag_prefix(da))) {
fr_strerror_const("The 'prefix=...' flag can only be used with attributes of type 'ipv4prefix'");
return false;
}
- if ((da->type != FR_TYPE_BOOL) && (da->flags.subtype == FLAG_ENCODE_BOOL_EXISTS)) {
- fr_strerror_const("The 'encode=exists' flag can only be used with attributes of type 'bool'");
+ if ((da->type != FR_TYPE_BOOL) && fr_dhcpv4_flag_exists(da)) {
+ fr_strerror_const("The 'exists' flag can only be used with attributes of type 'bool'");
return false;
}
.name = "dhcpv4",
.default_type_size = 1,
.default_type_length = 1,
- .subtype_table = subtype_table,
- .subtype_table_len = NUM_ELEMENTS(subtype_table),
.attr = {
+ .flags_table = dhcpv4_flags,
+ .flags_table_len = NUM_ELEMENTS(dhcpv4_flags),
+ .flags_len = sizeof(fr_dhcpv4_attr_flags_t),
.valid = attr_valid
},
/*
* @todo - we might need to limit this to only one DNS label.
*/
- if ((parent->type == FR_TYPE_STRING) && da_is_dns_label(parent)) {
+ if ((parent->type == FR_TYPE_STRING) && fr_dhcpv4_flag_dns_label(parent)) {
return fr_pair_dns_labels_from_network(ctx, out, parent, data, data, data_len, NULL, false);
}
* 4 octets of address
* 4 octets of mask
*/
- if (da_is_split_prefix(da)) {
+ if (fr_dhcpv4_flag_prefix_split(da)) {
uint32_t ipaddr, mask;
if (data_len < 8) goto raw;
break;
}
- if (da_is_bits_prefix(vp->da)) {
+ if (fr_dhcpv4_flag_prefix_bits(vp->da)) {
size_t needs;
if ((data_len == 0) || (*p > 32)) goto raw;
slen = fr_pair_raw_from_network(ctx, out, da, data + 2, len);
- } else if ((da->type == FR_TYPE_STRING) && da_is_dns_label(da)) {
+ } else if ((da->type == FR_TYPE_STRING) && fr_dhcpv4_flag_dns_label(da)) {
slen = fr_pair_dns_labels_from_network(ctx, out, da, data + 2, data + 2, len, NULL, true);
} else if (da->flags.array) {
#define FR_DHCP_PACKET_CODE_VALID(_code) (((_code) > 0) && ((_code) < FR_DHCP_CODE_MAX))
-/** subtype values for DHCPv4 and DHCPv6
- *
- */
-enum {
- FLAG_ENCODE_NONE = 0, //!< no particular encoding for DHCPv6 strings
- FLAG_ENCODE_DNS_LABEL, //!< encode as DNS label
- FLAG_ENCODE_SPLIT_PREFIX, //!< encode IPv4 prefixes as Policy-Filter, split into IP/mask
- FLAG_ENCODE_BITS_PREFIX, //!< encode IPv4 prefixes as prefix bits, followed by IP.
- FLAG_ENCODE_BOOL_EXISTS, //!< bool as existence checks
-};
-
-#define da_is_dns_label(_da) (!(_da)->flags.extra && ((_da)->flags.subtype == FLAG_ENCODE_DNS_LABEL))
-#define da_is_split_prefix(_da) (!(_da)->flags.extra && ((_da)->flags.subtype == FLAG_ENCODE_SPLIT_PREFIX))
-#define da_is_bits_prefix(_da) (!(_da)->flags.extra && ((_da)->flags.subtype == FLAG_ENCODE_BITS_PREFIX))
-#define da_is_bool_exists(_da) (!(_da)->flags.extra && ((_da)->flags.subtype == FLAG_ENCODE_BOOL_EXISTS))
-
typedef struct {
uint8_t opcode;
uint8_t htype;
TALLOC_CTX *tmp_ctx; //!< for temporary things cleaned up during decoding
} fr_dhcpv4_ctx_t;
+typedef enum {
+ DHCPV4_FLAG_PREFIX_INVALID = -1,
+ DHCPV4_FLAG_PREFIX_NONE = 0,
+ DHCPV4_FLAG_PREFIX_BITS = 1,
+ DHCPV4_FLAG_PREFIX_SPLIT = 2,
+} fr_dhcpv4_attr_flags_prefix_t;
+
+typedef struct {
+ bool exists;
+ bool dns_label;
+ fr_dhcpv4_attr_flags_prefix_t prefix;
+} fr_dhcpv4_attr_flags_t;
+
+static inline fr_dhcpv4_attr_flags_t const *fr_dhcpv4_attr_flags(fr_dict_attr_t const *da)
+{
+ return fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC);
+}
+
+#define fr_dhcpv4_flag_dns_label(_da) (fr_dhcpv4_attr_flags(_da)->dns_label)
+#define fr_dhcpv4_flag_exists(_da) (fr_dhcpv4_attr_flags(_da)->exists)
+
+#define fr_dhcpv4_flag_prefix(_da) fr_dhcpv4_attr_flags(_da)->prefix
+#define fr_dhcpv4_flag_prefix_bits(_da) (fr_dhcpv4_attr_flags(_da)->prefix == DHCPV4_FLAG_PREFIX_BITS)
+#define fr_dhcpv4_flag_prefix_split(_da) (fr_dhcpv4_attr_flags(_da)->prefix == DHCPV4_FLAG_PREFIX_SPLIT)
+
/*
* base.c
*/
* Rapid-Commit does this. Options 19/20 require encoding as one byte of 0/1.
*/
case FR_TYPE_BOOL:
- if (da_is_bool_exists(vp->da)) {
+ if (fr_dhcpv4_flag_exists(vp->da)) {
break;
}
FR_DBUFF_IN_RETURN(&work_dbuff, (uint8_t) (vp->vp_bool == true));
break;
case FR_TYPE_IPV4_PREFIX:
- if (da_is_split_prefix(vp->da)) {
+ if (fr_dhcpv4_flag_prefix_split(vp->da)) {
uint32_t mask;
mask = ~((~(uint32_t) 0) >> vp->vp_ip.prefix);
break;
}
- if (da_is_bits_prefix(vp->da)) {
+ if (fr_dhcpv4_flag_prefix_bits(vp->da)) {
size_t num_bytes = (vp->vp_ip.prefix + 0x07) >> 3;
FR_DBUFF_IN_RETURN(&work_dbuff, (uint8_t) vp->vp_ip.prefix);
*
* https://tools.ietf.org/html/rfc8415#section-10
*/
- if (da_is_dns_label(da)) {
+ if (fr_dhcpv4_flag_dns_label(da)) {
fr_dbuff_marker_t last_byte, src;
fr_dbuff_marker(&last_byte, &work_dbuff);