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;
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)
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;
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;
--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;
}
*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]);
+ }
+}
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
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)
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];
}
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);