summaryrefslogtreecommitdiff
path: root/common/packet.h
diff options
context:
space:
mode:
Diffstat (limited to 'common/packet.h')
-rw-r--r--common/packet.h79
1 files changed, 79 insertions, 0 deletions
diff --git a/common/packet.h b/common/packet.h
new file mode 100644
index 0000000..35c57e1
--- /dev/null
+++ b/common/packet.h
@@ -0,0 +1,79 @@
+#pragma once
+
+enum packet_type {
+ PACKET_IOCTL,
+ PACKET_WRITE,
+};
+
+enum ioctl_dir {
+ IOCTL_NONE,
+ IOCTL_IOR,
+ IOCTL_IOW,
+ IOCTL_IOWR,
+};
+
+enum ioctl_arg {
+ IOCTL_ARG_INT,
+ IOCTL_ARG_OTHER, // All bets off, can't assure portability
+};
+
+/**
+ * Lackluster "network transparent" ioctl call
+ * Implements enough to have remote uinput interface.
+ */
+struct ioctl {
+ /**
+ * Because the 32bit encoding of ioctl message is not stable ABI interface between CPU architectures,
+ * we'll write the raw _IOC arguments on the wire and reconstruct the 32bit encoding on uinputd.
+ */
+ uint8_t dir; // enum ioctl_dir, we can't use bitmask directly, as it's not portable
+ uint8_t type; // type of ioctl, e.g. UINPUT_IOCTL_BASE
+ uint8_t nr; // command code (nr), e.g. 100 of UINPUT_IOCTL_BASE which means UI_SET_EVBIT
+
+ /**
+ * Ioctl ABI also includes argument size part, which is mainly used for typechecking.
+ * However since the arguments are not exact size types, but again CPU architecture dependant sizes, and even
+ * compiler dependant for structs (even though they use __u32 and friends, the padding may differ), we can't
+ * really do generic network abstraction.
+ *
+ * To avoid creating wrapper/shim over uinput/evdev (or for other linux interfaces if ever needed to be expanded), we
+ * use another type enum for ioctl argument type, for structs all bets are off, they may work or not work at all.
+ * (e.g. the ioctl will fail since it won't pass typecheck due to different sized of structs in between client <-> server)
+ */
+
+ uint8_t arg; // enum ioctl_arg, ^ read above
+
+ union {
+ uint32_t integer;
+ uint16_t bytes; // max ioctl parameter size can be 16kB -1
+ };
+
+ // payload, for IOCTL_ARG_OTHER, read the amount of bytes indicated by 'bytes'
+};
+
+/**
+ * Network transparent write call
+ *
+ * The call itself is portable, the underlying data may not be.
+ * E.g. structs used by evdev aren't packed, and some of them contain non explicit types such as POSIX struct timeval.
+ */
+struct write {
+ uint64_t bytes; // amount of bytes to be written
+
+ // payload, read the amount of bytes indicated by 'bytes'
+};
+
+/**
+ * Binary specification for uinputd messages.
+ * All fields must be in little-endian.
+ *
+ * All packet operations are applied into the open uinput fd.
+ */
+struct packet {
+ uint8_t type; // enum packet_type
+
+ union {
+ struct ioctl ioctl;
+ struct write write;
+ };
+} __attribute__((packed)) __attribute__((scalar_storage_order("little-endian")));