diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-10-28 13:22:23 -0400 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-10-28 13:22:23 -0400 |
commit | 60ac1b77c54ee43d3a1c0d42d9349e455c348c3c (patch) | |
tree | 28bb5e7377cd4cd4fc697ddfae0a71a27a241a52 /node | |
parent | e514fe2bffff20631df81312816aa444098dde62 (diff) | |
download | infinitytier-60ac1b77c54ee43d3a1c0d42d9349e455c348c3c.tar.gz infinitytier-60ac1b77c54ee43d3a1c0d42d9349e455c348c3c.zip |
Fix for GitHub issue #25
Diffstat (limited to 'node')
-rw-r--r-- | node/EthernetTap.cpp | 38 |
1 files changed, 26 insertions, 12 deletions
diff --git a/node/EthernetTap.cpp b/node/EthernetTap.cpp index 226d0397..fadd8e50 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; + } } } } |