summaryrefslogtreecommitdiff
path: root/proto/radv/packets.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/radv/packets.c')
-rw-r--r--proto/radv/packets.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/proto/radv/packets.c b/proto/radv/packets.c
index 5cd8b2de..d1f86ec1 100644
--- a/proto/radv/packets.c
+++ b/proto/radv/packets.c
@@ -82,6 +82,13 @@ struct radv_opt_dnssl
char domain[];
};
+struct radv_opt_custom
+{
+ u8 type;
+ u8 length;
+ u8 payload[];
+};
+
static int
radv_prepare_route(struct radv_iface *ifa, struct radv_route *rt,
char **buf, char *bufend)
@@ -255,6 +262,36 @@ radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *b
}
static int
+radv_prepare_custom(struct radv_iface *ifa, list *custom_list, char **buf, char *bufend)
+{
+ struct radv_custom_config *ccf = HEAD(*custom_list);
+
+ while(NODE_VALID(ccf))
+ {
+ struct radv_opt_custom *op = (void *) *buf;
+ /* Add 2 octets for type and size and 8 - 1 for ceiling the division up to 8 octets */
+ int size = (ccf->payload->length + 2 + 8 - 1) / 8;
+ if (bufend - *buf < size * 8)
+ goto too_much;
+
+ memset(op, 0, size * 8); /* Clear buffer so there is no tail garbage */
+ op->type = ccf->type;
+ op->length = size;
+ memcpy(op->payload, ccf->payload->data, ccf->payload->length);
+
+ *buf += 8 * op->length;
+ ccf = NODE_NEXT(ccf);
+ }
+
+ return 0;
+
+ too_much:
+ log(L_WARN "%s: Too many RA options on interface %s",
+ ifa->ra->p.name, ifa->iface->name);
+ return -1;
+}
+
+static int
radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *px,
char **buf, char *bufend)
{
@@ -352,6 +389,14 @@ radv_prepare_ra(struct radv_iface *ifa)
if (radv_prepare_dnssl(ifa, &ic->dnssl_list, &buf, bufend) < 0)
goto done;
+ if (! ic->custom_local)
+ if (radv_prepare_custom(ifa, &cf->custom_list, &buf, bufend) < 0)
+ goto done;
+
+ if (radv_prepare_custom(ifa, &ic->custom_list, &buf, bufend) < 0)
+ goto done;
+
+
if (p->fib_up)
{
FIB_WALK(&p->routes, struct radv_route, rt)