diff options
-rw-r--r-- | src/libsystemd-network/ndisc-option.c | 66 | ||||
-rw-r--r-- | src/libsystemd-network/ndisc-option.h | 33 |
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, |