Re: [systemd-devel] [PATCH 07/11] sd-icmp6-nd: Parse ICMPv6 prefix information
On Tue, Jan 13, 2015 at 02:02:17PM +0200, Patrik Flykt wrote: Save each new onlink IPv6 prefix and attach an expiry timer to it. If the prefixes overlap, take the shorter prefix and write a debug message about the event. Once the prefix is resent in a Router Advertisement, update the timer. Add a new event for the expiring prefix. Add two helper functions, one for returning a prefix length given a Router Advertisement and the other for generic prefix matching given an IPv6 prefix and address. --- src/libsystemd-network/sd-icmp6-nd.c | 222 +++ src/systemd/sd-icmp6-nd.h| 6 + 2 files changed, 228 insertions(+) diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-icmp6-nd.c index 3501055..4848912 100644 --- a/src/libsystemd-network/sd-icmp6-nd.c +++ b/src/libsystemd-network/sd-icmp6-nd.c @@ -283,11 +283,227 @@ int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu) { return 0; } +static int icmp6_ra_prefix_timeout(sd_event_source *s, uint64_t usec, +void *userdata) { Indentation, here and below too. +sd_icmp6_nd *nd = userdata; +struct icmp6_prefix *prefix, *p; + +assert(nd); +assert(nd-link); +assert(nd-link-prefixes); + +LIST_FOREACH_SAFE(prefixes, prefix, p, nd-link-prefixes) { +if (prefix-timeout_valid != s) +continue; + +log_icmp6_nd(nd, Prefix expired %02x%02x:%02x%02x:%02x%02x:%02x%02x/%d, +prefix-addr.s6_addr[0], prefix-addr.s6_addr[1], +prefix-addr.s6_addr[2], prefix-addr.s6_addr[3], +prefix-addr.s6_addr[4], prefix-addr.s6_addr[5], +prefix-addr.s6_addr[6], prefix-addr.s6_addr[7], +prefix-len); + +LIST_REMOVE(prefixes, nd-link-prefixes, prefix); + +icmp6_nd_notify(nd, + ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED); +prefix = icmp6_prefix_unref(prefix); + +break; +} + +return 0; +} + +static int icmp6_ra_prefix_set_timeout(sd_icmp6_nd *nd, +struct icmp6_prefix *prefix, usec_t valid) { +usec_t time_now; +int r; + +assert_return(prefix, -EINVAL); + +r = sd_event_now(nd-event, clock_boottime_or_monotonic(), time_now); +if (r 0) +return r; + +prefix-timeout_valid = sd_event_source_unref(prefix-timeout_valid); + +r = sd_event_add_time(nd-event, prefix-timeout_valid, +clock_boottime_or_monotonic(), time_now + valid, +USEC_PER_SEC, icmp6_ra_prefix_timeout, nd); +if (r 0) +goto error; + +r = sd_event_source_set_priority(prefix-timeout_valid, +nd-event_priority); +if (r 0) +goto error; + +r = sd_event_source_set_description(prefix-timeout_valid, +icmp6-prefix-timeout); + +error: +if (r 0) +prefix-timeout_valid = +sd_event_source_unref(prefix-timeout_valid); + +return r; +} + +static int icmp6_prefix_match(const struct in6_addr *prefix, uint8_t prefixlen, +const struct in6_addr *addr, uint8_t addr_prefixlen) { +uint8_t bytes, mask, len; + +assert_return(prefix, -EINVAL); +assert_return(addr, -EINVAL); + +len = (prefixlen addr_prefixlen)? prefixlen: addr_prefixlen; MIN() + +bytes = len / 8; + +if (memcmp(prefix, addr, bytes)) +return -EADDRNOTAVAIL; + +if (len % 8) { I guess you can just remove the if() and say mask = 0xff (8 - len % 8); if (memcmp(prefix, addr, bytes) != 0 || (prefix-s6_addr[bytes] mask) != (addr-s6_addr[bytes] mask)) return ...; + + +if ((prefix-s6_addr[bytes] mask) != +(addr-s6_addr[bytes] mask)) +return -EADDRNOTAVAIL; +} + +return 0; +} + +static int icmp6_ra_prefix_match(struct icmp6_prefix *head, +const struct in6_addr *addr, uint8_t addr_len, +struct icmp6_prefix **result) { +struct icmp6_prefix *prefix; + +LIST_FOREACH(prefixes, prefix, head) { +if (icmp6_prefix_match(prefix-addr, prefix-len, addr, +addr_len) = 0) { +*result = prefix; +return 0; +} +} + +return -EADDRNOTAVAIL; +} + +int sd_icmp6_prefix_match(struct in6_addr
[systemd-devel] [PATCH 07/11] sd-icmp6-nd: Parse ICMPv6 prefix information
Save each new onlink IPv6 prefix and attach an expiry timer to it. If the prefixes overlap, take the shorter prefix and write a debug message about the event. Once the prefix is resent in a Router Advertisement, update the timer. Add a new event for the expiring prefix. Add two helper functions, one for returning a prefix length given a Router Advertisement and the other for generic prefix matching given an IPv6 prefix and address. --- src/libsystemd-network/sd-icmp6-nd.c | 222 +++ src/systemd/sd-icmp6-nd.h| 6 + 2 files changed, 228 insertions(+) diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-icmp6-nd.c index 3501055..4848912 100644 --- a/src/libsystemd-network/sd-icmp6-nd.c +++ b/src/libsystemd-network/sd-icmp6-nd.c @@ -283,11 +283,227 @@ int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu) { return 0; } +static int icmp6_ra_prefix_timeout(sd_event_source *s, uint64_t usec, +void *userdata) { +sd_icmp6_nd *nd = userdata; +struct icmp6_prefix *prefix, *p; + +assert(nd); +assert(nd-link); +assert(nd-link-prefixes); + +LIST_FOREACH_SAFE(prefixes, prefix, p, nd-link-prefixes) { +if (prefix-timeout_valid != s) +continue; + +log_icmp6_nd(nd, Prefix expired %02x%02x:%02x%02x:%02x%02x:%02x%02x/%d, +prefix-addr.s6_addr[0], prefix-addr.s6_addr[1], +prefix-addr.s6_addr[2], prefix-addr.s6_addr[3], +prefix-addr.s6_addr[4], prefix-addr.s6_addr[5], +prefix-addr.s6_addr[6], prefix-addr.s6_addr[7], +prefix-len); + +LIST_REMOVE(prefixes, nd-link-prefixes, prefix); + +icmp6_nd_notify(nd, + ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED); +prefix = icmp6_prefix_unref(prefix); + +break; +} + +return 0; +} + +static int icmp6_ra_prefix_set_timeout(sd_icmp6_nd *nd, +struct icmp6_prefix *prefix, usec_t valid) { +usec_t time_now; +int r; + +assert_return(prefix, -EINVAL); + +r = sd_event_now(nd-event, clock_boottime_or_monotonic(), time_now); +if (r 0) +return r; + +prefix-timeout_valid = sd_event_source_unref(prefix-timeout_valid); + +r = sd_event_add_time(nd-event, prefix-timeout_valid, +clock_boottime_or_monotonic(), time_now + valid, +USEC_PER_SEC, icmp6_ra_prefix_timeout, nd); +if (r 0) +goto error; + +r = sd_event_source_set_priority(prefix-timeout_valid, +nd-event_priority); +if (r 0) +goto error; + +r = sd_event_source_set_description(prefix-timeout_valid, +icmp6-prefix-timeout); + +error: +if (r 0) +prefix-timeout_valid = +sd_event_source_unref(prefix-timeout_valid); + +return r; +} + +static int icmp6_prefix_match(const struct in6_addr *prefix, uint8_t prefixlen, +const struct in6_addr *addr, uint8_t addr_prefixlen) { +uint8_t bytes, mask, len; + +assert_return(prefix, -EINVAL); +assert_return(addr, -EINVAL); + +len = (prefixlen addr_prefixlen)? prefixlen: addr_prefixlen; + +bytes = len / 8; + +if (memcmp(prefix, addr, bytes)) +return -EADDRNOTAVAIL; + +if (len % 8) { +mask = 0xff (8 - len % 8); + +if ((prefix-s6_addr[bytes] mask) != +(addr-s6_addr[bytes] mask)) +return -EADDRNOTAVAIL; +} + +return 0; +} + +static int icmp6_ra_prefix_match(struct icmp6_prefix *head, +const struct in6_addr *addr, uint8_t addr_len, +struct icmp6_prefix **result) { +struct icmp6_prefix *prefix; + +LIST_FOREACH(prefixes, prefix, head) { +if (icmp6_prefix_match(prefix-addr, prefix-len, addr, +addr_len) = 0) { +*result = prefix; +return 0; +} +} + +return -EADDRNOTAVAIL; +} + +int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen, +struct in6_addr *addr) { +return icmp6_prefix_match(prefix, prefixlen, addr, +sizeof(addr-s6_addr) * 8); +} + +int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr, +uint8_t *prefixlen) { +int r; +struct icmp6_prefix *prefix; + +assert_return(nd, -EINVAL);