]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Fix defining new options in dhcpcd.conf and requesting them.
authorRoy Marples <roy@marples.name>
Wed, 2 Jul 2014 18:59:19 +0000 (18:59 +0000)
committerRoy Marples <roy@marples.name>
Wed, 2 Jul 2014 18:59:19 +0000 (18:59 +0000)
dhcp-common.c
dhcp-common.h
dhcp.c
dhcp6.c
if-options.c

index d877436a23319296f6784a1e850ce260bc477905..d8ffc5dd30e3dad16fb64a4c50a31e7a796654f2 100644 (file)
@@ -86,6 +86,7 @@ dhcp_vendor(char *str, size_t len)
 
 int
 make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
+    const struct dhcp_opt *odopts, size_t odopts_len,
     uint8_t *mask, const char *opts, int add)
 {
        char *token, *o, *p, *t;
@@ -94,14 +95,14 @@ make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
        unsigned int n;
        size_t i;
 
-       o = p = strdup(opts);
        if (opts == NULL)
                return -1;
+       o = p = strdup(opts);
        while ((token = strsep(&p, ", "))) {
                if (*token == '\0')
                        continue;
-               for (i = 0, opt = dopts; i < dopts_len; i++, opt++) {
-                       match = 0;
+               match = 0;
+               for (i = 0, opt = odopts; i < odopts_len; i++, opt++) {
                        if (strcmp(opt->var, token) == 0)
                                match = 1;
                        else {
@@ -111,26 +112,40 @@ make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
                                        if (opt->option == n)
                                                match = 1;
                        }
-                       if (match) {
-                               if (add == 2 && !(opt->type & ADDRIPV4)) {
-                                       free(o);
-                                       errno = EINVAL;
-                                       return -1;
-                               }
-                               if (add == 1 || add == 2)
-                                       add_option_mask(mask,
-                                           opt->option);
-                               else
-                                       del_option_mask(mask,
-                                           opt->option);
+                       if (match)
                                break;
+               }
+               if (match == 0) {
+                       for (i = 0, opt = dopts; i < dopts_len; i++, opt++) {
+                               if (strcmp(opt->var, token) == 0)
+                                       match = 1;
+                               else {
+                                       errno = 0;
+                                       n = (unsigned int)strtol(token, &t, 0);
+                                       if (errno == 0 && !*t)
+                                               if (opt->option == n)
+                                                       match = 1;
+                               }
+                               if (match)
+                                       break;
                        }
                }
-               if (!opt->option) {
+               if (!match || !opt->option) {
                        free(o);
                        errno = ENOENT;
                        return -1;
                }
+               if (add == 2 && !(opt->type & ADDRIPV4)) {
+                       free(o);
+                       errno = EINVAL;
+                       return -1;
+               }
+               if (add == 1 || add == 2)
+                       add_option_mask(mask,
+                           opt->option);
+               else
+                       del_option_mask(mask,
+                           opt->option);
        }
        free(o);
        return 0;
index deef34a0f19152d7c502b7d2381ca9de1e87703b..e0994bf8f1b02ea93d7abfe9e5e9276bf222f51f 100644 (file)
@@ -88,6 +88,7 @@ size_t dhcp_vendor(char *, size_t);
 #define del_option_mask(var, val) (var[val >> 3] &= ~(1 << (val & 7)))
 #define has_option_mask(var, val) (var[val >>3] & (1 << (val & 7)))
 int make_option_mask(const struct dhcp_opt *, size_t,
+    const struct dhcp_opt *, size_t,
     uint8_t *, const char *, int);
 
 size_t encode_rfc1035(const char *src, uint8_t *dst);
diff --git a/dhcp.c b/dhcp.c
index d4ba47c9b6acf638c2f554129e2256d530290733..0b108a305eb4a71f7455572cec45a554930e0bc2 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -943,6 +943,30 @@ make_message(struct dhcp_message **message,
                                goto toobig;
                        *p++ = (uint8_t)opt->option;
                }
+               for (i = 0, opt = ifo->dhcp_override;
+                   i < ifo->dhcp_override_len;
+                   i++, opt++)
+               {
+                       /* Check if added above */
+                       for (lp = n_params + 1; lp < p; lp++)
+                               if (*lp == (uint8_t)opt->option)
+                                       break;
+                       if (lp < p)
+                               continue;
+                       if (!(opt->type & REQUEST ||
+                               has_option_mask(ifo->requestmask, opt->option)))
+                               continue;
+                       if (opt->type & NOREQ)
+                               continue;
+                       if (type == DHCP_INFORM &&
+                           (opt->option == DHO_RENEWALTIME ||
+                               opt->option == DHO_REBINDTIME))
+                               continue;
+                       len = (size_t)((p - m) + 2);
+                       if (len > sizeof(*dhcp))
+                               goto toobig;
+                       *p++ = (uint8_t)opt->option;
+               }
                *n_params = (uint8_t)(p - n_params - 1);
        }
 
diff --git a/dhcp6.c b/dhcp6.c
index 7201848eec8343fccd05827e5374c7c4f709946b..1c10e1cf16ded3d1f9f64efef84e35cbd05276d4 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
@@ -311,11 +311,11 @@ dhcp6_makemessage(struct interface *ifp)
        struct dhcp6_message *m;
        struct dhcp6_option *o, *so;
        const struct dhcp6_option *si, *unicast;
-       size_t l, len, ml, auth_len;
+       size_t l, n, len, ml, auth_len;
        uint8_t u8, type;
        uint16_t *u16, n_options;
        struct if_options *ifo;
-       const struct dhcp_opt *opt;
+       const struct dhcp_opt *opt, *opt2;
        uint8_t IA, *p;
        uint32_t u32;
        const struct ipv6_addr *ap;
@@ -355,6 +355,27 @@ dhcp6_makemessage(struct interface *ifp)
                for (l = 0, opt = ifp->ctx->dhcp6_opts;
                    l < ifp->ctx->dhcp6_opts_len;
                    l++, opt++)
+               {
+                       for (n = 0, opt2 = ifo->dhcp6_override;
+                           n < ifo->dhcp6_override_len;
+                           n++, opt2++)
+                       {
+                               if (opt->option == opt2->option)
+                                       break;
+                       }
+                       if (n < ifo->dhcp6_override_len)
+                           continue;
+                       if (!(opt->type & NOREQ) &&
+                           (opt->type & REQUEST ||
+                           has_option_mask(ifo->requestmask6, opt->option)))
+                       {
+                               n_options++;
+                               len += sizeof(*u16);
+                       }
+               }
+               for (l = 0, opt = ifo->dhcp6_override;
+                   l < ifo->dhcp6_override_len;
+                   l++, opt++)
                {
                        if (!(opt->type & NOREQ) &&
                            (opt->type & REQUEST ||
@@ -627,6 +648,28 @@ dhcp6_makemessage(struct interface *ifp)
                        for (l = 0, opt = ifp->ctx->dhcp6_opts;
                            l < ifp->ctx->dhcp6_opts_len;
                            l++, opt++)
+                       {
+                               for (n = 0, opt2 = ifo->dhcp6_override;
+                                   n < ifo->dhcp6_override_len;
+                                   n++, opt2++)
+                               {
+                                       if (opt->option == opt2->option)
+                                               break;
+                               }
+                               if (n < ifo->dhcp6_override_len)
+                                   continue;
+                               if (!(opt->type & NOREQ) &&
+                                   (opt->type & REQUEST ||
+                                   has_option_mask(ifo->requestmask6,
+                                       opt->option)))
+                               {
+                                       *u16++ = htons(opt->option);
+                                       o->len += sizeof(*u16);
+                               }
+                       }
+                       for (l = 0, opt = ifo->dhcp6_override;
+                           l < ifo->dhcp6_override_len;
+                           l++, opt++)
                        {
                                if (!(opt->type & NOREQ) &&
                                    (opt->type & REQUEST ||
index 2b695efe315476da499919e41a564e245293b88b..fa20513e0f60e70d7cb465f72bb4b4319a1d9dea 100644 (file)
@@ -518,7 +518,9 @@ parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net,
 
 static const char *
 set_option_space(struct dhcpcd_ctx *ctx,
-    const char *arg, const struct dhcp_opt **d, size_t *dl,
+    const char *arg,
+    const struct dhcp_opt **d, size_t *dl,
+    const struct dhcp_opt **od, size_t *odl,
     struct if_options *ifo,
     uint8_t *request[], uint8_t *require[], uint8_t *no[])
 {
@@ -527,6 +529,8 @@ set_option_space(struct dhcpcd_ctx *ctx,
        if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
                *d = ctx->dhcp6_opts;
                *dl = ctx->dhcp6_opts_len;
+               *od = ifo->dhcp6_override;
+               *odl = ifo->dhcp6_override_len;
                *request = ifo->requestmask6;
                *require = ifo->requiremask6;
                *no = ifo->nomask6;
@@ -537,9 +541,13 @@ set_option_space(struct dhcpcd_ctx *ctx,
 #ifdef INET
        *d = ctx->dhcp_opts;
        *dl = ctx->dhcp_opts_len;
+       *od = ifo->dhcp_override;
+       *odl = ifo->dhcp_override_len;
 #else
        *d = NULL;
        *dl = 0;
+       *od = NULL;
+       *odl = 0;
 #endif
        *request = ifo->requestmask;
        *require = ifo->requiremask;
@@ -630,10 +638,10 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
        struct in_addr addr, addr2;
        in_addr_t *naddr;
        struct rt *rt;
-       const struct dhcp_opt *d;
+       const struct dhcp_opt *d, *od;
        uint8_t *request, *require, *no;
        struct dhcp_opt **dop, *ndop;
-       size_t *dop_len, dl;
+       size_t *dop_len, dl, odl;
        struct vivco *vivco;
        struct token *token;
        struct group *grp;
@@ -733,10 +741,10 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
                }
                break;
        case 'o':
-               arg = set_option_space(ctx, arg, &d, &dl, ifo,
+               arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
                    &request, &require, &no);
-               if (make_option_mask(d, dl, request, arg, 1) != 0 ||
-                   make_option_mask(d, dl, no, arg, -1) != 0)
+               if (make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
+                   make_option_mask(d, dl, od, odl, no, arg, -1) != 0)
                {
                        syslog(LOG_ERR, "unknown option `%s'", arg);
                        return -1;
@@ -952,22 +960,22 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
                ifo->options |= DHCPCD_MASTER;
                break;
        case 'O':
-               arg = set_option_space(ctx, arg, &d, &dl, ifo,
+               arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
                    &request, &require, &no);
-               if (make_option_mask(d, dl, request, arg, -1) != 0 ||
-                   make_option_mask(d, dl, require, arg, -1) != 0 ||
-                   make_option_mask(d, dl, no, arg, 1) != 0)
+               if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
+                   make_option_mask(d, dl, od, odl, require, arg, -1) != 0 ||
+                   make_option_mask(d, dl, od, odl, no, arg, 1) != 0)
                {
                        syslog(LOG_ERR, "unknown option `%s'", arg);
                        return -1;
                }
                break;
        case 'Q':
-               arg = set_option_space(ctx, arg, &d, &dl, ifo,
+               arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
                    &request, &require, &no);
-               if (make_option_mask(d, dl, require, arg, 1) != 0 ||
-                   make_option_mask(d, dl, request, arg, 1) != 0 ||
-                   make_option_mask(d, dl, no, arg, -1) != 0)
+               if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 ||
+                   make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
+                   make_option_mask(d, dl, od, odl, no, arg, -1) != 0)
                {
                        syslog(LOG_ERR, "unknown option `%s'", arg);
                        return -1;
@@ -1156,8 +1164,11 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
                }
                break;
        case O_DESTINATION:
-               if (make_option_mask(ctx->dhcp_opts, ctx->dhcp_opts_len,
-                   ifo->dstmask, arg, 2) != 0) {
+               arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
+                   &request, &require, &no);
+               if (make_option_mask(d, dl, od, odl,
+                   ifo->dstmask, arg, 2) != 0)
+               {
                        if (errno == EINVAL)
                                syslog(LOG_ERR, "option `%s' does not take"
                                    " an IPv4 address", arg);