From: Roy Marples Date: Fri, 15 May 2015 10:01:24 +0000 (+0000) Subject: Add new variable of type bitflags:flags X-Git-Tag: v6.9.0~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cc71162dc663760d9715b03713f7fe56c55bf591;p=thirdparty%2Fdhcpcd.git Add new variable of type bitflags:flags where the flags ABCDEFGH, A is 10000000, B is 01000000, etc. Variables with the name reserved are no longer processed. --- diff --git a/dhcp-common.c b/dhcp-common.c index 2936b55c..0d67472e 100644 --- a/dhcp-common.c +++ b/dhcp-common.c @@ -76,6 +76,8 @@ dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols) printf(" ip6address"); else if (opt->type & FLAG) printf(" flag"); + else if (opt->type & BITFLAG) + printf(" bitflags"); else if (opt->type & RFC3397) printf(" domain"); else if (opt->type & DOMAIN) @@ -86,9 +88,9 @@ dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols) printf(" raw"); else if (opt->type & BINHEX) printf(" binhex"); - else if (opt->type & STRING) + else if (opt->type & STRING) printf(" string"); - if (opt->type & RFC3361) + if (opt->type & RFC3361) printf(" rfc3361"); if (opt->type & RFC3442) printf(" rfc3442"); @@ -559,7 +561,7 @@ dhcp_optlen(const struct dhcp_opt *opt, size_t dl) sz = sizeof(uint32_t); else if (opt->type & UINT16) sz = sizeof(uint16_t); - else if (opt->type & UINT8) + else if (opt->type & (UINT8 | BITFLAG)) sz = sizeof(uint8_t); else if (opt->type & ADDRIPV6) sz = ADDR6SZ; @@ -569,15 +571,9 @@ dhcp_optlen(const struct dhcp_opt *opt, size_t dl) return (dl < sz ? 0 : sz); } -#ifdef INET6 -#define PO_IFNAME -#else -#define PO_IFNAME __unused -#endif - -ssize_t -print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl, - PO_IFNAME const char *ifname) +static ssize_t +print_option(char *s, size_t len, const struct dhcp_opt *opt, + const uint8_t *data, size_t dl, const char *ifname) { const uint8_t *e, *t; uint16_t u16; @@ -589,7 +585,11 @@ print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl, size_t l; char *tmp; - if (type & RFC3397) { +#ifndef INET6 + UNUSED(ifname); +#endif + + if (opt->type & RFC3397) { sl = decode_rfc3397(NULL, 0, data, dl); if (sl == 0 || sl == -1) return sl; @@ -598,32 +598,32 @@ print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl, if (tmp == NULL) return -1; decode_rfc3397(tmp, l, data, dl); - sl = print_string(s, len, type, (uint8_t *)tmp, l - 1); + sl = print_string(s, len, opt->type, (uint8_t *)tmp, l - 1); free(tmp); return sl; } #ifdef INET - if (type & RFC3361) { + if (opt->type & RFC3361) { if ((tmp = decode_rfc3361(data, dl)) == NULL) return -1; l = strlen(tmp); - sl = print_string(s, len, type, (uint8_t *)tmp, l); + sl = print_string(s, len, opt->type, (uint8_t *)tmp, l); free(tmp); return sl; } - if (type & RFC3442) + if (opt->type & RFC3442) return decode_rfc3442(s, len, data, dl); - if (type & RFC5969) + if (opt->type & RFC5969) return decode_rfc5969(s, len, data, dl); #endif - if (type & STRING) - return print_string(s, len, type, data, dl); + if (opt->type & STRING) + return print_string(s, len, opt->type, data, dl); - if (type & FLAG) { + if (opt->type & FLAG) { if (s) { *s++ = '1'; *s = '\0'; @@ -631,27 +631,50 @@ print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl, return 1; } + if (opt->type & BITFLAG) { + /* bitflags are a string, MSB first, such as ABCDEFGH + * where A is 10000000, B is 01000000, etc. */ + bytes = 0; + for (l = 0, sl = sizeof(opt->bitflags) - 1; + l < sizeof(opt->bitflags); + l++, sl--) + { + /* Don't print NULL or 0 flags */ + if (opt->bitflags[l] != '\0' && + opt->bitflags[l] != '0' && + *data & (1 << sl)) + { + if (s) + *s++ = opt->bitflags[l]; + bytes++; + } + } + if (s) + *s = '\0'; + return bytes; + } + if (!s) { - if (type & UINT8) + if (opt->type & UINT8) l = 3; - else if (type & UINT16) { + else if (opt->type & UINT16) { l = 5; dl /= 2; - } else if (type & SINT16) { + } else if (opt->type & SINT16) { l = 6; dl /= 2; - } else if (type & UINT32) { + } else if (opt->type & UINT32) { l = 10; dl /= 4; - } else if (type & SINT32) { + } else if (opt->type & SINT32) { l = 11; dl /= 4; - } else if (type & ADDRIPV4) { + } else if (opt->type & ADDRIPV4) { l = 16; dl /= 4; } #ifdef INET6 - else if (type & ADDRIPV6) { + else if (opt->type & ADDRIPV6) { e = data + dl; l = 0; while (data < e) { @@ -680,36 +703,36 @@ print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl, bytes++; len--; } - if (type & UINT8) { + if (opt->type & UINT8) { sl = snprintf(s, len, "%u", *data); data++; - } else if (type & UINT16) { + } else if (opt->type & UINT16) { memcpy(&u16, data, sizeof(u16)); u16 = ntohs(u16); sl = snprintf(s, len, "%u", u16); data += sizeof(u16); - } else if (type & SINT16) { + } else if (opt->type & SINT16) { memcpy(&u16, data, sizeof(u16)); s16 = (int16_t)ntohs(u16); sl = snprintf(s, len, "%d", s16); data += sizeof(u16); - } else if (type & UINT32) { + } else if (opt->type & UINT32) { memcpy(&u32, data, sizeof(u32)); u32 = ntohl(u32); sl = snprintf(s, len, "%u", u32); data += sizeof(u32); - } else if (type & SINT32) { + } else if (opt->type & SINT32) { memcpy(&u32, data, sizeof(u32)); s32 = (int32_t)ntohl(u32); sl = snprintf(s, len, "%d", s32); data += sizeof(u32); - } else if (type & ADDRIPV4) { + } else if (opt->type & ADDRIPV4) { memcpy(&addr.s_addr, data, sizeof(addr.s_addr)); sl = snprintf(s, len, "%s", inet_ntoa(addr)); data += sizeof(addr.s_addr); } #ifdef INET6 - else if (type & ADDRIPV6) { + else if (opt->type & ADDRIPV6) { ssize_t r; r = ipv6_printaddr(s, len, data, ifname); @@ -773,7 +796,7 @@ dhcp_envoption1(struct dhcpcd_ctx *ctx, char **env, const char *prefix, if (opt->len && opt->len < ol) ol = opt->len; - len = print_option(NULL, 0, opt->type, od, ol, ifname); + len = print_option(NULL, 0, opt, od, ol, ifname); if (len < 0) return 0; if (vname) @@ -795,7 +818,7 @@ dhcp_envoption1(struct dhcpcd_ctx *ctx, char **env, const char *prefix, else v += snprintf(val, e, "%s=", prefix); if (len != 0) - print_option(v, (size_t)len + 1, opt->type, od, ol, ifname); + print_option(v, (size_t)len + 1, opt, od, ol, ifname); return e; } @@ -816,7 +839,8 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix, /* If no embedded or encapsulated options, it's easy */ if (opt->embopts_len == 0 && opt->encopts_len == 0) { - if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[0], + if (!(opt->type & RESERVED) && + dhcp_envoption1(ctx, env == NULL ? NULL : &env[0], prefix, opt, 1, od, ol, ifname)) return 1; return 0; @@ -857,10 +881,12 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix, /* Use the option prefix if the embedded option * name is different. * This avoids new_fqdn_fqdn which would be silly. */ - ov = strcmp(opt->var, eopt->var); - if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[n], - pfx, eopt, ov, od, e, ifname)) - n++; + if (!(eopt->type & RESERVED)) { + ov = strcmp(opt->var, eopt->var); + if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[n], + pfx, eopt, ov, od, e, ifname)) + n++; + } od += e; ol -= e; } diff --git a/dhcp-common.h b/dhcp-common.h index a3d62fca..5f7b1540 100644 --- a/dhcp-common.h +++ b/dhcp-common.h @@ -66,6 +66,8 @@ #define RAW (1 << 23) #define ESCSTRING (1 << 24) #define ESCFILE (1 << 25) +#define BITFLAG (1 << 26) +#define RESERVED (1 << 27) struct dhcp_opt { uint32_t option; /* Also used for IANA Enterpise Number */ @@ -74,6 +76,7 @@ struct dhcp_opt { char *var; int index; /* Index counter for many instances of the same option */ + char bitflags[8]; /* Embedded options. * The option code is irrelevant here. */ @@ -103,8 +106,6 @@ int make_option_mask(const struct dhcp_opt *, size_t, size_t encode_rfc1035(const char *src, uint8_t *dst); ssize_t decode_rfc3397(char *, size_t, const uint8_t *, size_t); ssize_t print_string(char *, size_t, int, const uint8_t *, size_t); -ssize_t print_option(char *, size_t, int, const uint8_t *, size_t, - const char *); int dhcp_set_leasefile(char *, size_t, int, const struct interface *, const char *); diff --git a/dhcpcd-definitions.conf b/dhcpcd-definitions.conf index d2991c51..e8d6b17f 100644 --- a/dhcpcd-definitions.conf +++ b/dhcpcd-definitions.conf @@ -107,7 +107,7 @@ define 80 norequest flag rapid_commit # DHCP Fully Qualified Domain Name, RFC4702 define 81 embed fqdn -embed byte flags +embed bitflags=0000NEOS flags embed byte rcode1 embed byte rcode2 embed domain fqdn @@ -291,13 +291,12 @@ encap 255 flag global definend 1 binhex source_address definend 2 binhex target_address -# FIXME: L and A flag need to be extracted from reserved1 definend 3 index embed prefix_information embed byte length -embed byte reserved1 +embed bitflags=LA flags embed uint32 vltime embed uint32 pltime -embed uint32 reserved2 +embed uint32 reserved embed array ip6address prefix # option 4 is only for Redirect messages @@ -428,7 +427,7 @@ define6 38 binhex subscriber_id # DHCPv6 Fully Qualified Domain Name, RFC4704 define6 39 embed fqdn -embed byte flags +embed bitflags=00000NOS flags embed domain fqdn # DHCPv6 PANA Authentication Agnet, RC5192 diff --git a/dhcpcd.conf.5.in b/dhcpcd.conf.5.in index ab072da7..80022337 100644 --- a/dhcpcd.conf.5.in +++ b/dhcpcd.conf.5.in @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 14, 2015 +.Dd May 15, 2015 .Dt DHCPCD.CONF 5 .Os .Sh NAME @@ -703,6 +703,11 @@ is not the same as defined in the parent option, it is prefixed with the parent .Ar variable first with an underscore. +If the +.Ar variable +has the name of +.Ar reserved +then it is not processed. .It Ic encap Ar code Ar type Ar variable Defines an encapsulated variable within the defined option. The length is determined by the @@ -736,35 +741,42 @@ Lengths can be specified for string and binhex types, but this is generally with other data embedded afterwards in the same option. .Bl -tag -width indent .It Ic ipaddress -An IPv4 address, 4 bytes +An IPv4 address, 4 bytes. .It Ic ip6address -An IPv6 address, 16 bytes +An IPv6 address, 16 bytes. .It Ic string Op : Ic length A NVT ASCII string of printable characters. .It Ic byte -A byte +A byte. +.It Ic bitflags : Ic flags +A byte represented as a string of flags, most significant bit first. +For example, using ABCDEFGH then A would equal 10000000, B 01000000, +C 00100000, etc. +If the bit is not set, the flag is not printed. +A flag of 0 is not printed even if the bit postition is set. +This is to allow reservation of the first bits while assinging the last bits. .It Ic int16 -A signed 16bit integer, 2 bytes +A signed 16bit integer, 2 bytes. .It Ic uint16 -An unsigned 16bit integer, 2 bytes +An unsigned 16bit integer, 2 bytes. .It Ic int32 -A signed 32bit integer, 4 bytes +A signed 32bit integer, 4 bytes. .It Ic uint32 -An unsigned 32bit integer, 4 bytes -.It Ic flag -A fixed value (1) to indicate that the option is present, 0 bytes +An unsigned 32bit integer, 4 bytes. +.It Ic flag +A fixed value (1) to indicate that the option is present, 0 bytes. .It Ic domain -A RFC 3397 encoded string +A RFC 3397 encoded string. .It Ic dname -A RFC 1035 validated string +A RFC 1035 validated string. .It Ic binhex Op : Ic length -Binary data expressed as hexadecimal +Binary data expressed as hexadecimal. .It Ic embed -Contains embedded options (implies encap as well) +Contains embedded options (implies encap as well). .It Ic encap -Contains encapsulated options (implies embed as well) +Contains encapsulated options (implies embed as well). .It Ic option -References an option from the global definition +References an option from the global definition. .El .Ss Example definition .D1 # DHCP option 81, Fully Qualified Domain Name, RFC4702 diff --git a/if-options.c b/if-options.c index 8bb1185b..c2d232bf 100644 --- a/if-options.c +++ b/if-options.c @@ -646,7 +646,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, int e, i, t; long l; unsigned long u; - char *p = NULL, *fp, *np, **nconf; + char *p = NULL, *bp, *fp, *np, **nconf; ssize_t s; struct in_addr addr, addr2; in_addr_t *naddr; @@ -1554,13 +1554,18 @@ err_sla: /* length */ if (np) { *np++ = '\0'; + bp = NULL; /* No bitflag */ l = (long)strtou(np, NULL, 0, 0, LONG_MAX, &e); if (e) { - logger(ctx, LOG_ERR, "failed to convert length"); + logger(ctx,LOG_ERR, "failed to convert length"); return -1; } - } else + } else { l = 0; + bp = strchr(arg, '='); /* bitflag assignment */ + if (bp) + *bp++ = '\0'; + } t = 0; if (strcasecmp(arg, "request") == 0) { t |= REQUEST; @@ -1609,6 +1614,8 @@ err_sla: t |= STRING; else if (strcasecmp(arg, "byte") == 0) t |= UINT8; + else if (strcasecmp(arg, "bitflags") == 0) + t |= BITFLAG; else if (strcasecmp(arg, "uint16") == 0) t |= UINT16; else if (strcasecmp(arg, "int16") == 0) @@ -1656,6 +1663,11 @@ err_sla: logger(ctx, LOG_WARNING, "ignoring array for strings"); t &= ~ARRAY; } + if (t & BITFLAG) { + if (bp == NULL) + logger(ctx, LOG_WARNING, + "missing bitflag assignment"); + } /* variable */ if (!fp) { if (!(t & OPTION)) { @@ -1669,10 +1681,16 @@ err_sla: fp = strwhite(arg); if (fp) *fp++ = '\0'; - np = strdup(arg); - if (np == NULL) { - logger(ctx, LOG_ERR, "%s: %m", __func__); - return -1; + if (strcasecmp(arg, "reserved")) { + np = strdup(arg); + if (np == NULL) { + logger(ctx, LOG_ERR, + "%s: %m", __func__); + return -1; + } + } else { + np = NULL; + t |= RESERVED; } } if (opt != O_EMBED) { @@ -1707,6 +1725,13 @@ err_sla: ndop->type = t; ndop->len = (size_t)l; ndop->var = np; + if (bp) { + dl = strlen(bp); + memcpy(ndop->bitflags, bp, dl); + memset(ndop->bitflags + dl, 0, + sizeof(ndop->bitflags) - dl); + } else + memset(ndop->bitflags, 0, sizeof(ndop->bitflags)); /* Save the define for embed and encap options */ switch (opt) { case O_DEFINE: