summaryrefslogtreecommitdiffstats
path: root/src/libsystemd-network/sd-radv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-network/sd-radv.c')
-rw-r--r--src/libsystemd-network/sd-radv.c77
1 files changed, 52 insertions, 25 deletions
diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c
index cb7bc07f5a..a35311efb9 100644
--- a/src/libsystemd-network/sd-radv.c
+++ b/src/libsystemd-network/sd-radv.c
@@ -231,6 +231,17 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_us
if (ra->dnssl)
iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->dnssl, ra->dnssl->length * 8);
+ if (FLAGS_SET(ra->flags, ND_RA_FLAG_HOME_AGENT)) {
+ ra->home_agent.nd_opt_home_agent_info_type = ND_OPT_HOME_AGENT_INFO;
+ ra->home_agent.nd_opt_home_agent_info_len = 1;
+
+ /* 0 means to place the current Router Lifetime value */
+ if (ra->home_agent.nd_opt_home_agent_info_lifetime == 0)
+ ra->home_agent.nd_opt_home_agent_info_lifetime = adv.nd_ra_router_lifetime;
+
+ iov[msg.msg_iovlen++] = IOVEC_MAKE(&ra->home_agent, sizeof(ra->home_agent));
+ }
+
if (sendmsg(ra->fd, &msg, 0) < 0)
return -errno;
@@ -264,8 +275,7 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
if (r < 0)
switch (r) {
case -EADDRNOTAVAIL:
- log_radv(ra, "Received RS from non-link-local address %s. Ignoring",
- IN6_ADDR_TO_STRING(&src));
+ log_radv(ra, "Received RS from neither link-local nor null address. Ignoring");
return 0;
case -EMULTIHOP:
@@ -286,6 +296,9 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
return 0;
}
+ /* TODO: if the sender address is null, check that the message does not have the source link-layer
+ * address option. See RFC 4861 Section 6.1.1. */
+
const char *addr = IN6_ADDR_TO_STRING(&src);
r = radv_send(ra, &src, ra->lifetime_usec);
@@ -570,6 +583,39 @@ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
return 0;
}
+int sd_radv_set_home_agent_information(sd_radv *ra, int home_agent) {
+ assert_return(ra, -EINVAL);
+
+ if (ra->state != RADV_STATE_IDLE)
+ return -EBUSY;
+
+ SET_FLAG(ra->flags, ND_RA_FLAG_HOME_AGENT, home_agent);
+
+ return 0;
+}
+
+int sd_radv_set_home_agent_preference(sd_radv *ra, uint16_t preference) {
+ assert_return(ra, -EINVAL);
+
+ if (ra->state != RADV_STATE_IDLE)
+ return -EBUSY;
+
+ ra->home_agent.nd_opt_home_agent_info_preference = htobe16(preference);
+
+ return 0;
+}
+
+int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint16_t lifetime) {
+ assert_return(ra, -EINVAL);
+
+ if (ra->state != RADV_STATE_IDLE)
+ return -EBUSY;
+
+ ra->home_agent.nd_opt_home_agent_info_lifetime = htobe16(lifetime);
+
+ return 0;
+}
+
int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
sd_radv_prefix *found = NULL;
int r;
@@ -1091,33 +1137,14 @@ int sd_radv_pref64_prefix_set_prefix(
uint16_t pref64_lifetime;
uint8_t prefixlen_code;
+ int r;
assert_return(p, -EINVAL);
assert_return(prefix, -EINVAL);
- switch (prefixlen) {
- case 96:
- prefixlen_code = 0;
- break;
- case 64:
- prefixlen_code = 1;
- break;
- case 56:
- prefixlen_code = 2;
- break;
- case 48:
- prefixlen_code = 3;
- break;
- case 40:
- prefixlen_code = 4;
- break;
- case 32:
- prefixlen_code = 5;
- break;
- default:
- log_radv(NULL, "Unsupported PREF64 prefix length %u. Valid lengths are 32, 40, 48, 56, 64 and 96", prefixlen);
- return -EINVAL;
- }
+ r = pref64_prefix_length_to_plc(prefixlen, &prefixlen_code);
+ if (r < 0)
+ return log_radv_errno(NULL, r, "Unsupported PREF64 prefix length %u. Valid lengths are 32, 40, 48, 56, 64 and 96", prefixlen);
if (lifetime_usec == USEC_INFINITY || DIV_ROUND_UP(lifetime_usec, 8 * USEC_PER_SEC) >= UINT64_C(1) << 13)
return -EINVAL;