From 60ac1b77c54ee43d3a1c0d42d9349e455c348c3c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 28 Oct 2013 13:22:23 -0400 Subject: [PATCH] Fix for GitHub issue #25 --- Makefile.mac | 2 +- node/EthernetTap.cpp | 38 ++++++++++++++++++++++++------------ tap-mac/tuntap/src/tuntap.cc | 8 ++++++-- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/Makefile.mac b/Makefile.mac index f3c6136fc..6955710e2 100644 --- a/Makefile.mac +++ b/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) diff --git a/node/EthernetTap.cpp b/node/EthernetTap.cpp index 226d03978..fadd8e502 100644 --- a/node/EthernetTap.cpp +++ b/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; + } } } } diff --git a/tap-mac/tuntap/src/tuntap.cc b/tap-mac/tuntap/src/tuntap.cc index 941de94c3..7fdbb7959 100644 --- a/tap-mac/tuntap/src/tuntap.cc +++ b/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 + //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 */