• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANDROID_APF_APF_H
18 #define ANDROID_APF_APF_H
19 
20 /* A brief overview of APF:
21  *
22  * APF machine is composed of:
23  *  1. A read-only program consisting of bytecodes as described below.
24  *  2. Two 32-bit registers, called R0 and R1.
25  *  3. Sixteen 32-bit temporary memory slots (cleared between packets).
26  *  4. A read-only packet.
27  *  5. An optional read-write transmit buffer.
28  * The program is executed by the interpreter below and parses the packet
29  * to determine if the application processor (AP) should be woken up to
30  * handle the packet or if it can be dropped.  The program may also choose
31  * to allocate/transmit/deallocate the transmit buffer.
32  *
33  * APF bytecode description:
34  *
35  * The APF interpreter uses big-endian byte order for loads from the packet
36  * and for storing immediates in instructions.
37  *
38  * Each instruction starts with a byte composed of:
39  *  Top 5 bits form "opcode" field, see *_OPCODE defines below.
40  *  Next 2 bits form "size field", which indicates the length of an immediate
41  *  value which follows the first byte.  Values in this field:
42  *                 0 => immediate value is 0 and no bytes follow.
43  *                 1 => immediate value is 1 byte big.
44  *                 2 => immediate value is 2 bytes big.
45  *                 3 => immediate value is 4 bytes big.
46  *  Bottom bit forms "register" field, which (usually) indicates which register
47  *  this instruction operates on.
48  *
49  *  There are four main categories of instructions:
50  *  Load instructions
51  *    These instructions load byte(s) of the packet into a register.
52  *    They load either 1, 2 or 4 bytes, as determined by the "opcode" field.
53  *    They load into the register specified by the "register" field.
54  *    The immediate value that follows the first byte of the instruction is
55  *    the byte offset from the beginning of the packet to load from.
56  *    There are "indexing" loads which add the value in R1 to the byte offset
57  *    to load from. The "opcode" field determines which loads are "indexing".
58  *  Arithmetic instructions
59  *    These instructions perform simple operations, like addition, on register
60  *    values. The result of these instructions is always written into R0. One
61  *    argument of the arithmetic operation is R0's value. The other argument
62  *    of the arithmetic operation is determined by the "register" field:
63  *            If the "register" field is 0 then the immediate value following
64  *            the first byte of the instruction is used as the other argument
65  *            to the arithmetic operation.
66  *            If the "register" field is 1 then R1's value is used as the other
67  *            argument to the arithmetic operation.
68  *  Conditional jump instructions
69  *    These instructions compare register R0's value with another value, and if
70  *    the comparison succeeds, jump (i.e. adjust the program counter). The
71  *    immediate value that follows the first byte of the instruction
72  *    represents the jump target offset, i.e. the value added to the program
73  *    counter if the comparison succeeds. The other value compared is
74  *    determined by the "register" field:
75  *            If the "register" field is 0 then another immediate value
76  *            follows the jump target offset. This immediate value is of the
77  *            same size as the jump target offset, and represents the value
78  *            to compare against.
79  *            If the "register" field is 1 then register R1's value is
80  *            compared against.
81  *    The type of comparison (e.g. equal to, greater than etc) is determined
82  *    by the "opcode" field. The comparison interprets both values being
83  *    compared as unsigned values.
84  *  Miscellaneous instructions
85  *    Instructions for:
86  *      - allocating/transmitting/deallocating transmit buffer
87  *      - building the transmit packet (copying bytes into it)
88  *      - read/writing data section
89  *
90  *  Miscellaneous details:
91  *
92  *  Pre-filled temporary memory slot values
93  *    When the APF program begins execution, six of the sixteen memory slots
94  *    are pre-filled by the interpreter with values that may be useful for
95  *    programs:
96  *      #0 to #7 are zero initialized.
97  *      Slot #8  is initialized with apf version (on APF >4).
98  *      Slot #9  this is slot #15 with greater resolution (1/16384ths of a second)
99  *      Slot #10 starts at zero, implicitly used as tx buffer output pointer.
100  *      Slot #11 contains the size (in bytes) of the APF program.
101  *      Slot #12 contains the total size of the APF program + data.
102  *      Slot #13 is filled with the IPv4 header length. This value is calculated
103  *               by loading the first byte of the IPv4 header and taking the
104  *               bottom 4 bits and multiplying their value by 4. This value is
105  *               set to zero if the first 4 bits after the link layer header are
106  *               not 4, indicating not IPv4.
107  *      Slot #14 is filled with size of the packet in bytes, including the
108  *               ethernet link-layer header.
109  *      Slot #15 is filled with the filter age in seconds. This is the number of
110  *               seconds since the host installed the program. This may
111  *               be used by filters that should have a particular lifetime. For
112  *               example, it can be used to rate-limit particular packets to one
113  *               every N seconds.
114  *  Special jump targets:
115  *    When an APF program executes a jump to the byte immediately after the last
116  *      byte of the progam (i.e., one byte past the end of the program), this
117  *      signals the program has completed and determined the packet should be
118  *      passed to the AP.
119  *    When an APF program executes a jump two bytes past the end of the program,
120  *      this signals the program has completed and determined the packet should
121  *      be dropped.
122  *  Jump if byte sequence doesn't match:
123  *    This is a special instruction to facilitate matching long sequences of
124  *    bytes in the packet. Initially it is encoded like a conditional jump
125  *    instruction with two exceptions:
126  *      The first byte of the instruction is always followed by two immediate
127  *        fields: The first immediate field is the jump target offset like other
128  *        conditional jump instructions. The second immediate field specifies the
129  *        number of bytes to compare.
130  *      These two immediate fields are followed by a sequence of bytes. These
131  *        bytes are compared with the bytes in the packet starting from the
132  *        position specified by the value of the register specified by the
133  *        "register" field of the instruction.
134  */
135 
136 // Number of temporary memory slots, see ldm/stm instructions.
137 #define MEMORY_ITEMS 16
138 // Upon program execution, some temporary memory slots are prefilled:
139 
140 typedef union {
141   struct {
142     u32 pad[8];               // 0..7
143     u32 apf_version;          // 8:  Initialized with apf_version()
144     u32 filter_age_16384ths;  // 9:  Age since filter installed in 1/16384 seconds.
145     u32 tx_buf_offset;        // 10: Offset in tx_buf where next byte will be written
146     u32 program_size;         // 11: Size of program (in bytes)
147     u32 ram_len;              // 12: Total size of program + data, ie. ram_len
148     u32 ipv4_header_size;     // 13: 4*([APF_FRAME_HEADER_SIZE]&15)
149     u32 packet_size;          // 14: Size of packet in bytes.
150     u32 filter_age;           // 15: Age since filter installed in seconds.
151   } named;
152   u32 slot[MEMORY_ITEMS];
153 } memory_type;
154 
155 /* ---------------------------------------------------------------------------------------------- */
156 
157 // Standard opcodes.
158 
159 /* Unconditionally pass (if R=0) or drop (if R=1) packet and optionally increment counter.
160  * An optional non-zero unsigned immediate value can be provided to encode the counter number.
161  * The counter is located (-4 * counter number) bytes from the end of the data region.
162  * It is a U32 big-endian value and is always incremented by 1.
163  * This is more or less equivalent to: lddw R0, -4*N; add R0, 1; stdw R0, -4*N; {pass,drop}
164  * e.g. "pass", "pass 1", "drop", "drop 1"
165  */
166 #define PASSDROP_OPCODE 0
167 
168 #define LDB_OPCODE 1    // Load 1 byte  from immediate offset, e.g. "ldb R0, [5]"
169 #define LDH_OPCODE 2    // Load 2 bytes from immediate offset, e.g. "ldh R0, [5]"
170 #define LDW_OPCODE 3    // Load 4 bytes from immediate offset, e.g. "ldw R0, [5]"
171 #define LDBX_OPCODE 4   // Load 1 byte  from immediate offset plus register, e.g. "ldbx R0, [5+R0]"
172 #define LDHX_OPCODE 5   // Load 2 bytes from immediate offset plus register, e.g. "ldhx R0, [5+R0]"
173 #define LDWX_OPCODE 6   // Load 4 bytes from immediate offset plus register, e.g. "ldwx R0, [5+R0]"
174 #define ADD_OPCODE 7    // Add, e.g. "add R0,5"
175 #define MUL_OPCODE 8    // Multiply, e.g. "mul R0,5"
176 #define DIV_OPCODE 9    // Divide, e.g. "div R0,5"
177 #define AND_OPCODE 10   // And, e.g. "and R0,5"
178 #define OR_OPCODE 11    // Or, e.g. "or R0,5"
179 #define SH_OPCODE 12    // Left shift, e.g. "sh R0, 5" or "sh R0, -5" (shifts right)
180 #define LI_OPCODE 13    // Load signed immediate, e.g. "li R0,5"
181 #define JMP_OPCODE 14   // Unconditional jump, e.g. "jmp label"
182 #define JEQ_OPCODE 15   // Compare equal and branch, e.g. "jeq R0,5,label"
183 #define JNE_OPCODE 16   // Compare not equal and branch, e.g. "jne R0,5,label"
184 #define JGT_OPCODE 17   // Compare greater than and branch, e.g. "jgt R0,5,label"
185 #define JLT_OPCODE 18   // Compare less than and branch, e.g. "jlt R0,5,label"
186 #define JSET_OPCODE 19  // Compare any bits set and branch, e.g. "jset R0,5,label"
187 #define JBSMATCH_OPCODE 20 // Compare byte sequence [R=0 not] equal, e.g. "jbsne R0,2,label,0x1122"
188                            // NOTE: Only APFv6+ implements R=1 'jbseq' version and multi match
189                            // imm1 is jmp target, imm2 is (cnt - 1) * 2048 + compare_len,
190                            // which is followed by cnt * compare_len bytes to compare against.
191                            // Warning: do not specify the same byte sequence multiple times.
192 #define EXT_OPCODE 21   // Immediate value is one of *_EXT_OPCODE
193 #define LDDW_OPCODE 22  // Load 4 bytes from data address (register + signed imm): "lddw R0, [5+R1]"
194                         // LDDW/STDW in APFv6+ *mode* load/store from counter specified in imm.
195 #define STDW_OPCODE 23  // Store 4 bytes to data address (register + signed imm): "stdw R0, [5+R1]"
196 
197 /* Write 1, 2 or 4 byte immediate to the output buffer and auto-increment the output buffer pointer.
198  * Immediate length field specifies size of write.  R must be 0.  imm_len != 0.
199  * e.g. "write 5"
200  */
201 #define WRITE_OPCODE 24
202 
203 /* Copy bytes from input packet/APF program/data region to output buffer and
204  * auto-increment the output buffer pointer.
205  * Register bit is used to specify the source of data copy.
206  * R=0 means copy from packet.
207  * R=1 means copy from APF program/data region.
208  * The source offset is stored in imm1, copy length is stored in u8 imm2.
209  * APFv6.1: if u8 imm2 is 0 then copy length is 256 + extra u8 imm3
210  * e.g. "pktcopy 0, 16" or "datacopy 0, 16"
211  */
212 #define PKTDATACOPY_OPCODE 25
213 
214 #define JNSET_OPCODE 26 // JSET with reverse condition (jump if no bits set)
215 
216 /* APFv6.1: Compare byte sequence [R=0 not] equal, e.g. "jbsptrne 22,16,label,<dataptr>"
217  * imm1 is jmp target
218  * imm2(u8) is offset [0..255] into packet
219  * imm3(u8) is (count - 1) * 16 + (compare_len - 1), thus both count & compare_len are in [1..16]
220  * which is followed by compare_len u8 'even offset' ptrs into max 526 byte data section to compare
221  * against - ie. they are multipied by 2 and have 3 added to them (to skip over 'datajmp u16')
222  * Warning: do not specify the same byte sequence multiple times.
223  */
224 #define JBSPTRMATCH_OPCODE 27
225 
226 /* APFv6.1: Bytecode optimized allocate | transmit instruction.
227  * R=1 -> allocate(266 + imm * 8)
228  * R=0 -> transmit
229  *   immlen=0 -> no checksum offload (transmit ip_ofs=255)
230  *   immlen>0 -> with checksum offload (transmit(udp) ip_ofs=14 ...)
231  *     imm & 7 | type of offload      | ip_ofs | udp | csum_start  | csum_ofs      | partial_csum |
232  *         0   | ip4/udp              |   14   |  X  | 14+20-8 =26 | 14+20   +6=40 |   imm >> 3   |
233  *         1   | ip4/tcp              |   14   |     | 14+20-8 =26 | 14+20  +10=44 |     --"--    |
234  *         2   | ip4/icmp             |   14   |     | 14+20   =34 | 14+20   +2=36 |     --"--    |
235  *         3   | ip4/routeralert/icmp |   14   |     | 14+20+4 =38 | 14+20+4 +2=40 |     --"--    |
236  *         4   | ip6/udp              |   14   |  X  | 14+40-32=22 | 14+40   +6=60 |     --"--    |
237  *         5   | ip6/tcp              |   14   |     | 14+40-32=22 | 14+40  +10=64 |     --"--    |
238  *         6   | ip6/icmp             |   14   |     | 14+40-32=22 | 14+40   +2=56 |     --"--    |
239  *         7   | ip6/routeralert/icmp |   14   |     | 14+40-32=22 | 14+40+8 +2=64 |     --"--    |
240  */
241 #define ALLOC_XMIT_OPCODE 28
242 
243 /* ---------------------------------------------------------------------------------------------- */
244 
245 // Extended opcodes.
246 // These all have an opcode of EXT_OPCODE and specify the actual opcode in the immediate field.
247 
248 #define LDM_EXT_OPCODE 0   // Load from temporary memory, e.g. "ldm R0,5"
249   // Values 0-15 represent loading the different temporary memory slots.
250 #define STM_EXT_OPCODE 16  // Store to temporary memory, e.g. "stm R0,5"
251   // Values 16-31 represent storing to the different temporary memory slots.
252 #define NOT_EXT_OPCODE 32  // Not, e.g. "not R0"
253 #define NEG_EXT_OPCODE 33  // Negate, e.g. "neg R0"
254 #define SWAP_EXT_OPCODE 34 // Swap, e.g. "swap R0,R1"
255 #define MOV_EXT_OPCODE 35  // Move, e.g. "move R0,R1"
256 
257 /* Allocate writable output buffer.
258  * R=0: register R0 specifies the length
259  * R=1: length provided in u16 imm2
260  * e.g. "allocate R0" or "allocate 123"
261  * On failure automatically executes 'pass 3'
262  */
263 #define ALLOCATE_EXT_OPCODE 36
264 
265 /* Transmit and deallocate the buffer (transmission can be delayed until the program
266  * terminates).  Length of buffer is the output buffer pointer (0 means discard).
267  * R=1 iff udp style L4 checksum
268  * u8 imm2 - ip header offset from start of buffer (255 for non-ip packets)
269  * u8 imm3 - offset from start of buffer to store L4 checksum (255 for no L4 checksum)
270  * u8 imm4 - offset from start of buffer to begin L4 checksum calculation (present iff imm3 != 255)
271  * u16 imm5 - partial checksum value to include in L4 checksum (present iff imm3 != 255)
272  * "e.g. transmit"
273  */
274 #define TRANSMIT_EXT_OPCODE 37
275 
276 /* Write 1, 2 or 4 byte value from register to the output buffer and auto-increment the
277  * output buffer pointer.
278  * e.g. "ewrite1 r0" or "ewrite2 r1"
279  */
280 #define EWRITE1_EXT_OPCODE 38
281 #define EWRITE2_EXT_OPCODE 39
282 #define EWRITE4_EXT_OPCODE 40
283 
284 /* Copy bytes from input packet/APF program/data region to output buffer and
285  * auto-increment the output buffer pointer.
286  * Register bit is used to specify the source of data copy.
287  * R=0 means copy from packet.
288  * R=1 means copy from APF program/data region.
289  * The source offset is stored in R0, copy length is stored in u8 imm2 or R1.
290  * APFv6.1: if u8 imm2 is 0 then copy length is 256 + extra u8 imm3.
291  * e.g. "epktcopy r0, 16", "edatacopy r0, 16", "epktcopy r0, r1", "edatacopy r0, r1"
292  */
293 #define EPKTDATACOPYIMM_EXT_OPCODE 41
294 #define EPKTDATACOPYR1_EXT_OPCODE 42
295 
296 /* Jumps if the UDP payload content (starting at R0) does [not] match one
297  * of the specified QNAMEs in question records, applying case insensitivity.
298  * SAFE version PASSES corrupt packets, while the other one DROPS.
299  * R=0/1 meaning 'does not match'/'matches'
300  * R0: Offset to UDP payload content
301  * imm1: Extended opcode
302  * imm2: Jump label offset
303  * imm3(u8): Question type (PTR/SRV/TXT/A/AAAA)
304  *   note: imm3 is instead u16 in '1' version
305  * imm4(bytes): null terminated list of null terminated LV-encoded QNAMEs
306  * e.g.: "jdnsqeq R0,label,0xc,\002aa\005local\0\0", "jdnsqne R0,label,0xc,\002aa\005local\0\0"
307  */
308 #define JDNSQMATCH_EXT_OPCODE 43
309 #define JDNSQMATCHSAFE_EXT_OPCODE 45
310 #define JDNSQMATCH1_EXT_OPCODE 55
311 #define JDNSQMATCHSAFE1_EXT_OPCODE 57
312 
313 /* Jumps if the UDP payload content (starting at R0) does [not] match one
314  * of the specified NAMEs in answers/authority/additional records, applying
315  * case insensitivity.
316  * SAFE version PASSES corrupt packets, while the other one DROPS.
317  * R=0/1 meaning 'does not match'/'matches'
318  * R0: Offset to UDP payload content
319  * imm1: Extended opcode
320  * imm2: Jump label offset
321  * imm3(bytes): null terminated list of null terminated LV-encoded NAMEs
322  * e.g.: "jdnsaeq R0,label,0xc,\002aa\005local\0\0", "jdnsane R0,label,0xc,\002aa\005local\0\0"
323  */
324 #define JDNSAMATCH_EXT_OPCODE 44
325 #define JDNSAMATCHSAFE_EXT_OPCODE 46
326 
327 /* Jumps if the UDP payload content (starting at R0) does [not] match one
328  * of the specified QNAMEs in question records, applying case insensitivity.
329  * The qtypes in the input packet can match either of the two supplied qtypes.
330  * SAFE version PASSES corrupt packets, while the other one DROPS.
331  * R=0/1 meaning 'does not match'/'matches'
332  * R0: Offset to UDP payload content
333  * imm1: Extended opcode
334  * imm2: Jump label offset
335  * imm3(u8): Question type1 (PTR/SRV/TXT/A/AAAA)
336  * imm4(u8): Question type2 (PTR/SRV/TXT/A/AAAA)
337  * imm5(bytes): null terminated list of null terminated LV-encoded QNAMEs
338  * e.g.: "jdnsqeq2 R0,label,A,AAAA,\002aa\005local\0\0",
339  *       "jdnsqne2 R0,label,A,AAAA,\002aa\005local\0\0"
340  */
341 #define JDNSQMATCH2_EXT_OPCODE 51
342 #define JDNSQMATCHSAFE2_EXT_OPCODE 53
343 
344 /* Jump if register is [not] one of the list of values
345  * R bit - specifies the register (R0/R1) to test
346  * imm1: Extended opcode
347  * imm2: Jump label offset
348  * imm3(u8): top 5 bits - number 'n' of following u8/be16/be32 values - 2
349  *        middle 2 bits - 1..4 length of immediates - 1
350  *        bottom 1 bit  - =0 jmp if in set, =1 if not in set
351  * imm4(n * 1/2/3/4 bytes): the *UNIQUE* values to compare against
352  */
353 #define JONEOF_EXT_OPCODE 47
354 
355 /* Specify length of exception buffer, which is populated on abnormal program termination.
356  * imm1: Extended opcode
357  * imm2(u16): Length of exception buffer (located *immediately* after the program itself)
358  */
359 #define EXCEPTIONBUFFER_EXT_OPCODE 48
360 
361 // Note: 51, 53, 55, 57 used up above for DNS matching
362 
363 // This extended opcode is used to implement PKTDATACOPY_OPCODE
364 #define PKTDATACOPYIMM_EXT_OPCODE 65536
365 
366 #define EXTRACT_OPCODE(i) (((i) >> 3) & 31)
367 #define EXTRACT_REGISTER(i) ((i) & 1)
368 #define EXTRACT_IMM_LENGTH(i) (((i) >> 1) & 3)
369 
370 #endif  // ANDROID_APF_APF_H
371