router: move pref64 calculations to the config stage
authorDavid Härdeman <david@hardeman.nu>
Sat, 10 Feb 2024 02:35:04 +0000 (03:35 +0100)
committerdedeckeh <dedeckeh@gmail.com>
Mon, 30 Dec 2024 19:44:26 +0000 (20:44 +0100)
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>
src/config.c
src/odhcpd.h
src/router.c

index e816f4b3e3499ca4f4126c5c309588cd4f863b78..4e1493f350670e9826d9862ebac17a4f9e394d62 100644 (file)
@@ -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);
index 61fb64c54a0f89f2e88c2e563838011560dff829..779f50f84a58262bac1fd5e7897dce2123314728 100644 (file)
@@ -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;
index b6309531a5920ab1692c05ffb79bd848c502d612..2443078ae0113d44220c9c85f4bde9cf3db72186 100644 (file)
@@ -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;