From: Roy Marples Date: Wed, 2 Jul 2014 18:59:19 +0000 (+0000) Subject: Fix defining new options in dhcpcd.conf and requesting them. X-Git-Tag: v6.4.1~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=49b749f0f9e1b12007a0191822b8e143ceaaee5c;p=thirdparty%2Fdhcpcd.git Fix defining new options in dhcpcd.conf and requesting them. --- diff --git a/dhcp-common.c b/dhcp-common.c index d877436a..d8ffc5dd 100644 --- a/dhcp-common.c +++ b/dhcp-common.c @@ -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; diff --git a/dhcp-common.h b/dhcp-common.h index deef34a0..e0994bf8 100644 --- a/dhcp-common.h +++ b/dhcp-common.h @@ -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 d4ba47c9..0b108a30 100644 --- 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 7201848e..1c10e1cf 100644 --- 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 || diff --git a/if-options.c b/if-options.c index 2b695efe..fa20513e 100644 --- a/if-options.c +++ b/if-options.c @@ -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);