diff --git a/src/ioctl_tree.c b/src/ioctl_tree.c
index 6f96a20258497d1d26535e9a89aeb70038a1e1b0..b6462f58794c0d37939fcfdcabb0f107c2888741 100644
--- a/src/ioctl_tree.c
+++ b/src/ioctl_tree.c
@@ -19,11 +19,15 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <stddef.h>
 #include <assert.h>
 #include <errno.h>
+#include <stdint.h>
 #include <sys/ioctl.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/input.h>
+#include <linux/sockios.h>
+#include <linux/ethtool.h>
 
 #include "ioctl_tree.h"
 
@@ -785,6 +789,33 @@ usbdevfs_reapurb_insertion_parent(ioctl_tree * tree, ioctl_tree * node)
     }
 }
 
+/***********************************
+ *
+ * ethtool
+ *
+ ***********************************/
+
+static size_t
+ioctl_ethtool_data_len(unsigned long id, const void* data)
+{
+    /* see /usr/include/linux/ethtool.h */
+    uint32_t cmd = *((uint32_t*) data);
+    DBG("ioctl_ethtool_data_len: id %lX, cmd: %X\n", id, cmd);
+    switch (cmd) {
+	/* structs with fixed size */
+	case ETHTOOL_GWOL:
+	    /* cannot use sizeof, as this gives 2 padding junk bytes at the end */
+	    return offsetof(struct ethtool_wolinfo, sopass) + SOPASS_MAX;
+
+	/* structs with dynamic size */
+
+	default:
+	    fprintf(stderr, "ioctl_ethtool_data_len: unsupported cmd: %X\n", cmd);
+	    abort();
+    }
+}
+
+
 /***********************************
  *
  * generic implementations for hardware/state independent ioctls
@@ -913,6 +944,9 @@ ioctl_type ioctl_db[] = {
     I_NAMED_SIMPLE_STRUCT_IN(EVIOCGMTSLOTS(32), "EVIOCGMTSLOTS", 0, ioctl_insertion_parent_stateless),
 #endif
 
+    /* ethtool */
+    I_VARLEN_STRUCT_IN(SIOCETHTOOL, ioctl_insertion_parent_stateless, ioctl_ethtool_data_len),
+
     /* terminator */
     {0, 0, 0, "", NULL, NULL, NULL, NULL, NULL}
 };
diff --git a/tests/test-ioctl-tree.c b/tests/test-ioctl-tree.c
index 997b957287a4bad166a78237a8b83e46368bbaea..d03c975785abbe6a296ca6959de3ad30890be930 100644
--- a/tests/test-ioctl-tree.c
+++ b/tests/test-ioctl-tree.c
@@ -25,6 +25,8 @@
 #include <sys/ioctl.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/input.h>
+#include <linux/sockios.h>
+#include <linux/ethtool.h>
 
 #include "ioctl_tree.h"
 
@@ -554,6 +556,61 @@ t_evdev(void)
     ioctl_tree_free(tree);
 }
 
+static void
+t_ethtool(void)
+{
+    ioctl_tree *tree = NULL, *t;
+    FILE *f;
+    char contents[1000];
+    struct ethtool_wolinfo wolinfo = { ETHTOOL_GWOL, 1, 42, "s3kr1t" };
+    int ret;
+
+    /* create tree from ioctl */
+    tree = ioctl_tree_new_from_bin(SIOCETHTOOL, &wolinfo, 0);
+    g_assert(tree != NULL);
+    g_assert(ioctl_tree_insert(NULL, tree) == NULL);
+
+    /* insert duplicate, should be recognized as such */
+    t = ioctl_tree_new_from_bin(SIOCETHTOOL, &wolinfo, 0);
+    g_assert(t != NULL);
+    g_assert(ioctl_tree_insert(tree, t) == tree);
+
+    /* write it */
+    f = tmpfile();
+    ioctl_tree_write(f, tree);
+    rewind(f);
+    ioctl_tree_free(tree);
+
+    /* check text representation */
+    memset(contents, 0, sizeof(contents));
+    g_assert_cmpint(fread(contents, 1, sizeof(contents), f), >, 10);
+    g_assert_cmpstr(contents, ==,
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+		    "SIOCETHTOOL 0 05000000010000002A00000073336B723174\n"
+#else
+		    "SIOCETHTOOL 0 00000005000000010000002A73336B723174\n"
+#endif
+    );
+    rewind(f);
+
+    /* read it back */
+    tree = ioctl_tree_read(f);
+    fclose(f);
+
+    /* execute ETHTOOL_GWOL */
+    memset(&wolinfo, 0xAA, sizeof(wolinfo));
+    wolinfo.cmd = ETHTOOL_GWOL;
+    g_assert(ioctl_tree_execute(tree, NULL, SIOCETHTOOL, &wolinfo, &ret));
+    g_assert(ret == 0);
+    g_assert_cmpuint(wolinfo.cmd, ==, ETHTOOL_GWOL);
+    g_assert_cmpuint(wolinfo.supported, ==, 1);
+    g_assert_cmpuint(wolinfo.wolopts, ==, 42);
+    g_assert(memcmp(wolinfo.sopass, "s3kr1t", 6) == 0);
+    /* does not write into padding (if we have any) */
+    if (sizeof(wolinfo) > tree->type->get_data_size(tree->id, tree->data))
+	g_assert_cmpuint(wolinfo.sopass[6], ==, 0xAA);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -571,6 +628,7 @@ main(int argc, char **argv)
     g_test_add_func("/umockdev-ioctl-tree/execute_unknown", t_execute_unknown);
 
     g_test_add_func("/umockdev-ioctl-tree/evdev", t_evdev);
+    g_test_add_func("/umockdev-ioctl-tree/ethtool", t_ethtool);
 
     return g_test_run();
 }