Re: [systemd-devel] [PATCH 07/11] sd-icmp6-nd: Parse ICMPv6 prefix information

2015-01-13 Thread Zbigniew Jędrzejewski-Szmek
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

2015-01-13 Thread Patrik Flykt
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);