diff options
| author | Jari Vetoniemi <mailroxas@gmail.com> | 2018-07-04 20:25:49 +0300 | 
|---|---|---|
| committer | Jari Vetoniemi <mailroxas@gmail.com> | 2018-07-04 20:56:04 +0300 | 
| commit | 0699cbd82b577a4358d199a627e9bc4497f436e7 (patch) | |
| tree | 3ebd8effe6ce2100077052622ceb8678070ebe9e /common | |
initial commit
Diffstat (limited to 'common')
| -rw-r--r-- | common/packet.h | 79 | 
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"))); | 
