summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/netdev/taptun.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/netdev/taptun.cpp')
-rw-r--r--src/osd/modules/netdev/taptun.cpp40
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);
}
}