Medius - Native APIRewrite

Rewrite

Match traffic in flight and change it

REWRITE manages up to 32 rules on the device chip. A rule matches packets at one surface and passes, drops, patches, replaces, answers or refuses them before they reach the game PC or the real device.

  real device                                                        game PC

  report      --> [ HID_IN ] --> input pipeline --> [ EMIT ] -------------->
                                                        ^
                        inject, render, clip entries ---+
  vendor IN   --> [ VEND_INTR, VEND_BULK ] -------------------------------->
  IN reply    --> [ CONTROL, reply side ] --------------------------------->

  OUT packet  <-- [ HID_OUT, VEND_INTR, VEND_BULK ] <-----------------------
  request     <-- [ CONTROL, request side ] <-------------------------------
                    |
                    +-- ANSWER, STALL and NAK end the request here

A surface is a CATCH traffic class, addressed by the same (class, id, dir).

NameValueid isCarriesHead
HID_IN4an interface number; 0xFFFF = every HID interfaceINthe device's report as it arrived, report ID first
HID_OUT5an endpoint number; 0xFFFF = every HID interrupt-OUT endpointOUTa report the PC writes to the device
VEND_INTR6an endpoint number; 0xFFFF = every vendor interrupt endpointIN, OUTa relayed vendor interrupt packet
VEND_BULK7an endpoint number; 0xFFFF = every vendor bulk endpointIN, OUTa relayed vendor bulk packet
CONTROL8an endpoint number, 0 = EP0; 0xFFFF = every control endpointIN, OUTthe 8 SETUP bytes, then the first 8 OUT data bytes
EMIT9an endpoint number; 0xFFFF = every cloned HID interrupt-IN endpointINthe report going on the wire
ANY0xFFnot comparedIN, OUTthe head at each surface a packet crosses, so a mouse report meets the rule at HID_IN and again at EMIT

Rules need OPTION(IMPERFECT). Otherwise the box discards every REWRITE but the whole-table clear; turning it off empties the table.

REWRITE

Install, overwrite, or remove one rule

A rule is keyed by (cls, id, dir, mlen, match, mask); setting one whose key exists overwrites it. Opcode 0x1C.

REWRITE 0x1C · payload 9 + 2 x mlen + plen bytes

Fire-and-forget

PAYLOAD
OffsetFieldTypeNotes
0clsu8surface, 4-9 or 0xFF, as the table above
1idu16class address, little-endian; 0xFFFF = every id in the class
3diru80 both, 1 IN, 2 OUT; on CONTROL, the request's direction
4stateu81 set (add or overwrite), 0 remove the keyed rule
5actionu8rule action, 0-8
6offu16byte offset a PATCH or REPLY_PATCH writes at, little-endian
8mlenu8match length, 0-16; 0 takes every packet on the address
9matchu8[]mlen bytes compared against the packet head
9+mlenmasku8[]mlen bytes: a head byte ANDed with its mask byte must equal the match byte
9+2 x mlenpayloadu8[]rest of the frame, plen bytes: what the action writes or replies with

state = 0 removes the rule under that key and ignores action, off and the payload. cls = 0xFF, id = 0xFFFF, state = 0 clears the whole table.

REFUSALS
Refused whenWhy
OPTION(IMPERFECT) off, for any frame but the whole-table clearthe advanced layer needs the opt-in
frame shorter than 9 + 2 x mlenmalformed
11 + 2 x mlen + plen above 512a rule must fit its own readback in one frame
cls is not 4-9 or 0xFFother classes carry no packet
dir above 2a packet travels IN or OUT
mlen above 16the head compare reads at most 16 bytes
action invalid on clsthe action table lists each action's classes
off + plen of a PATCH or REPLY_PATCH passes 64 on a report class or ANY, or 2056 on CONTROLthe write lands past the largest packet the surface carries
a REPLACE payload above 64 bytes on a report class or ANYa report is at most 64 bytes
all rule payloads would pass 2048 bytesone shared pool; an overwrite is costed with its old payload returned, and a refused one keeps the old rule; RESP(REWRITE) sets its full flag
a 33rd rulenothing is evicted; RESP(REWRITE) sets its full flag
state = 0 with no rule under that keynothing to remove
EFFECT

