Browse Source

Fix for missing broadcast address on Linux Ethernet taps.

Adam Ierymenko 11 years ago
parent
commit
6df9546742
3 changed files with 37 additions and 2 deletions
  1. 22 0
      node/InetAddress.cpp
  2. 8 0
      node/InetAddress.hpp
  3. 7 2
      osnet/LinuxEthernetTap.cpp

+ 22 - 0
node/InetAddress.cpp

@@ -196,6 +196,28 @@ InetAddress InetAddress::netmask() const
 	return r;
 	return r;
 }
 }
 
 
+InetAddress InetAddress::broadcast() const
+	throw()
+{
+	InetAddress r(*this);
+	switch(_sa.saddr.sa_family) {
+		case AF_INET:
+			r._sa.sin.sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
+			break;
+		case AF_INET6: {
+			unsigned char *bf = (unsigned char *)r._sa.sin6.sin6_addr.s6_addr;
+			signed int bitsLeft = (signed int)netmaskBits();
+			for(unsigned int i=0;i<16;++i) {
+				if (bitsLeft > 0) {
+					bf[i] |= (unsigned char)((bitsLeft >= 8) ? 0x00 : (0xff >> bitsLeft));
+					bitsLeft -= 8;
+				}
+			}
+		}	break;
+	}
+	return r;
+}
+
 bool InetAddress::sameNetworkAs(const InetAddress &ipnet) const
 bool InetAddress::sameNetworkAs(const InetAddress &ipnet) const
 	throw()
 	throw()
 {
 {

+ 8 - 0
node/InetAddress.hpp

@@ -217,6 +217,14 @@ public:
 	InetAddress netmask() const
 	InetAddress netmask() const
 		throw();
 		throw();
 
 
+	/**
+	 * Constructs a broadcast address from a network/netmask address
+	 *
+	 * @return Broadcast address (only IP portion is meaningful)
+	 */
+	InetAddress broadcast() const
+		throw();
+
 	/**
 	/**
 	 * @return True if this is an IPv4 address
 	 * @return True if this is an IPv4 address
 	 */
 	 */

+ 7 - 2
osnet/LinuxEthernetTap.cpp

@@ -224,8 +224,13 @@ bool LinuxEthernetTap::addIP(const InetAddress &ip)
 	long cpid = (long)vfork();
 	long cpid = (long)vfork();
 	if (cpid == 0) {
 	if (cpid == 0) {
 		Utils::redirectUnixOutputs("/dev/null",(const char *)0);
 		Utils::redirectUnixOutputs("/dev/null",(const char *)0);
-		::execl("/sbin/ip","/sbin/ip","addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
-		::execl("/usr/sbin/ip","/usr/sbin/ip","addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
+		if (ip.isV4()) {
+			::execl("/sbin/ip","/sbin/ip","addr","add",ip.toString().c_str(),"broadcast",ip.broadcast().toIpString().c_str(),"dev",_dev.c_str(),(const char *)0);
+			::execl("/usr/sbin/ip","/usr/sbin/ip","addr","add",ip.toString().c_str(),"broadcast",ip.broadcast().toIpString().c_str(),"dev",_dev.c_str(),(const char *)0);
+		} else {
+			::execl("/sbin/ip","/sbin/ip","addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
+			::execl("/usr/sbin/ip","/usr/sbin/ip","addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
+		}
 		::_exit(-1);
 		::_exit(-1);
 	} else if (cpid > 0) {
 	} else if (cpid > 0) {
 		int exitcode = -1;
 		int exitcode = -1;