Use ffs64(3) instead of ffs(3) when calculating to see if we can fit the

user number inside the resultant length given the prefix length, so we can
use the whole of the user number (64 bits) if needed.

Add a compat ffs64(3) implementation from NetBSD if none found on the platform.
This commit is contained in:
Roy Marples 2016-01-29 10:18:02 +00:00
parent 40095c803a
commit f5eb2f8781
3 changed files with 103 additions and 4 deletions

73
compat/ffs64.h Normal file
View File

@ -0,0 +1,73 @@
/* $NetBSD: bitops.h,v 1.11 2012/12/07 02:27:58 christos Exp $ */
/*-
* Copyright (c) 2007, 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas and Joerg Sonnenberger.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef COMPAT_FFS64
#define COMPAT_FFS64
#include <stdint.h>
inline static int
ffs64(uint64_t _n)
{
int _v;
if (!_n)
return 0;
_v = 1;
if ((_n & 0x00000000FFFFFFFFULL) == 0) {
_n >>= 32;
_v += 32;
}
if ((_n & 0x000000000000FFFFULL) == 0) {
_n >>= 16;
_v += 16;
}
if ((_n & 0x00000000000000FFULL) == 0) {
_n >>= 8;
_v += 8;
}
if ((_n & 0x000000000000000FULL) == 0) {
_n >>= 4;
_v += 4;
}
if ((_n & 0x0000000000000003ULL) == 0) {
_n >>= 2;
_v += 2;
}
if ((_n & 0x0000000000000001ULL) == 0) {
_n >>= 1;
_v += 1;
}
return _v;
}
#endif

22
configure vendored
View File

@ -985,6 +985,28 @@ if [ "$BE64ENC" = no ]; then
echo "#include \"compat/endian.h\"" >>$CONFIG_H echo "#include \"compat/endian.h\"" >>$CONFIG_H
fi fi
if [ -z "$FFS64" ]; then
printf "Testing for ffs64 ... "
cat <<EOF >_ffs64.c
#include <sys/bitops.h>
int main(void) {
return (int)ffs64(1337);
}
EOF
if $XCC _ffs64.c -o _ffs64 2>&3; then
FFS64=yes
else
FFS64=no
fi
echo "$FFS64"
rm -f _ffs64.c _ffs64
fi
if [ "$FFS64" = yes ]; then
echo "CPPFLAGS+= -DHAVE_SYS_BITOPS_H" >>$CONFIG_MK
else
echo "#include \"compat/ffs64.h\"" >>$CONFIG_H
fi
if [ -z "$MD5" ]; then if [ -z "$MD5" ]; then
MD5_LIB= MD5_LIB=
printf "Testing for MD5Init ... " printf "Testing for MD5Init ... "

12
ipv6.c
View File

@ -37,6 +37,10 @@
#include "config.h" #include "config.h"
#ifdef HAVE_SYS_BITOPS_H
#include <sys/bitops.h>
#endif
#ifdef BSD #ifdef BSD
/* Purely for the ND6_IFF_AUTO_LINKLOCAL #define which is solely used /* Purely for the ND6_IFF_AUTO_LINKLOCAL #define which is solely used
* to generate our CAN_ADD_LLADDR #define. */ * to generate our CAN_ADD_LLADDR #define. */
@ -518,16 +522,16 @@ ipv6_userprefix(
{ {
uint64_t vh, vl, user_low, user_high; uint64_t vh, vl, user_low, user_high;
if (prefix_len < 0 || prefix_len > 120 || if (prefix_len < 0 || prefix_len > 128 ||
result_len < 0 || result_len > 120) result_len < 0 || result_len > 128)
{ {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
/* Check that the user_number fits inside result_len less prefix_len */ /* Check that the user_number fits inside result_len less prefix_len */
if (result_len < prefix_len || user_number > INT_MAX || if (result_len < prefix_len ||
ffs((int)user_number) > result_len - prefix_len) ffs64(user_number) > result_len - prefix_len)
{ {
errno = ERANGE; errno = ERANGE;
return -1; return -1;