On Sat, May 26, 2018 at 12:54:03PM +0200, Klemens Nanni wrote:
> 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],
Not related to this diff but RFC2374 has been made obsolete by RFC3587 for some
years : "implementations should not make any assumptions about 2000::/3 being
special". I think we can simplify this "else if" :)
> @@ -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;
Can't we consider this done in prefixlen() ?
>
> - return (0);
> - }
> + for (i = 0; i < 16; ++i)
> + sin6->sin6_addr.s6_addr[i] &= so_mask.sin6.sin6_addr.s6_addr[i];
> +
> + return (0);
> }
>
> /*
>