A rule applies from the next packet at its surface. A refused frame changes nothing, so compare QUERY(REWRITE) with what was sent.

EXAMPLE

Drop every report the clone emits on endpoint 1: cls = 9, id = 1, dir = 1, action = 1 (DROP), mlen = 0:

+--------+--------+--------+--------+--------+--------+
| A5     | 1C     | 00     | 09 00  | 09     | 01 00  |
+--------+--------+--------+--------+--------+--------+
| SOF    | TYPE   | SEQ    | LEN    | cls    | id     |
+--------+--------+--------+--------+--------+--------+

+--------+--------+--------+--------+--------+--------+
| 01     | 01     | 01     | 00 00  | 00     | lo hi  |
+--------+--------+--------+--------+--------+--------+
| dir    | state  | action | off    | mlen   | CRC16  |
+--------+--------+--------+--------+--------+--------+

Answer every HID GET_REPORT on EP0 with report ID 7's four bytes: cls = 8, dir = 1, action = 4, and a two-byte match on bmRequestType and bRequest under mask FF FF:

+--------+--------+--------+--------+--------+--------+
| A5     | 1C     | 01     | 11 00  | 08     | 00 00  |
+--------+--------+--------+--------+--------+--------+
| SOF    | TYPE   | SEQ    | LEN    | cls    | id     |
+--------+--------+--------+--------+--------+--------+

+--------+--------+--------+--------+--------+--------+
| 01     | 01     | 04     | 00 00  | 02     | A1 01  |
+--------+--------+--------+--------+--------+--------+
| dir    | state  | action | off    | mlen   | match  |
+--------+--------+--------+--------+--------+--------+

+--------+--------------+--------+
| FF FF  | 07 01 00 00  | lo hi  |
+--------+--------------+--------+
| mask   | payload      | CRC16  |
+--------+--------------+--------+

Library bindings: set_rewrite, remove_rewrite, and clear_rewrite.

Actions

Top-ranked rule's effect

Report classes are 4-7 and 9.

NameValueEffect
PASS0Any class. The packet passes unchanged, and a broader rule it outranks doesn't act.
DROP1Report classes. The packet is dropped.
PATCH2Any class. Writes the payload at off and keeps the length; a write past the packet's end is left unapplied.
REPLACE3Any class. A report becomes the payload, length included.
ANSWER4CONTROL. The box completes the request itself.
STALL5CONTROL. The request ends in a STALL handshake.
NAK6CONTROL. EP0 NAKs until the PC times out; a control endpoint above 0 STALLs.
REPLY_PATCH7CONTROL. Writes the payload into the device's IN reply at off, unapplied past the reply's end.
REPLY_REPLACE8CONTROL. The IN reply becomes the payload, cut to wLength.
CONTROL

On CONTROL an action depends on the request's direction. The reply actions apply only when the device completed the request.

ActionIN requestOUT request
PASSproxied unchangedproxied unchanged
PATCHproxied unchangedthe data stage is patched at off before the device gets it
REPLACEproxied unchangedthe payload overwrites the start of the data stage; wLength is kept
ANSWERthe payload is the reply, cut to wLengththe status stage is ACKed and the data goes no further
STALL, NAKrefusedrefused
REPLY_PATCH, REPLY_REPLACEthe device's reply is rewrittenproxied unchanged

On EP0 the table matches class and vendor requests. The clone serves standard requests such as GET_DESCRIPTOR itself; change a descriptor with PATCH. A control endpoint above 0 passes every request to the table.

Matching

Which rule a packet reaches

A packet shorter than mlen does not match. A match bit outside its mask, or a dir the class never carries, is stored and matches nothing.

RANK

Only the highest-ranked match applies to a packet.

  rank   1  exact (cls, id)       over  id = 0xFFFF   over  cls = 0xFF
         2  more mask bits set    over  fewer
         3  dir 1 or 2            over  dir 0
         4  lower table index

  table (every rule dir 1)                      action
    #0  EMIT  id 0xFFFF  mlen 0                 PASS
    #1  EMIT  id 1       mlen 0                 DROP
    #2  EMIT  id 1       match 02  mask FF      PATCH

  report 02 ... on endpoint 1
    +- #2  exact id, 8 mask bits      top-ranked  --> patched
    +- #1  exact id, 0 mask bits      outranked
    +- #0  id 0xFFFF                  outranked

  report 01 ... on endpoint 1
    +- #2  01 AND FF is not 02        no match
    +- #1  exact id                   top-ranked  --> dropped
    +- #0  id 0xFFFF                  outranked

  report on endpoint 2
    +- #0  id 0xFFFF                  top-ranked  --> passed

