Add dhcpv6_custom_opts_fill() which appends user-specified custom
options to DHCPv6 response packets, and call it from the main dhcpv6()
handler after the built-in DNS and FQDN options.
Each custom option is written with its DHCPv6 option header (code +
length) followed by the binary-encoded value from dhcpv6_opt_parse().
Options that would exceed the IPv6 minimum MTU are skipped with a
debug message.
Signed-off-by: Anshu Kumari
---
dhcpv6.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/dhcpv6.c b/dhcpv6.c
index 85e2926..590c40d 100644
--- a/dhcpv6.c
+++ b/dhcpv6.c
@@ -798,6 +798,41 @@ static size_t dhcpv6_client_fqdn_fill(const struct iov_tail *data,
return offset + sizeof(struct opt_hdr) + opt_len;
}
+/**
+ * dhcpv6_custom_opts_fill() - Append user-specified custom options to reply
+ * @c: Execution context
+ * @buf: Response message buffer
+ * @offset: Current offset in buffer
+ *
+ * Return: updated offset after appending custom options
+ */
+static size_t dhcpv6_custom_opts_fill(const struct ctx *c,
+ char *buf, int offset)
+{
+ int i;
+
+ for (i = 0; i < c->custom_v6opts_count; i++) {
+ struct opt_hdr *hdr;
+ uint16_t len = c->custom_v6opts[i].len;
+
+ if ((size_t)offset + sizeof(struct opt_hdr) + len > OPT_MAX_SIZE) {
+ debug("DHCPv6: custom option %u doesn't fit, skipping",
+ c->custom_v6opts[i].code);
+ continue;
+ }
+
+ hdr = (struct opt_hdr *)(buf + offset);
+ hdr->t = htons(c->custom_v6opts[i].code);
+ hdr->l = htons(len);
+ offset += sizeof(struct opt_hdr);
+
+ memcpy(buf + offset, c->custom_v6opts[i].val, len);
+ offset += len;
+ }
+
+ return offset;
+}
+
/**
* dhcpv6() - Check if this is a DHCPv6 message, reply as needed
* @c: Execution context
@@ -936,6 +971,7 @@ int dhcpv6(struct ctx *c, struct iov_tail *data,
sizeof(struct opt_hdr) + ntohs(client_id->l);
n = dhcpv6_dns_fill(c, (char *)&resp, n);
n = dhcpv6_client_fqdn_fill(data, c, (char *)&resp, n);
+ n = dhcpv6_custom_opts_fill(c, (char *)&resp, n);
resp.hdr.xid = mh->xid;
--
2.54.0