diff options
Diffstat (limited to 'src/osd/modules/netdev/taptun.cpp')
-rw-r--r-- | src/osd/modules/netdev/taptun.cpp | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/src/osd/modules/netdev/taptun.cpp b/src/osd/modules/netdev/taptun.cpp index b4d8b963c02..a76718e1ad8 100644 --- a/src/osd/modules/netdev/taptun.cpp +++ b/src/osd/modules/netdev/taptun.cpp @@ -28,6 +28,9 @@ // for some reason this isn't defined in the header, and presumably it changes // with major? versions of the driver - perhaps it should be configurable? #define PRODUCT_TAP_WIN_COMPONENT_ID "tap0901" + +// Ethernet minimum frame length +static constexpr int ETHERNET_MIN_FRAME = 64; #endif class taptun_module : public osd_module, public netdev_module @@ -53,10 +56,10 @@ public: netdev_tap(const char *name, class device_network_interface *ifdev, int rate); ~netdev_tap(); - int send(uint8_t *buf, int len); + int send(uint8_t *buf, int len) override; void set_mac(const char *mac); protected: - int recv_dev(uint8_t **buf); + int recv_dev(uint8_t **buf) override; private: #if defined(WIN32) HANDLE m_handle = INVALID_HANDLE_VALUE; @@ -136,6 +139,35 @@ void netdev_tap::set_mac(const char *mac) } #if defined(WIN32) +static u32 finalise_frame(u8 buf[], u32 length) +{ + /* + * On Windows, the taptun driver receives frames which are shorter + * than the Ethernet minimum. Partly this is because it can't see + * the frame check sequence bytes, but mainly it's because NDIS + * expects the lower level device to add the required padding. + * We do the equivalent padding here (i.e. pad with zeroes to the + * minimum Ethernet length minus FCS), so that devices which check + * for this will not reject these packets. + */ + if (length < ETHERNET_MIN_FRAME - 4) + { + std::fill_n(&buf[length], ETHERNET_MIN_FRAME - length - 4, 0); + + length = ETHERNET_MIN_FRAME - 4; + } + + // compute and append the frame check sequence + const u32 fcs = util::crc32_creator::simple(buf, length); + + buf[length++] = (fcs >> 0) & 0xff; + buf[length++] = (fcs >> 8) & 0xff; + buf[length++] = (fcs >> 16) & 0xff; + buf[length++] = (fcs >> 24) & 0xff; + + return length; +} + int netdev_tap::send(uint8_t *buf, int len) { OVERLAPPED overlapped = {}; @@ -171,7 +203,7 @@ int netdev_tap::recv_dev(uint8_t **buf) // handle unexpected synchronous completion *buf = m_buf; - return bytes_transferred; + return finalise_frame(m_buf, bytes_transferred); } else if (GetLastError() == ERROR_IO_PENDING) m_receive_pending = true; @@ -184,7 +216,7 @@ int netdev_tap::recv_dev(uint8_t **buf) m_receive_pending = false; *buf = m_buf; - return bytes_transferred; + return finalise_frame(m_buf, bytes_transferred); } } |