inet6_makenetandmask() parses the provided prefix length `plen' twice:
first from inside prefixlen() which sets the mask, then right again
doing almost the same dance to find out which bits to zero in the
provided address.

But once prefixlen() set so_mask, we can just use it to actually mask
the address.

prefixlen() returns `(len == max)' where `max = 128' for `AF_INET6', so
it's equivalent to the strcmp() call.

Regress tests pass on amd64, also no issue after manually adding,
testing and removing routes on my machine.

Feedback? OK?

Index: route.c
===================================================================
RCS file: /cvs/src/sbin/route/route.c,v
retrieving revision 1.214
diff -u -p -r1.214 route.c
--- route.c     1 May 2018 18:14:10 -0000       1.214
+++ route.c     26 May 2018 10:49:50 -0000
@@ -786,21 +786,17 @@ inet_makenetandmask(u_int32_t net, struc
        sin->sin_len = 1 + cp - (char *)sin;
 }
 
-/*
- * XXX the function may need more improvement...
- */
 int
 inet6_makenetandmask(struct sockaddr_in6 *sin6, char *plen)
 {
        struct in6_addr in6;
-       const char *errstr;
-       int i, len, q, r;
+       int i;
 
-       if (NULL==plen) {
+       if (!plen) {
                if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
-                   sin6->sin6_scope_id == 0) {
+                   sin6->sin6_scope_id == 0)
                        plen = "0";
-               } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
+               else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
                        /* aggregatable global unicast - RFC2374 */
                        memset(&in6, 0, sizeof(in6));
                        if (!memcmp(&sin6->sin6_addr.s6_addr[8],
@@ -809,27 +805,14 @@ inet6_makenetandmask(struct sockaddr_in6
                }
        }
 
-       if (!plen || strcmp(plen, "128") == 0)
+       if (!plen || prefixlen(AF_INET6, plen))
                return (1);
-       else {
-               rtm_addrs |= RTA_NETMASK;
-               prefixlen(AF_INET6, plen);
-
-               len = strtonum(plen, 0, 128, &errstr);
-               if (errstr)
-                       errx(1, "prefixlen %s is %s", plen, errstr);
-
-               q = (128-len) >> 3;
-               r = (128-len) & 7;
-               i = 15;
-
-               while (q-- > 0)
-                       sin6->sin6_addr.s6_addr[i--] = 0;
-               if (r > 0)
-                       sin6->sin6_addr.s6_addr[i] &= 0xff << r;
+       rtm_addrs |= RTA_NETMASK;
 
-               return (0);
-       }
+       for (i = 0; i < 16; ++i)
+               sin6->sin6_addr.s6_addr[i] &= so_mask.sin6.sin6_addr.s6_addr[i];
+
+       return (0);
 }
 
 /*

Reply via email to