summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/dhcpv6-ia.c7
-rw-r--r--src/ndp.c31
-rw-r--r--src/odhcpd.c30
-rw-r--r--src/odhcpd.h3
-rw-r--r--src/router.c13
5 files changed, 44 insertions, 40 deletions
diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c
index 4d68258..cca6664 100644
--- a/src/dhcpv6-ia.c
+++ b/src/dhcpv6-ia.c
@@ -233,7 +233,7 @@ void dhcpv6_write_statefile(void)
struct in6_addr addr;
for (size_t i = 0; i < iface->ia_addr_len; ++i) {
- if (iface->ia_addr[i].prefix > 64)
+ if (iface->ia_addr[i].prefix > 96)
continue;
addr = iface->ia_addr[i].addr;
@@ -451,7 +451,6 @@ static void update(struct interface *iface)
if (addr[i].prefix > minprefix)
minprefix = addr[i].prefix;
- addr[i].addr.s6_addr32[2] = 0;
addr[i].addr.s6_addr32[3] = 0;
if (addr[i].preferred < UINT32_MAX - now)
@@ -604,7 +603,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
uint32_t prefix_pref = iface->ia_addr[i].preferred - now;
uint32_t prefix_valid = iface->ia_addr[i].valid - now;
- if (iface->ia_addr[i].prefix > 64 ||
+ if (iface->ia_addr[i].prefix > 96 ||
iface->ia_addr[i].preferred <= (uint32_t)now)
continue;
@@ -712,7 +711,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
bool found = false;
if (a) {
for (size_t i = 0; i < iface->ia_addr_len; ++i) {
- if (iface->ia_addr[i].prefix > 64 ||
+ if (iface->ia_addr[i].prefix > 96 ||
iface->ia_addr[i].preferred <= (uint32_t)now)
continue;
diff --git a/src/ndp.c b/src/ndp.c
index 02c2dbd..6d18bb5 100644
--- a/src/ndp.c
+++ b/src/ndp.c
@@ -364,41 +364,12 @@ static void free_neighbor(struct ndp_neighbor *n)
--neighbor_count;
}
-
-static bool match_neighbor(struct ndp_neighbor *n, struct in6_addr *addr)
-{
- if (n->len <= 32)
- return ntohl(n->addr.s6_addr32[0]) >> (32 - n->len) ==
- ntohl(addr->s6_addr32[0]) >> (32 - n->len);
-
- if (n->addr.s6_addr32[0] != addr->s6_addr32[0])
- return false;
-
- if (n->len <= 64)
- return ntohl(n->addr.s6_addr32[1]) >> (64 - n->len) ==
- ntohl(addr->s6_addr32[1]) >> (64 - n->len);
-
- if (n->addr.s6_addr32[1] != addr->s6_addr32[1])
- return false;
-
- if (n->len <= 96)
- return ntohl(n->addr.s6_addr32[2]) >> (96 - n->len) ==
- ntohl(addr->s6_addr32[2]) >> (96 - n->len);
-
- if (n->addr.s6_addr32[2] != addr->s6_addr32[2])
- return false;
-
- return ntohl(n->addr.s6_addr32[3]) >> (128 - n->len) ==
- ntohl(addr->s6_addr32[3]) >> (128 - n->len);
-}
-
-
static struct ndp_neighbor* find_neighbor(struct in6_addr *addr, bool strict)
{
time_t now = time(NULL);
struct ndp_neighbor *n, *e;
list_for_each_entry_safe(n, e, &neighbors, head) {
- if ((!strict && match_neighbor(n, addr)) ||
+ if ((!strict && !odhcpd_bmemcmp(&n->addr, addr, n->len)) ||
(n->len == 128 && IN6_ARE_ADDR_EQUAL(&n->addr, addr)))
return n;
diff --git a/src/odhcpd.c b/src/odhcpd.c
index f40cea0..25a6047 100644
--- a/src/odhcpd.c
+++ b/src/odhcpd.c
@@ -427,3 +427,33 @@ void odhcpd_hexlify(char *dst, const uint8_t *src, size_t len)
}
*dst = 0;
}
+
+
+int odhcpd_bmemcmp(const void *av, const void *bv, size_t bits)
+{
+ const uint8_t *a = av, *b = bv;
+ size_t bytes = bits / 8;
+ bits %= 8;
+
+ int res = memcmp(a, b, bytes);
+ if (res == 0 && bits > 0)
+ res = (a[bytes] >> (8 - bits)) - (b[bytes] >> (8 - bits));
+
+ return res;
+}
+
+
+void odhcpd_bmemcpy(void *av, const void *bv, size_t bits)
+{
+ uint8_t *a = av;
+ const uint8_t *b = bv;
+
+ size_t bytes = bits / 8;
+ bits %= 8;
+ memcpy(a, b, bytes);
+
+ if (bits > 0) {
+ uint8_t mask = (1 << (8 - bits)) - 1;
+ a[bytes] = (a[bytes] & mask) | ((~mask) & b[bytes]);
+ }
+}
diff --git a/src/odhcpd.h b/src/odhcpd.h
index 789f696..010cd9e 100644
--- a/src/odhcpd.h
+++ b/src/odhcpd.h
@@ -188,6 +188,9 @@ time_t odhcpd_time(void);
ssize_t odhcpd_unhexlify(uint8_t *dst, size_t len, const char *src);
void odhcpd_hexlify(char *dst, const uint8_t *src, size_t len);
+int odhcpd_bmemcmp(const void *av, const void *bv, size_t bits);
+void odhcpd_bmemcpy(void *av, const void *bv, size_t bits);
+
int config_parse_interface(void *data, size_t len, const char *iname, bool overwrite);
#ifdef WITH_UBUS
diff --git a/src/router.c b/src/router.c
index 372c400..907011a 100644
--- a/src/router.c
+++ b/src/router.c
@@ -296,7 +296,7 @@ static void send_router_advert(struct uloop_timeout *event)
for (ssize_t i = 0; i < ipcnt; ++i) {
struct odhcpd_ipaddr *addr = &addrs[i];
- if (addr->prefix > 64 || addr->has_class)
+ if (addr->prefix > 96 || addr->has_class)
continue; // Address not suitable
if (addr->preferred > MaxPreferredTime)
@@ -307,8 +307,9 @@ static void send_router_advert(struct uloop_timeout *event)
struct nd_opt_prefix_info *p = NULL;
for (size_t i = 0; i < cnt; ++i) {
- if (!memcmp(&adv.prefix[i].nd_opt_pi_prefix,
- &addr->addr, 8))
+ if (addr->prefix == adv.prefix[i].nd_opt_pi_prefix_len &&
+ !odhcpd_bmemcmp(&adv.prefix[i].nd_opt_pi_prefix,
+ &addr->addr, addr->prefix))
p = &adv.prefix[i];
}
@@ -326,14 +327,14 @@ static void send_router_advert(struct uloop_timeout *event)
maxpreferred = 1000 * addr->preferred;
}
- memcpy(&p->nd_opt_pi_prefix, &addr->addr, 8);
+ odhcpd_bmemcpy(&p->nd_opt_pi_prefix, &addr->addr, addr->prefix);
p->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
p->nd_opt_pi_len = 4;
- p->nd_opt_pi_prefix_len = 64;
+ p->nd_opt_pi_prefix_len = (addr->prefix < 64) ? 64 : addr->prefix;
p->nd_opt_pi_flags_reserved = 0;
if (!iface->ra_not_onlink)
p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
- if (iface->managed < RELAYD_MANAGED_NO_AFLAG)
+ if (iface->managed < RELAYD_MANAGED_NO_AFLAG && addr->prefix <= 64)
p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
p->nd_opt_pi_valid_time = htonl(addr->valid);
p->nd_opt_pi_preferred_time = htonl(addr->preferred);