]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Add new variable of type bitflags:flags
authorRoy Marples <roy@marples.name>
Fri, 15 May 2015 10:01:24 +0000 (10:01 +0000)
committerRoy Marples <roy@marples.name>
Fri, 15 May 2015 10:01:24 +0000 (10:01 +0000)
where the flags ABCDEFGH, A is 10000000, B is 01000000, etc.
Variables with the name reserved are no longer processed.

dhcp-common.c
dhcp-common.h
dhcpcd-definitions.conf
dhcpcd.conf.5.in
if-options.c

index 2936b55c79ba730cb5bf5c8714f26e109cc3f20b..0d67472e070726573f0da6632908c6a80889b6f6 100644 (file)
@@ -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;
        }
index a3d62fcac616ec03abe43a624669bf9919a61eb1..5f7b15404d580e9403f44b13fd5c8dfd4005de64 100644 (file)
@@ -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 *);
 
index d2991c51f54fce7f9758a645c7dc7226ee4044ba..e8d6b17fcae71e758c70102000abd8b1e39c4f61 100644 (file)
@@ -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
index ab072da79b280d2e0458272aac1eca7068eaf615..80022337737cb727c26682b931bf8b758d256c59 100644 (file)
@@ -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
index 8bb1185b27fe2e7ec89fb06d55119e6c8ad340ca..c2d232bf28914d1e8ca37287988ffda57275a791 100644 (file)
@@ -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: