Browse Source

Fix for GitHub issue #25

Adam Ierymenko 11 years ago
parent
commit
60ac1b77c5
3 changed files with 33 additions and 15 deletions
  1. 1 1
      Makefile.mac
  2. 26 12
      node/EthernetTap.cpp
  3. 6 2
      tap-mac/tuntap/src/tuntap.cc

+ 1 - 1
Makefile.mac

@@ -17,7 +17,7 @@ CXXFLAGS=$(CFLAGS) -fno-rtti
 
 include objects.mk
 
-all: one cli mac-tap
+all: one cli
 
 one:	$(OBJS)
 	$(CXX) $(CXXFLAGS) -o zerotier-one main.cpp $(OBJS) $(LIBS)

+ 26 - 12
node/EthernetTap.cpp

@@ -533,6 +533,7 @@ void EthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const
 		*((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
 		memcpy(putBuf + 14,data,len);
 		len += 14;
+
 		int n = ::write(_fd,putBuf,len);
 		if (n <= 0) {
 			LOG("error writing packet to Ethernet tap device: %s",strerror(errno));
@@ -658,7 +659,8 @@ void EthernetTap::threadMain()
 {
 	fd_set readfds,nullfds;
 	MAC to,from;
-	char getBuf[4096 + 14];
+	int n,nfds,r;
+	char getBuf[8194];
 	Buffer<4096> data;
 
 	// Wait for a moment after startup -- wait for Network to finish
@@ -667,8 +669,9 @@ void EthernetTap::threadMain()
 
 	FD_ZERO(&readfds);
 	FD_ZERO(&nullfds);
-	int nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
+	nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
 
+	r = 0;
 	for(;;) {
 		FD_SET(_shutdownSignalPipe[0],&readfds);
 		FD_SET(_fd,&readfds);
@@ -678,20 +681,31 @@ void EthernetTap::threadMain()
 			break;
 
 		if (FD_ISSET(_fd,&readfds)) {
-			int n = (int)::read(_fd,getBuf,_mtu + 14);
-
-			if (n > 14) {
-				for(int i=0;i<6;++i)
-					to.data[i] = (unsigned char)getBuf[i];
-				for(int i=0;i<6;++i)
-					from.data[i] = (unsigned char)getBuf[i + 6];
-				data.copyFrom(getBuf + 14,(unsigned int)n - 14);
-				_handler(_arg,from,to,ntohs(((const uint16_t *)getBuf)[6]),data);
-			} else if (n < 0) {
+			n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r);
+			if (n < 0) {
 				if ((errno != EINTR)&&(errno != ETIMEDOUT)) {
 					TRACE("unexpected error reading from tap: %s",strerror(errno));
 					break;
 				}
+			} else {
+				// Some tap drivers like to send the ethernet frame and the
+				// payload in two chunks, so handle that by accumulating
+				// data until we have at least a frame.
+				r += n;
+				if (r > 14) {
+					if (r > (_mtu + 14)) // sanity check for weird TAP behavior on some platforms
+						r = _mtu + 14;
+					for(int i=0;i<6;++i)
+						to.data[i] = (unsigned char)getBuf[i];
+					for(int i=0;i<6;++i)
+						from.data[i] = (unsigned char)getBuf[i + 6];
+					unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]);
+					if (etherType != 0x8100) { // VLAN tagged frames are not supported!
+						data.copyFrom(getBuf + 14,(unsigned int)r - 14);
+						_handler(_arg,from,to,etherType,data);
+					}
+					r = 0;
+				}
 			}
 		}
 	}

+ 6 - 2
tap-mac/tuntap/src/tuntap.cc

@@ -648,7 +648,9 @@ tuntap_interface::cdev_write(uio_t uio, int ioflag)
 	mb = first;
 	while (uio_resid(uio) > 0) {
 		/* copy a chunk. enforce mtu (don't know if this is correct behaviour) */
-		chunk_len = min(ifnet_mtu(ifp), min(uio_resid(uio), mlen));
+		// ... evidently not :) -- Adam Ierymenko <[email protected]>
+		//chunk_len = min(ifnet_mtu(ifp), min(uio_resid(uio), mlen));
+		chunk_len = min(uio_resid(uio),mlen);
 		error = uiomove((caddr_t) mbuf_data(mb), chunk_len, uio);
 		if (error) {
 			log(LOG_ERR, "tuntap: could not copy data from userspace: %d\n", error);
@@ -664,7 +666,9 @@ tuntap_interface::cdev_write(uio_t uio, int ioflag)
 		copied += chunk_len;
 
 		/* if done, break the loop */
-		if (uio_resid(uio) <= 0 || copied >= ifnet_mtu(ifp))
+		//if (uio_resid(uio) <= 0 || copied >= ifnet_mtu(ifp))
+		//	break;
+		if (uio_resid(uio) <= 0)
 			break;
 
 		/* allocate a new mbuf if the current is filled */