An overwrite moves the rule to the end of the table with its hits at 0, so an equal-ranked rule installed earlier now outranks it. A remove or an overwrite shifts every later rule down one index; re-read the list before a QUERY(REWRITE_ENTRY).

HITS

A rule counts one hit per packet it matches as top-ranked, PASS included. A cls = 0xFF rule counts, and its PATCH applies, at each surface it matches. RESP(REWRITE) reports hits saturated at 65535.

Order

Clip triggers, pipeline, RAW

Each surface runs its packets through two tables before delivery.

  packet at a surface
        |
        v
  [ clip packet triggers ]   a consuming trigger stops the packet here
        |
        v
  [ rewrite table ]          the top-ranked match counts a hit and applies
        |
        v
  delivered                  to the game PC (IN) or the real device (OUT)
NameBehaviour
packet triggersA packet can fire a trigger and then match a rule. A report a trigger consumes reaches no rule and counts no hit.
HID_INButtons, keys, media and a secondary mouse's report are read from the rewritten bytes by LOCK, TRANSFORM and injection. A DROP removes the native report; injection still emits on the frame clock.
EMITActs last, on native, injected and rendered reports and a clip's entries. A rewritten report that carries no event against the last one sent is suppressed, unless the device reports every poll.
RAWGoes straight to the endpoint, past every rule and trigger, as a clip's raw items do.
TRANSFERRuns on its own messages to the device, past every rule.

The host chip weighs the bound mouse's relative axes from the report as it arrived. Whenever a scale, injection or rendering changes them, the host chip's values replace a HID_IN rewrite of those bytes. Rewrite motion at EMIT.

CATCH

Each CATCH tap sits at a fixed side of the table, and flags bit 7 marks a packet a rule acted on: changed, dropped, answered or refused. A PASS leaves it clear. A CONTROL event is the transaction the game PC received, on every control endpoint; each class is in rules and taps.

Lifecycle

Rules are PC-owned session state

The table holds until one of these empties it, on the same terms as injection and locks.

CLEARS ON
remove      a REWRITE with state = 0 and the rule's key
clear       state 0 with cls = 0xFF and id = 0xFFFF
silence     ~1 s with no control-PC frame
RESET       a RESET command
link loss   the inter-chip link drops
detach      the real device goes away
re-clone    the box clones the device again: a replug, or a patch presentation
opt-in off  OPTION(IMPERFECT) turned off

Any valid frame resets the silence timer, so a keepalive holds the table. The library re-asserts its held rules on keepalive and across a control-link reconnect, as for LOCK.

Every clear here but remove and clear moves the session count.

GEN
EventEffect
a rule added, overwritten or removedgen goes up by one, wrapping at 255.
a re-send identical to the stored rulegen stays.
a clear or silence that empties a non-empty tablegen goes up by one.
RESET, link loss, detach, re-clone, opt-in offThe table and gen both return to 0.
READBACK

QUERY(REWRITE) returns gen, the full flag and a line per rule; QUERY(REWRITE_ENTRY) returns one rule in this frame's shape. HEALTH sets REWRITE_ON (0x0100) while the table is non-empty.

EXAMPLE

Clear the whole table:

+--------+--------+--------+--------+--------+--------+
| A5     | 1C     | 02     | 09 00  | FF     | FF FF  |
+--------+--------+--------+--------+--------+--------+
| SOF    | TYPE   | SEQ    | LEN    | cls    | id     |
+--------+--------+--------+--------+--------+--------+

+--------+--------+--------+--------+--------+--------+
| 00     | 00     | 00     | 00 00  | 00     | lo hi  |
+--------+--------+--------+--------+--------+--------+
| dir    | state  | action | off    | mlen   | CRC16  |
+--------+--------+--------+--------+--------+--------+

Library bindings: query_rewrite and query_rewrite_entry.