summaryrefslogtreecommitdiffstats
path: root/src/libsystemd-network/ndisc-option.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-network/ndisc-option.h')
-rw-r--r--src/libsystemd-network/ndisc-option.h330
1 files changed, 330 insertions, 0 deletions
diff --git a/src/libsystemd-network/ndisc-option.h b/src/libsystemd-network/ndisc-option.h
new file mode 100644
index 0000000..d7bd861
--- /dev/null
+++ b/src/libsystemd-network/ndisc-option.h
@@ -0,0 +1,330 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <inttypes.h>
+#include <net/ethernet.h>
+#include <netinet/icmp6.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <sys/uio.h>
+
+#include "sd-ndisc-protocol.h"
+
+#include "icmp6-packet.h"
+#include "macro.h"
+#include "set.h"
+#include "time-util.h"
+
+typedef struct sd_ndisc_raw {
+ uint8_t *bytes;
+ size_t length;
+} sd_ndisc_raw;
+
+/* Mostly equivalent to struct nd_opt_prefix_info, but using usec_t. */
+typedef struct sd_ndisc_prefix {
+ uint8_t flags;
+ uint8_t prefixlen;
+ struct in6_addr address;
+ usec_t valid_lifetime;
+ usec_t preferred_lifetime;
+ /* timestamp in CLOCK_BOOTTIME, used when sending option for adjusting lifetime. */
+ usec_t valid_until;
+ usec_t preferred_until;
+} sd_ndisc_prefix;
+
+typedef struct sd_ndisc_home_agent {
+ uint16_t preference;
+ usec_t lifetime;
+ usec_t valid_until;
+} sd_ndisc_home_agent;
+
+typedef struct sd_ndisc_route {
+ uint8_t preference;
+ uint8_t prefixlen;
+ struct in6_addr address;
+ usec_t lifetime;
+ usec_t valid_until;
+} sd_ndisc_route;
+
+typedef struct sd_ndisc_rdnss {
+ size_t n_addresses;
+ struct in6_addr *addresses;
+ usec_t lifetime;
+ usec_t valid_until;
+} sd_ndisc_rdnss;
+
+typedef struct sd_ndisc_dnssl {
+ char **domains;
+ usec_t lifetime;
+ usec_t valid_until;
+} sd_ndisc_dnssl;
+
+typedef struct sd_ndisc_prefix64 {
+ uint8_t prefixlen;
+ struct in6_addr prefix;
+ usec_t lifetime;
+ usec_t valid_until;
+} sd_ndisc_prefix64;
+
+typedef struct sd_ndisc_option {
+ uint8_t type;
+ 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_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;
+
+/* RFC 8781: PREF64 or (NAT64 prefix) */
+#define PREF64_SCALED_LIFETIME_MASK 0xfff8
+#define PREF64_PLC_MASK 0x0007
+#define PREF64_MAX_LIFETIME_USEC (65528 * USEC_PER_SEC)
+
+typedef enum PrefixLengthCode {
+ PREFIX_LENGTH_CODE_96,
+ PREFIX_LENGTH_CODE_64,
+ PREFIX_LENGTH_CODE_56,
+ PREFIX_LENGTH_CODE_48,
+ PREFIX_LENGTH_CODE_40,
+ PREFIX_LENGTH_CODE_32,
+ _PREFIX_LENGTH_CODE_MAX,
+ _PREFIX_LENGTH_CODE_INVALID = -EINVAL,
+} PrefixLengthCode;
+
+/* rfc8781: section 4 - Scaled Lifetime: 13-bit unsigned integer. PREFIX_LEN (Prefix Length Code): 3-bit unsigned integer */
+struct nd_opt_prefix64_info {
+ uint8_t type;
+ uint8_t length;
+ uint16_t lifetime_and_plc;
+ uint8_t prefix[12];
+} _packed_;
+
+int pref64_prefix_length_to_plc(uint8_t prefixlen, uint8_t *ret);
+
+sd_ndisc_option* ndisc_option_free(sd_ndisc_option *option);
+
+int ndisc_option_parse(
+ ICMP6Packet *p,
+ size_t offset,
+ uint8_t *ret_type,
+ size_t *ret_len,
+ const uint8_t **ret_opt);
+
+int ndisc_parse_options(ICMP6Packet *p, Set **ret_options);
+
+static inline sd_ndisc_option* ndisc_option_get(Set *options, const sd_ndisc_option *p) {
+ return set_get(options, ASSERT_PTR(p));
+}
+static inline sd_ndisc_option* ndisc_option_get_by_type(Set *options, uint8_t type) {
+ return ndisc_option_get(options, &(const sd_ndisc_option) { .type = type });
+}
+int ndisc_option_get_mac(Set *options, uint8_t type, struct ether_addr *ret);
+
+static inline void ndisc_option_remove(Set *options, const sd_ndisc_option *p) {
+ ndisc_option_free(set_remove(options, ASSERT_PTR(p)));
+}
+static inline void ndisc_option_remove_by_type(Set *options, uint8_t type) {
+ ndisc_option_remove(options, &(const sd_ndisc_option) { .type = type });
+}
+
+int ndisc_option_set_raw(
+ Set **options,
+ size_t length,
+ const uint8_t *bytes);
+int ndisc_option_add_link_layer_address(
+ Set **options,
+ uint8_t type,
+ size_t offset,
+ const struct ether_addr *mac);
+static inline int ndisc_option_set_link_layer_address(
+ Set **options,
+ uint8_t type,
+ const struct ether_addr *mac) {
+ return ndisc_option_add_link_layer_address(options, type, 0, mac);
+}
+int ndisc_option_add_prefix_internal(
+ Set **options,
+ size_t offset,
+ uint8_t flags,
+ uint8_t prefixlen,
+ const struct in6_addr *address,
+ usec_t valid_lifetime,
+ usec_t preferred_lifetime,
+ usec_t valid_until,
+ usec_t preferred_until);
+static inline int ndisc_option_add_prefix(
+ Set **options,
+ size_t offset,
+ uint8_t flags,
+ uint8_t prefixlen,
+ const struct in6_addr *address,
+ usec_t valid_lifetime,
+ usec_t preferred_lifetime) {
+ return ndisc_option_add_prefix_internal(options, offset, flags, prefixlen, address,
+ valid_lifetime, preferred_lifetime,
+ USEC_INFINITY, USEC_INFINITY);
+}
+static inline int ndisc_option_set_prefix(
+ Set **options,
+ uint8_t flags,
+ uint8_t prefixlen,
+ const struct in6_addr *address,
+ usec_t valid_lifetime,
+ usec_t preferred_lifetime,
+ usec_t valid_until,
+ usec_t preferred_until) {
+ return ndisc_option_add_prefix_internal(options, 0, flags, prefixlen, address,
+ valid_lifetime, preferred_lifetime,
+ valid_until, preferred_until);
+}
+int ndisc_option_add_redirected_header(
+ Set **options,
+ size_t offset,
+ const struct ip6_hdr *hdr);
+int ndisc_option_add_mtu(
+ Set **options,
+ size_t offset,
+ uint32_t mtu);
+static inline int ndisc_option_set_mtu(
+ Set **options,
+ uint32_t mtu) {
+ return ndisc_option_add_mtu(options, 0, mtu);
+}
+int ndisc_option_add_home_agent_internal(
+ Set **options,
+ size_t offset,
+ uint16_t preference,
+ usec_t lifetime,
+ usec_t valid_until);
+static inline int ndisc_option_add_home_agent(
+ Set **options,
+ size_t offset,
+ uint16_t preference,
+ usec_t lifetime) {
+ return ndisc_option_add_home_agent_internal(options, offset, preference, lifetime, USEC_INFINITY);
+}
+static inline int ndisc_option_set_home_agent(
+ Set **options,
+ uint16_t preference,
+ usec_t lifetime,
+ usec_t valid_until) {
+ return ndisc_option_add_home_agent_internal(options, 0, preference, lifetime, valid_until);
+}
+int ndisc_option_add_route_internal(
+ Set **options,
+ size_t offset,
+ uint8_t preference,
+ uint8_t prefixlen,
+ const struct in6_addr *prefix,
+ usec_t lifetime,
+ usec_t valid_until);
+static inline int ndisc_option_add_route(
+ Set **options,
+ size_t offset,
+ uint8_t preference,
+ uint8_t prefixlen,
+ const struct in6_addr *prefix,
+ usec_t lifetime) {
+ return ndisc_option_add_route_internal(options, offset, preference, prefixlen, prefix, lifetime, USEC_INFINITY);
+}
+static inline int ndisc_option_set_route(
+ Set **options,
+ uint8_t preference,
+ uint8_t prefixlen,
+ const struct in6_addr *prefix,
+ usec_t lifetime,
+ usec_t valid_until) {
+ return ndisc_option_add_route_internal(options, 0, preference, prefixlen, prefix, lifetime, valid_until);
+}
+int ndisc_option_add_rdnss_internal(
+ Set **options,
+ size_t offset,
+ size_t n_addresses,
+ const struct in6_addr *addresses,
+ usec_t lifetime,
+ usec_t valid_until);
+static inline int ndisc_option_add_rdnss(
+ Set **options,
+ size_t offset,
+ size_t n_addresses,
+ const struct in6_addr *addresses,
+ usec_t lifetime) {
+ return ndisc_option_add_rdnss_internal(options, offset, n_addresses, addresses, lifetime, USEC_INFINITY);
+}
+static inline int ndisc_option_set_rdnss(
+ Set **options,
+ size_t n_addresses,
+ const struct in6_addr *addresses,
+ usec_t lifetime,
+ usec_t valid_until) {
+ return ndisc_option_add_rdnss_internal(options, 0, n_addresses, addresses, lifetime, valid_until);
+}
+int ndisc_option_add_flags_extension(
+ Set **options,
+ size_t offset,
+ uint64_t flags);
+int ndisc_option_add_dnssl_internal(
+ Set **options,
+ size_t offset,
+ char * const *domains,
+ usec_t lifetime,
+ usec_t valid_until);
+static inline int ndisc_option_add_dnssl(
+ Set **options,
+ size_t offset,
+ char * const *domains,
+ usec_t lifetime) {
+ return ndisc_option_add_dnssl_internal(options, offset, domains, lifetime, USEC_INFINITY);
+}
+static inline int ndisc_option_set_dnssl(
+ Set **options,
+ char * const *domains,
+ usec_t lifetime,
+ usec_t valid_until) {
+ return ndisc_option_add_dnssl_internal(options, 0, domains, lifetime, valid_until);
+}
+int ndisc_option_add_captive_portal(
+ Set **options,
+ size_t offset,
+ const char *portal);
+static inline int ndisc_option_set_captive_portal(
+ Set **options,
+ const char *portal) {
+ return ndisc_option_add_captive_portal(options, 0, portal);
+}
+int ndisc_option_add_prefix64_internal(
+ Set **options,
+ size_t offset,
+ uint8_t prefixlen,
+ const struct in6_addr *prefix,
+ usec_t lifetime,
+ usec_t valid_until);
+static inline int ndisc_option_add_prefix64(
+ Set **options,
+ size_t offset,
+ uint8_t prefixlen,
+ const struct in6_addr *prefix,
+ usec_t lifetime) {
+ return ndisc_option_add_prefix64_internal(options, offset, prefixlen, prefix, lifetime, USEC_INFINITY);
+}
+static inline int ndisc_option_set_prefix64(
+ Set **options,
+ uint8_t prefixlen,
+ const struct in6_addr *prefix,
+ usec_t lifetime,
+ usec_t valid_until) {
+ return ndisc_option_add_prefix64_internal(options, 0, prefixlen, prefix, lifetime, valid_until);
+}
+
+int ndisc_send(int fd, const struct in6_addr *dst, const struct icmp6_hdr *hdr, Set *options, usec_t timestamp);