summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--proto/radv/config.Y14
-rw-r--r--proto/radv/packets.c45
-rw-r--r--proto/radv/radv.h10
3 files changed, 69 insertions, 0 deletions
diff --git a/proto/radv/config.Y b/proto/radv/config.Y
index 8d4a3ab9..5c213d50 100644
--- a/proto/radv/config.Y
+++ b/proto/radv/config.Y
@@ -25,6 +25,15 @@ static struct radv_dnssl_config this_radv_dnssl;
static list radv_dns_list; /* Used by radv_rdnss and radv_dnssl */
static u8 radv_mult_val; /* Used by radv_mult for second return value */
+static inline void
+radv_add_to_custom_list(list *l, int type, struct bytestring *payload)
+{
+ if (type < 0 || type > 255) cf_error("RA cusom type must be in range 0-255");
+ struct radv_custom_config *cf = cfg_allocz(sizeof(struct radv_custom_config));
+ add_tail(l, NODE cf);
+ cf->type = type;
+ cf->payload = payload;
+}
CF_DECLS
@@ -52,6 +61,7 @@ radv_proto_start: proto_start RADV
init_list(&RADV_CFG->pref_list);
init_list(&RADV_CFG->rdnss_list);
init_list(&RADV_CFG->dnssl_list);
+ init_list(&RADV_CFG->custom_list);
};
radv_proto_item:
@@ -61,6 +71,7 @@ radv_proto_item:
| PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); }
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); }
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
+ | OTHER TYPE expr BYTESTRING { radv_add_to_custom_list(&RADV_CFG->custom_list, $3, $4); }
| TRIGGER net_ip6 { RADV_CFG->trigger = $2; }
| PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; }
;
@@ -82,6 +93,7 @@ radv_iface_start:
init_list(&RADV_IFACE->pref_list);
init_list(&RADV_IFACE->rdnss_list);
init_list(&RADV_IFACE->dnssl_list);
+ init_list(&RADV_IFACE->custom_list);
RADV_IFACE->min_ra_int = (u32) -1; /* undefined */
RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT;
@@ -124,8 +136,10 @@ radv_iface_item:
| PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); }
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); }
+ | OTHER TYPE expr BYTESTRING { radv_add_to_custom_list(&RADV_IFACE->custom_list, $3, $4); }
| RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; }
| DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; }
+ | OTHER LOCAL bool { RADV_IFACE->custom_local = $3; }
;
radv_preference:
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)
diff --git a/proto/radv/radv.h b/proto/radv/radv.h
index 14d40f8a..8c716158 100644
--- a/proto/radv/radv.h
+++ b/proto/radv/radv.h
@@ -51,6 +51,7 @@ struct radv_config
list pref_list; /* Global list of prefix configs (struct radv_prefix_config) */
list rdnss_list; /* Global list of RDNSS configs (struct radv_rdnss_config) */
list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */
+ list custom_list; /* Global list of custom configs (struct radv_custom_config) */
net_addr trigger; /* Prefix of a trigger route, if defined */
u8 propagate_routes; /* Do we propagate more specific routes (RFC 4191)? */
@@ -63,6 +64,7 @@ struct radv_iface_config
list pref_list; /* Local list of prefix configs (struct radv_prefix_config) */
list rdnss_list; /* Local list of RDNSS configs (struct radv_rdnss_config) */
list dnssl_list; /* Local list of DNSSL configs (struct radv_dnssl_config) */
+ list custom_list; /* Local list of custom configs (struct radv_custom_config) */
u32 min_ra_int; /* Standard options from RFC 4861 */
u32 max_ra_int;
@@ -75,6 +77,7 @@ struct radv_iface_config
u8 rdnss_local; /* Global list is not used for RDNSS */
u8 dnssl_local; /* Global list is not used for DNSSL */
+ u8 custom_local; /* Global list is not used for custom */
u8 managed; /* Standard options from RFC 4861 */
u8 other_config;
@@ -122,6 +125,13 @@ struct radv_dnssl_config
const char *domain; /* Domain for DNS search list, in processed form */
};
+struct radv_custom_config
+{
+ node n;
+ u8 type; /* Identifier of the type of option */
+ struct bytestring *payload; /* Payload of the option */
+};
+
/*
* One more specific route as per RFC 4191.
*