summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libsystemd-network/ndisc-option.c66
-rw-r--r--src/libsystemd-network/ndisc-option.h33
2 files changed, 88 insertions, 11 deletions
diff --git a/src/libsystemd-network/ndisc-option.c b/src/libsystemd-network/ndisc-option.c
index 61c58d2971..855ec0469a 100644
--- a/src/libsystemd-network/ndisc-option.c
+++ b/src/libsystemd-network/ndisc-option.c
@@ -131,6 +131,7 @@ static int ndisc_option_compare_func(const sd_ndisc_option *x, const sd_ndisc_op
case SD_NDISC_OPTION_TARGET_LL_ADDRESS:
case SD_NDISC_OPTION_REDIRECTED_HEADER:
case SD_NDISC_OPTION_MTU:
+ case SD_NDISC_OPTION_HOME_AGENT:
case SD_NDISC_OPTION_FLAGS_EXTENSION:
case SD_NDISC_OPTION_CAPTIVE_PORTAL:
/* These options cannot be specified multiple times. */
@@ -497,6 +498,63 @@ static int ndisc_option_build_mtu(const sd_ndisc_option *option, uint8_t **ret)
return 0;
}
+int ndisc_option_add_home_agent(Set **options, size_t offset, uint16_t preference, usec_t lifetime) {
+ assert(options);
+
+ if (lifetime > UINT16_MAX * USEC_PER_SEC)
+ return -EINVAL;
+
+ sd_ndisc_option *p = ndisc_option_new(SD_NDISC_OPTION_HOME_AGENT, offset);
+ if (!p)
+ return -ENOMEM;
+
+ p->home_agent = (sd_ndisc_home_agent) {
+ .preference = preference,
+ .lifetime = lifetime,
+ };
+
+ return ndisc_option_consume(options, p);
+}
+
+static int ndisc_option_parse_home_agent(Set **options, size_t offset, size_t len, const uint8_t *opt) {
+ const struct nd_opt_home_agent_info *p = (const struct nd_opt_home_agent_info*) ASSERT_PTR(opt);
+
+ assert(options);
+
+ if (len != sizeof(struct nd_opt_home_agent_info))
+ return -EBADMSG;
+
+ if (p->nd_opt_home_agent_info_type != SD_NDISC_OPTION_HOME_AGENT)
+ return -EBADMSG;
+
+ return ndisc_option_add_home_agent(
+ options, offset,
+ be16toh(p->nd_opt_home_agent_info_preference),
+ be16_sec_to_usec(p->nd_opt_home_agent_info_lifetime, /* max_as_infinity = */ false));
+}
+
+static int ndisc_option_build_home_agent(const sd_ndisc_option *option, uint8_t **ret) {
+ assert(option);
+ assert(option->type == SD_NDISC_OPTION_HOME_AGENT);
+ assert(ret);
+
+ assert_cc(sizeof(struct nd_opt_home_agent_info) % 8 == 0);
+
+ _cleanup_free_ struct nd_opt_home_agent_info *buf = new(struct nd_opt_home_agent_info, 1);
+ if (!buf)
+ return -ENOMEM;
+
+ *buf = (struct nd_opt_home_agent_info) {
+ .nd_opt_home_agent_info_type = SD_NDISC_OPTION_HOME_AGENT,
+ .nd_opt_home_agent_info_len = sizeof(struct nd_opt_home_agent_info) / 8,
+ .nd_opt_home_agent_info_preference = htobe16(option->home_agent.preference),
+ .nd_opt_home_agent_info_lifetime = usec_to_be16_sec(option->home_agent.lifetime),
+ };
+
+ *ret = (uint8_t*) TAKE_PTR(buf);
+ return 0;
+}
+
int ndisc_option_add_route(
Set **options,
size_t offset,
@@ -1121,6 +1179,10 @@ int ndisc_parse_options(ICMP6Packet *packet, Set **ret_options) {
r = ndisc_option_parse_mtu(&options, offset, length, opt);
break;
+ case SD_NDISC_OPTION_HOME_AGENT:
+ r = ndisc_option_parse_home_agent(&options, offset, length, opt);
+ break;
+
case SD_NDISC_OPTION_ROUTE_INFORMATION:
r = ndisc_option_parse_route(&options, offset, length, opt);
break;
@@ -1228,6 +1290,10 @@ int ndisc_send(int fd, const struct sockaddr_in6 *dst, const struct icmp6_hdr *h
r = ndisc_option_build_mtu(option, &buf);
break;
+ case SD_NDISC_OPTION_HOME_AGENT:
+ r = ndisc_option_build_home_agent(option, &buf);
+ break;
+
case SD_NDISC_OPTION_ROUTE_INFORMATION:
r = ndisc_option_build_route(option, &buf);
break;
diff --git a/src/libsystemd-network/ndisc-option.h b/src/libsystemd-network/ndisc-option.h
index 7e7a702b80..3bf29af0c9 100644
--- a/src/libsystemd-network/ndisc-option.h
+++ b/src/libsystemd-network/ndisc-option.h
@@ -29,6 +29,11 @@ typedef struct sd_ndisc_prefix {
usec_t preferred_lifetime;
} sd_ndisc_prefix;
+typedef struct sd_ndisc_home_agent {
+ uint16_t preference;
+ usec_t lifetime;
+} sd_ndisc_home_agent;
+
typedef struct sd_ndisc_route {
uint8_t preference;
uint8_t prefixlen;
@@ -58,17 +63,18 @@ typedef struct sd_ndisc_option {
size_t offset;
union {
- sd_ndisc_raw raw; /* for testing or unsupported options */
- struct ether_addr mac; /* SD_NDISC_OPTION_SOURCE_LL_ADDRESS or SD_NDISC_OPTION_TARGET_LL_ADDRESS */
- sd_ndisc_prefix prefix; /* SD_NDISC_OPTION_PREFIX_INFORMATION */
- struct ip6_hdr hdr; /* SD_NDISC_OPTION_REDIRECTED_HEADER */
- uint32_t mtu; /* SD_NDISC_OPTION_MTU */
- sd_ndisc_route route; /* SD_NDISC_OPTION_ROUTE_INFORMATION */
- sd_ndisc_rdnss rdnss; /* SD_NDISC_OPTION_RDNSS */
- uint64_t extended_flags; /* SD_NDISC_OPTION_FLAGS_EXTENSION */
- sd_ndisc_dnssl dnssl; /* SD_NDISC_OPTION_DNSSL */
- char *captive_portal; /* SD_NDISC_OPTION_CAPTIVE_PORTAL */
- sd_ndisc_prefix64 prefix64; /* SD_NDISC_OPTION_PREF64 */
+ sd_ndisc_raw raw; /* for testing or unsupported options */
+ struct ether_addr mac; /* SD_NDISC_OPTION_SOURCE_LL_ADDRESS or SD_NDISC_OPTION_TARGET_LL_ADDRESS */
+ sd_ndisc_prefix prefix; /* SD_NDISC_OPTION_PREFIX_INFORMATION */
+ struct ip6_hdr hdr; /* SD_NDISC_OPTION_REDIRECTED_HEADER */
+ uint32_t mtu; /* SD_NDISC_OPTION_MTU */
+ sd_ndisc_home_agent home_agent; /* SD_NDISC_OPTION_HOME_AGENT */
+ sd_ndisc_route route; /* SD_NDISC_OPTION_ROUTE_INFORMATION */
+ sd_ndisc_rdnss rdnss; /* SD_NDISC_OPTION_RDNSS */
+ uint64_t extended_flags; /* SD_NDISC_OPTION_FLAGS_EXTENSION */
+ sd_ndisc_dnssl dnssl; /* SD_NDISC_OPTION_DNSSL */
+ char *captive_portal; /* SD_NDISC_OPTION_CAPTIVE_PORTAL */
+ sd_ndisc_prefix64 prefix64; /* SD_NDISC_OPTION_PREF64 */
};
} sd_ndisc_option;
@@ -150,6 +156,11 @@ int ndisc_option_add_mtu(
Set **options,
size_t offset,
uint32_t mtu);
+int ndisc_option_add_home_agent(
+ Set **options,
+ size_t offset,
+ uint16_t preference,
+ usec_t lifetime);
int ndisc_option_add_route(
Set **options,
size_t offset,