summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Härdeman2024-02-10 02:35:04 +0000
committerdedeckeh2024-12-30 19:44:26 +0000
commit5585b969c18f84bd3bb7d02a0034c19ebae79e79 (patch)
treec9d7ec430d93e337b242763b172d01c258784530
parent171140e90b6a6a8e0c9e8e12dc5cbd4cbe972bef (diff)
downloadodhcpd-5585b969c18f84bd3bb7d02a0034c19ebae79e79.tar.gz
router: move pref64 calculations to the config stage
If pref64 is misconfigured, it'll print a LOG_WARNING message every time a RA is generated, which seems a bit excessive. When fixing that, I noticed that all work is done for every RA, so I ended up moving the gist over to the config stage where it is done once. Signed-off-by: David Härdeman <david@hardeman.nu>
-rw-r--r--src/config.c46
-rw-r--r--src/odhcpd.h3
-rw-r--r--src/router.c50
3 files changed, 48 insertions, 51 deletions
diff --git a/src/config.c b/src/config.c
index e816f4b..4e1493f 100644
--- a/src/config.c
+++ b/src/config.c
@@ -1314,10 +1314,50 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
}
}
- if ((c = tb[IFACE_ATTR_RA_PREF64]))
+ if ((c = tb[IFACE_ATTR_RA_PREF64])) {
+ struct in6_addr addr;
+
odhcpd_parse_addr6_prefix(blobmsg_get_string(c),
- &iface->pref64_addr,
- &iface->pref64_length);
+ &addr, &iface->pref64_length);
+
+ iface->pref64_prefix[0] = addr.s6_addr32[0];
+ switch (iface->pref64_length) {
+ case 96:
+ iface->pref64_plc = 0;
+ iface->pref64_prefix[1] = addr.s6_addr32[1];
+ iface->pref64_prefix[2] = addr.s6_addr32[2];
+ break;
+ case 64:
+ iface->pref64_plc = 1;
+ iface->pref64_prefix[1] = addr.s6_addr32[1];
+ iface->pref64_prefix[2] = 0;
+ break;
+ case 56:
+ iface->pref64_plc = 2;
+ iface->pref64_prefix[1] = addr.s6_addr32[1] & htonl(0xffffff00);
+ iface->pref64_prefix[2] = 0;
+ break;
+ case 48:
+ iface->pref64_plc = 3;
+ iface->pref64_prefix[1] = addr.s6_addr32[1] & htonl(0xffff0000);
+ iface->pref64_prefix[2] = 0;
+ break;
+ case 40:
+ iface->pref64_plc = 4;
+ iface->pref64_prefix[1] = addr.s6_addr32[1] & htonl(0xff000000);
+ iface->pref64_prefix[2] = 0;
+ break;
+ case 32:
+ iface->pref64_plc = 5;
+ iface->pref64_prefix[1] = 0;
+ iface->pref64_prefix[2] = 0;
+ break;
+ default:
+ syslog(LOG_WARNING, "Invalid PREF64 prefix size (%d), "
+ "ignoring ra_pref64 option!", iface->pref64_length);
+ iface->pref64_length = 0;
+ }
+ }
if ((c = tb[IFACE_ATTR_RA_PREFERENCE])) {
const char *prio = blobmsg_get_string(c);
diff --git a/src/odhcpd.h b/src/odhcpd.h
index 61fb64c..779f50f 100644
--- a/src/odhcpd.h
+++ b/src/odhcpd.h
@@ -330,7 +330,8 @@ struct interface {
bool ra_useleasetime;
bool ra_dns;
uint8_t pref64_length;
- struct in6_addr pref64_addr;
+ uint8_t pref64_plc;
+ uint32_t pref64_prefix[3];
bool no_dynamic_dhcp;
bool have_link_local;
uint8_t pio_filter_length;
diff --git a/src/router.c b/src/router.c
index b630953..2443078 100644
--- a/src/router.c
+++ b/src/router.c
@@ -438,7 +438,7 @@ struct nd_opt_pref64_info {
uint8_t type;
uint8_t len;
uint16_t lifetime_plc;
- uint32_t addr[3];
+ uint32_t prefix[3];
};
struct nd_opt_dnr_info {
@@ -742,59 +742,15 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr
if (iface->pref64_length) {
/* RFC 8781 § 4.1 rounding up lifetime to multiple of 8 */
uint16_t pref64_lifetime = lifetime < (UINT16_MAX - 7) ? lifetime + 7 : UINT16_MAX;
- uint8_t prefix_length_code;
- uint32_t mask_a1, mask_a2;
-
- switch (iface->pref64_length) {
- case 96:
- prefix_length_code = 0;
- mask_a1 = 0xffffffff;
- mask_a2 = 0xffffffff;
- break;
- case 64:
- prefix_length_code = 1;
- mask_a1 = 0xffffffff;
- mask_a2 = 0x00000000;
- break;
- case 56:
- prefix_length_code = 2;
- mask_a1 = 0xffffff00;
- mask_a2 = 0x00000000;
- break;
- case 48:
- prefix_length_code = 3;
- mask_a1 = 0xffff0000;
- mask_a2 = 0x00000000;
- break;
- case 40:
- prefix_length_code = 4;
- mask_a1 = 0xff000000;
- mask_a2 = 0x00000000;
- break;
- case 32:
- prefix_length_code = 5;
- mask_a1 = 0x00000000;
- mask_a2 = 0x00000000;
- break;
- default:
- syslog(LOG_WARNING, "Invalid PREF64 prefix size (%d), "
- "ignoring ra_pref64 option!", iface->pref64_length);
- goto pref64_out;
- break;
- }
pref64_sz = sizeof(*pref64);
pref64 = alloca(pref64_sz);
- memset(pref64, 0, pref64_sz);
pref64->type = ND_OPT_PREF64;
pref64->len = 2;
pref64->lifetime_plc = htons((0xfff8 & pref64_lifetime) |
- (0x7 & prefix_length_code));
- pref64->addr[0] = iface->pref64_addr.s6_addr32[0];
- pref64->addr[1] = iface->pref64_addr.s6_addr32[1] & htonl(mask_a1);
- pref64->addr[2] = iface->pref64_addr.s6_addr32[2] & htonl(mask_a2);
+ (0x7 & iface->pref64_plc));
+ memcpy(pref64->prefix, iface->pref64_prefix, sizeof(pref64->prefix));
}
-pref64_out:
iov[IOV_RA_PREF64].iov_base = (char *)pref64;
iov[IOV_RA_PREF64].iov_len = pref64_sz;