Author: axeld Date: 2010-08-11 15:53:31 +0200 (Wed, 11 Aug 2010) New Revision: 38026 Changeset: http://dev.haiku-os.org/changeset/38026 Modified: haiku/trunk/headers/os/net/NetworkAddress.h haiku/trunk/src/kits/network/libnetapi/NetworkAddress.cpp Log: * Implemented SetToMask(), and added PrefixLength() method, mostly reusing code from ifconfig. Modified: haiku/trunk/headers/os/net/NetworkAddress.h =================================================================== --- haiku/trunk/headers/os/net/NetworkAddress.h 2010-08-11 13:25:36 UTC (rev 38025) +++ haiku/trunk/headers/os/net/NetworkAddress.h 2010-08-11 13:53:31 UTC (rev 38026) @@ -82,6 +82,8 @@ bool IsSiteLocal() const; bool IsLocal() const; + ssize_t PrefixLength() const; + uint32 LinkLevelIndex() const; BString LinkLevelInterface() const; uint32 LinkLevelType() const; Modified: haiku/trunk/src/kits/network/libnetapi/NetworkAddress.cpp =================================================================== --- haiku/trunk/src/kits/network/libnetapi/NetworkAddress.cpp 2010-08-11 13:25:36 UTC (rev 38025) +++ haiku/trunk/src/kits/network/libnetapi/NetworkAddress.cpp 2010-08-11 13:53:31 UTC (rev 38026) @@ -423,8 +423,52 @@ status_t BNetworkAddress::SetToMask(int family, uint32 prefixLength) { - // TODO: implement SetToMask() - return B_NOT_SUPPORTED; + switch (family) { + case AF_INET: + { + if (prefixLength > 32) + return B_BAD_VALUE; + + sockaddr_in& mask = (sockaddr_in&)fAddress; + memset(&fAddress, 0, sizeof(sockaddr_storage)); + mask.sin_family = AF_INET; + mask.sin_len = sizeof(sockaddr_in); + + uint32 hostMask = 0; + for (uint8 i = 32; i > 32 - prefixLength; i--) + hostMask |= 1 << (i - 1); + + mask.sin_addr.s_addr = htonl(hostMask); + break; + } + + case AF_INET6: + { + if (prefixLength > 128) + return B_BAD_VALUE; + + sockaddr_in6& mask = (sockaddr_in6&)fAddress; + memset(&fAddress, 0, sizeof(sockaddr_storage)); + mask.sin6_family = AF_INET6; + mask.sin6_len = sizeof(sockaddr_in6); + + for (uint8 i = 0; i < sizeof(in6_addr); i++, prefixLength -= 8) { + if (prefixLength < 8) { + mask.sin6_addr.s6_addr[i] + = (uint8)(0xff << (8 - prefixLength)); + break; + } + + mask.sin6_addr.s6_addr[i] = 0xff; + } + break; + } + + default: + return B_NOT_SUPPORTED; + } + + return B_OK; } @@ -709,6 +753,47 @@ } +ssize_t +BNetworkAddress::PrefixLength() const +{ + switch (fAddress.ss_family) { + case AF_INET: + { + sockaddr_in& mask = (sockaddr_in&)fAddress; + + ssize_t result = 0; + uint32 hostMask = ntohl(mask.sin_addr.s_addr); + for (uint8 i = 32; i > 0; i--) { + if ((hostMask & (1 << (i - 1))) == 0) + break; + result++; + } + + return result; + } + + case AF_INET6: + { + sockaddr_in6& mask = (sockaddr_in6&)fAddress; + + ssize_t result = 0; + for (uint8 i = 0; i < sizeof(in6_addr); i++) { + for (uint8 j = 0; j < 8; j++) { + if (!(mask.sin6_addr.s6_addr[i] & (1 << j))) + return result; + result++; + } + } + + return 128; + } + + default: + return B_NOT_SUPPORTED; + } +} + + uint32 BNetworkAddress::LinkLevelIndex() const {