summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apf_interpreter.h6
-rw-r--r--apf_run.c4
-rw-r--r--disassembler.c60
-rw-r--r--v5/Android.bp19
-rw-r--r--v5/apf.h15
-rw-r--r--v5/apf_interpreter.c100
-rw-r--r--v5/apf_interpreter.h136
-rw-r--r--v5/test_buf_allocator.c15
8 files changed, 250 insertions, 105 deletions
diff --git a/apf_interpreter.h b/apf_interpreter.h
index 368ae04..1c8e7c9 100644
--- a/apf_interpreter.h
+++ b/apf_interpreter.h
@@ -37,9 +37,9 @@ extern "C" {
* begins at program + program_len and ends at program + ram_len - 1,
* as described in the following diagram:
*
- *     program         program + program_len    program + ram_len
- *        |    text section    | data section    |
- *    +--------------------+------------------------+
+ * program program + program_len program + ram_len
+ * | text section | data section |
+ * +--------------------+------------------------+
*
* @param program the program bytecode, followed by the writable data region.
* @param program_len the length in bytes of the read-only portion of the APF
diff --git a/apf_run.c b/apf_run.c
index d40172f..242a7bb 100644
--- a/apf_run.c
+++ b/apf_run.c
@@ -176,7 +176,7 @@ void packet_handler(int use_apf_v6_interpreter, uint8_t* program,
int ret;
if (use_apf_v6_interpreter) {
- ret = apf_run(program, program_len, ram_len, packet, packet_len,
+ ret = apf_run(NULL, program, program_len, ram_len, packet, packet_len,
filter_age);
} else {
ret = accept_packet(program, program_len, ram_len, packet, packet_len,
@@ -234,7 +234,7 @@ void file_handler(int use_apf_v6_interpreter, uint8_t* program,
int result;
if (use_apf_v6_interpreter) {
- result = apf_run(program, program_len, ram_len, apf_packet,
+ result = apf_run(NULL, program, program_len, ram_len, apf_packet,
apf_header.len, filter_age);
} else {
result = accept_packet(program, program_len, ram_len, apf_packet,
diff --git a/disassembler.c b/disassembler.c
index 6db8d7d..06a164b 100644
--- a/disassembler.c
+++ b/disassembler.c
@@ -113,6 +113,10 @@ uint32_t apf_disassemble(const uint8_t* program, uint32_t program_len,
const uint32_t opcode = EXTRACT_OPCODE(bytecode);
#define PRINT_OPCODE() \
print_opcode(opcode_names[opcode], output_buffer, output_buffer_len, offset)
+#define DECODE_IMM(value, length) \
+ for (uint32_t i = 0; i < (length) && pc < program_len; i++) \
+ value = (value << 8) | program[pc++]
+
const uint32_t reg_num = EXTRACT_REGISTER(bytecode);
// All instructions have immediate fields, so load them now.
const uint32_t len_field = EXTRACT_IMM_LENGTH(bytecode);
@@ -120,8 +124,7 @@ uint32_t apf_disassemble(const uint8_t* program, uint32_t program_len,
int32_t signed_imm = 0;
if (len_field != 0) {
const uint32_t imm_len = 1 << (len_field - 1);
- for (uint32_t i = 0; i < imm_len && pc < program_len; i++)
- imm = (imm << 8) | program[pc++];
+ DECODE_IMM(imm, imm_len);
// Sign extend imm into signed_imm.
signed_imm = imm << ((4 - imm_len) * 8);
signed_imm >>= (4 - imm_len) * 8;
@@ -193,10 +196,7 @@ uint32_t apf_disassemble(const uint8_t* program, uint32_t program_len,
ASSERT_RET_INBOUND(ret);
offset += ret;
} else {
- uint32_t cmp_imm_len = 1 << (len_field - 1);
- uint32_t i;
- for (i = 0; i < cmp_imm_len && pc < program_len; i++)
- cmp_imm = (cmp_imm << 8) | program[pc++];
+ DECODE_IMM(cmp_imm, 1 << (len_field - 1));
ret = snprintf(output_buffer + offset,
output_buffer_len - offset, "0x%x, ", cmp_imm);
ASSERT_RET_INBOUND(ret);
@@ -381,6 +381,32 @@ uint32_t apf_disassemble(const uint8_t* program, uint32_t program_len,
offset += ret;
break;
}
+ case EDATACOPY:
+ case EPKTCOPY: {
+ if (imm == EPKTCOPY) {
+ ret = print_opcode("pcopy", output_buffer,
+ output_buffer_len, offset);
+ } else {
+ ret = print_opcode("dcopy", output_buffer,
+ output_buffer_len, offset);
+ }
+ ASSERT_RET_INBOUND(ret);
+ offset += ret;
+ if (len_field > 0) {
+ const uint32_t imm_len = 1 << (len_field - 1);
+ uint32_t relative_offs = 0;
+ DECODE_IMM(relative_offs, imm_len);
+ uint32_t copy_len = 0;
+ DECODE_IMM(copy_len, 1);
+
+ ret = snprintf(
+ output_buffer + offset, output_buffer_len - offset,
+ "[r%u+%d], %d", reg_num, relative_offs, copy_len);
+ ASSERT_RET_INBOUND(ret);
+ offset += ret;
+ }
+ break;
+ }
default:
ret = snprintf(output_buffer + offset,
output_buffer_len - offset, "unknown_ext %u",
@@ -437,6 +463,28 @@ uint32_t apf_disassemble(const uint8_t* program, uint32_t program_len,
}
break;
}
+ case MEMCOPY_OPCODE: {
+ if (reg_num == 0) {
+ ret = print_opcode("pcopy", output_buffer, output_buffer_len,
+ offset);
+ } else {
+ ret = print_opcode("dcopy", output_buffer, output_buffer_len,
+ offset);
+ }
+ ASSERT_RET_INBOUND(ret);
+ offset += ret;
+ if (len_field > 0) {
+ uint32_t src_offs = imm;
+ uint32_t copy_len = 0;
+ DECODE_IMM(copy_len, 1);
+ ret =
+ snprintf(output_buffer + offset, output_buffer_len - offset,
+ "%d, %d", src_offs, copy_len);
+ ASSERT_RET_INBOUND(ret);
+ offset += ret;
+ }
+ break;
+ }
// Unknown opcode
default:
ret = snprintf(output_buffer + offset, output_buffer_len - offset,
diff --git a/v5/Android.bp b/v5/Android.bp
index 9dbfd9f..23bfa9c 100644
--- a/v5/Android.bp
+++ b/v5/Android.bp
@@ -18,9 +18,26 @@ package {
default_applicable_licenses: ["hardware_google_apf_license"],
}
+cc_defaults {
+ name: "apfv5_defaults",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Werror=implicit-fallthrough",
+ "-Werror=strict-prototypes",
+ "-Wnullable-to-nonnull-conversion",
+ "-Wsign-compare",
+ "-Wsign-conversion",
+ "-Wthread-safety",
+ "-Wunused-parameter",
+ "-Wuninitialized",
+ ],
+}
+
cc_library_static {
name: "libapf_v5",
- defaults: ["apf_defaults"],
+ defaults: ["apfv5_defaults"],
srcs: [
"apf_interpreter.c",
"test_buf_allocator.c"
diff --git a/v5/apf.h b/v5/apf.h
index e981593..b0b34af 100644
--- a/v5/apf.h
+++ b/v5/apf.h
@@ -159,6 +159,11 @@
#define LDDW_OPCODE 22 // Load 4 bytes from data address (register + simm): "lddw R0, [5+R1]"
#define STDW_OPCODE 23 // Store 4 bytes to data address (register + simm): "stdw R0, [5+R1]"
#define WRITE_OPCODE 24 // Write 1, 2 or 4 bytes imm to the output buffer, e.g. "WRITE 5"
+// Copy the data from input packet or APF data region to output buffer. Register bit is
+// used to specify the source of data copy: R=0 means copy from packet, R=1 means copy
+// from APF data region. The source offset is encoded in the first imm and the copy length
+// is encoded in the second imm. "e.g. MEMCOPY(R=0), 5, 5"
+#define MEMCOPY_OPCODE 25
// Extended opcodes. These all have an opcode of EXT_OPCODE
// and specify the actual opcode in the immediate field.
@@ -175,6 +180,16 @@
#define EWRITE1_EXT_OPCODE 38 // Write 1 byte from register to the output buffer, e.g. "EWRITE1 R0"
#define EWRITE2_EXT_OPCODE 39 // Write 2 bytes from register to the output buffer, e.g. "EWRITE2 R0"
#define EWRITE4_EXT_OPCODE 40 // Write 4 bytes from register to the output buffer, e.g. "EWRITE4 R0"
+// Copy the data from input packet to output buffer. The source offset is encoded as [Rx + second imm].
+// The copy length is encoded in the third imm. "e.g. EPKTCOPY [R0 + 5], 5"
+#define EPKTCOPY 41
+// Copy the data from APF data region to output buffer. The source offset is encoded as [Rx + second imm].
+// The copy length is encoded in the third imm. "e.g. EDATACOPY [R0 + 5], 5"
+#define EDATACOPY 42
+// It is executed as a jump, it tells how many bytes of the program regions
+// are used to store the data and followed by the actual data bytes.
+// "e.g. data 5, abcde"
+#define DATA_EXT_OPCODE 43
#define EXTRACT_OPCODE(i) (((i) >> 3) & 31)
#define EXTRACT_REGISTER(i) ((i) & 1)
diff --git a/v5/apf_interpreter.c b/v5/apf_interpreter.c
index 3cef719..6679c72 100644
--- a/v5/apf_interpreter.c
+++ b/v5/apf_interpreter.c
@@ -17,7 +17,7 @@
#include "apf_interpreter.h"
// TODO: Remove the dependency of the standard library and make the interpreter self-contained.
-#include <string.h> // For memcmp
+#include <string.h>// For memcmp
#include "apf.h"
@@ -32,6 +32,8 @@ extern void APF_TRACE_HOOK(uint32_t pc, const uint32_t* regs, const uint8_t* pro
} while (0)
#endif
+// Frame header size should be 14
+#define APF_FRAME_HEADER_SIZE 14
// Return code indicating "packet" should accepted.
#define PASS_PACKET 1
// Return code indicating "packet" should be dropped.
@@ -43,11 +45,17 @@ extern void APF_TRACE_HOOK(uint32_t pc, const uint32_t* regs, const uint8_t* pro
// superfluous ">= 0" with unsigned expressions generates compile warnings.
#define ENFORCE_UNSIGNED(c) ((c)==(uint32_t)(c))
-int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
- const uint8_t* packet, uint32_t packet_len,
- uint32_t filter_age) {
+uint32_t apf_version(void) {
+ return 20231214;
+}
+
+int apf_run(void* ctx, uint8_t* const program, const uint32_t program_len,
+ const uint32_t ram_len, const uint8_t* const packet,
+ const uint32_t packet_len, const uint32_t filter_age_16384ths) {
// Is offset within program bounds?
#define IN_PROGRAM_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < program_len)
+// Is offset within ram bounds?
+#define IN_RAM_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < ram_len)
// Is offset within packet bounds?
#define IN_PACKET_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < packet_len)
// Is access to offset |p| length |size| within data bounds?
@@ -58,6 +66,8 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
(p) + (size) >= (p)) // catch wraparounds
// Accept packet if not within program bounds
#define ASSERT_IN_PROGRAM_BOUNDS(p) ASSERT_RETURN(IN_PROGRAM_BOUNDS(p))
+// Accept packet if not within ram bounds
+#define ASSERT_IN_RAM_BOUNDS(p) ASSERT_RETURN(IN_RAM_BOUNDS(p))
// Accept packet if not within packet bounds
#define ASSERT_IN_PACKET_BOUNDS(p) ASSERT_RETURN(IN_PACKET_BOUNDS(p))
// Accept packet if not within data bounds
@@ -74,7 +84,7 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
memory[MEMORY_OFFSET_PROGRAM_SIZE] = program_len;
memory[MEMORY_OFFSET_DATA_SIZE] = ram_len;
memory[MEMORY_OFFSET_PACKET_SIZE] = packet_len;
- memory[MEMORY_OFFSET_FILTER_AGE] = filter_age;
+ memory[MEMORY_OFFSET_FILTER_AGE] = filter_age_16384ths >> 14;
ASSERT_IN_PACKET_BOUNDS(APF_FRAME_HEADER_SIZE);
// Only populate if IP version is IPv4.
if ((packet[APF_FRAME_HEADER_SIZE] & 0xf0) == 0x40) {
@@ -91,7 +101,22 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
// The output buffer pointer
uint8_t* allocated_buffer = NULL;
// The length of the output buffer
- uint32_t allocate_buffer_len = 0;
+ uint32_t allocated_buffer_len = 0;
+// Is access to offset |p| length |size| within output buffer bounds?
+#define IN_OUTPUT_BOUNDS(p, size) (ENFORCE_UNSIGNED(p) && \
+ ENFORCE_UNSIGNED(size) && \
+ (p) + (size) <= allocated_buffer_len && \
+ (p) + (size) >= (p))
+// Accept packet if not write within allocated output buffer
+#define ASSERT_IN_OUTPUT_BOUNDS(p, size) ASSERT_RETURN(IN_OUTPUT_BOUNDS(p, size))
+
+// Decode the imm length.
+#define DECODE_IMM(value, length) \
+ do { \
+ uint32_t i; \
+ for (i = 0; i < (length) && pc < program_len; i++) \
+ value = (value << 8) | program[pc++]; \
+ } while (0)
do {
APF_TRACE_HOOK(pc, registers, program, program_len, packet, packet_len, memory, ram_len);
@@ -113,11 +138,9 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
if (len_field != 0) {
const uint32_t imm_len = 1 << (len_field - 1);
ASSERT_FORWARD_IN_PROGRAM(pc + imm_len - 1);
- uint32_t i;
- for (i = 0; i < imm_len; i++)
- imm = (imm << 8) | program[pc++];
+ DECODE_IMM(imm, imm_len);
// Sign extend imm into signed_imm.
- signed_imm = imm << ((4 - imm_len) * 8);
+ signed_imm = (int32_t) (imm << ((4 - imm_len) * 8));
signed_imm >>= (4 - imm_len) * 8;
}
@@ -134,7 +157,7 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
offs += registers[1];
}
ASSERT_IN_PACKET_BOUNDS(offs);
- uint32_t load_size;
+ uint32_t load_size = 0;
switch (opcode) {
case LDB_OPCODE:
case LDBX_OPCODE:
@@ -178,9 +201,7 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
} else if (len_field != 0) {
uint32_t cmp_imm_len = 1 << (len_field - 1);
ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm_len - 1);
- uint32_t i;
- for (i = 0; i < cmp_imm_len; i++)
- cmp_imm = (cmp_imm << 8) | program[pc++];
+ DECODE_IMM(cmp_imm, cmp_imm_len);
}
switch (opcode) {
case JEQ_OPCODE:
@@ -249,7 +270,7 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
break;
}
case LI_OPCODE:
- REG = signed_imm;
+ REG = (uint32_t) signed_imm;
break;
case EXT_OPCODE:
if (
@@ -282,19 +303,20 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
break;
case ALLOC_EXT_OPCODE:
ASSERT_RETURN(allocated_buffer == NULL);
- allocate_buffer_len = REG;
- allocated_buffer = apf_allocate_buffer(allocate_buffer_len);
+ allocated_buffer_len = REG;
+ allocated_buffer =
+ apf_allocate_buffer(ctx, allocated_buffer_len);
ASSERT_RETURN(allocated_buffer != NULL);
memory[MEMORY_OFFSET_OUTPUT_BUFFER_OFFSET] = 0;
break;
case TRANS_EXT_OPCODE:
ASSERT_RETURN(allocated_buffer != NULL);
- uint32_t pkt_len =
- memory[MEMORY_OFFSET_OUTPUT_BUFFER_OFFSET];
+ uint32_t pkt_len = memory[MEMORY_OFFSET_OUTPUT_BUFFER_OFFSET];
// If pkt_len > allocate_buffer_len, it means sth. wrong
// happened and the allocated_buffer should be deallocated.
- if (pkt_len > allocate_buffer_len) {
+ if (pkt_len > allocated_buffer_len) {
apf_transmit_buffer(
+ ctx,
allocated_buffer,
0 /* len */,
0 /* dscp */);
@@ -302,11 +324,20 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
}
// TODO: calculate packet checksum and get dscp
apf_transmit_buffer(
+ ctx,
allocated_buffer,
pkt_len,
0 /* dscp */);
allocated_buffer = NULL;
break;
+ case DATA_EXT_OPCODE: {
+ ASSERT_FORWARD_IN_PROGRAM(pc + 1);
+ uint32_t skip_len = 0;
+ DECODE_IMM(skip_len, 2);
+ ASSERT_FORWARD_IN_PROGRAM(pc + skip_len - 1);
+ pc += skip_len;
+ break;
+ }
// Unknown extended opcode
default:
// Bail out
@@ -314,7 +345,7 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
}
break;
case LDDW_OPCODE: {
- uint32_t offs = OTHER_REG + signed_imm;
+ uint32_t offs = OTHER_REG + (uint32_t) signed_imm;
uint32_t size = 4;
uint32_t val = 0;
// Negative offsets wrap around the end of the address space.
@@ -330,7 +361,7 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
break;
}
case STDW_OPCODE: {
- uint32_t offs = OTHER_REG + signed_imm;
+ uint32_t offs = OTHER_REG + (uint32_t) signed_imm;
uint32_t size = 4;
uint32_t val = REG;
// Negative offsets wrap around the end of the address space.
@@ -346,6 +377,31 @@ int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
}
break;
}
+ case MEMCOPY_OPCODE: {
+ ASSERT_RETURN(allocated_buffer != NULL);
+ ASSERT_RETURN(len_field > 0);
+ uint32_t src_offs = imm;
+ uint32_t copy_len = 0;
+ DECODE_IMM(copy_len, 1);
+ uint32_t dst_offs = memory[MEMORY_OFFSET_OUTPUT_BUFFER_OFFSET];
+ ASSERT_IN_OUTPUT_BOUNDS(dst_offs, copy_len);
+ // reg_num == 0 copy from packet, reg_num == 1 copy from data.
+ if (reg_num == 0) {
+ ASSERT_IN_PACKET_BOUNDS(src_offs);
+ const uint32_t last_packet_offs = src_offs + copy_len - 1;
+ ASSERT_RETURN(last_packet_offs >= src_offs);
+ ASSERT_IN_PACKET_BOUNDS(last_packet_offs);
+ memmove(allocated_buffer + dst_offs, packet + src_offs,
+ copy_len);
+ } else {
+ ASSERT_IN_RAM_BOUNDS(src_offs + copy_len - 1);
+ memmove(allocated_buffer + dst_offs, program + src_offs,
+ copy_len);
+ }
+ dst_offs += copy_len;
+ memory[MEMORY_OFFSET_OUTPUT_BUFFER_OFFSET] = dst_offs;
+ break;
+ }
// Unknown opcode
default:
// Bail out
diff --git a/v5/apf_interpreter.h b/v5/apf_interpreter.h
index 461d3ee..6ef4cc9 100644
--- a/v5/apf_interpreter.h
+++ b/v5/apf_interpreter.h
@@ -24,93 +24,107 @@ extern "C" {
#endif
/**
- * Version of APF instruction set processed by apf_run().
- * Should be returned by wifi_get_packet_filter_info.
+ * Returns the max version of the APF instruction set supported by apf_run().
+ * APFv6 is a superset of APFv4. APFv6 interpreters are able to run APFv4 code.
*/
-uint32_t apf_version();
+uint32_t apf_version(void);
/**
- * Allocates a buffer for APF program to write the transmit packet.
- *
- * The implementations must always support allocating at least one 1500 bytes
- * buffer until it is effectively transmitted. Before passing a memory region
- * back to the caller, the implementations must zero it out.
- *
- * The firmware is responsible for freeing everything that was allocated by APF.
- * It is OK if the firmware decides only to limit allocations to at most one
- * response packet for every packet received by APF. In other words, while
- * processing a single received packet, it is OK for apf_allocate_buffer() to
- * succeed only once and return NULL after that.
- *
- * @param size the size of buffer to allocate, it should be the size of the
- * packet to be transmitted.
- * @return the pointer to the allocated region. The function can return null to
- * indicate the allocation failure due to not enough memory. This may
- * happened if there are too many buffers allocated that have not been
- * transmitted and deallocated yet.
+ * Allocates a buffer for the APF program to build a reply packet.
+ *
+ * Unless in a critical low memory state, the firmware must allow allocating at
+ * least one 1500 byte buffer for every call to apf_run(). The interpreter will
+ * have at most one active allocation at any given time, and will always either
+ * transmit or deallocate the buffer before apf_run() returns.
+ *
+ * It is OK if the firmware decides to limit allocations to at most one per
+ * apf_run() invocation.
+ *
+ * The firmware MAY choose to allocate a larger buffer than requested, and
+ * give the apf_interpreter a pointer to the middle of the buffer. This will
+ * allow firmware to later (during or after apf_transmit_buffer call) populate
+ * any required headers, trailers, etc.
+ *
+ * @param ctx - unmodified ctx pointer passed into apf_run().
+ * @param size - the minimum size of buffer to allocate
+ * @return the pointer to the allocated region. The function can return NULL to
+ * indicate allocation failure, for example if too many buffers are
+ * pending transmit. Returning NULL will most likely result in the
+ * apf_run() returning PASS.
*/
-uint8_t* apf_allocate_buffer(uint32_t size);
+uint8_t* apf_allocate_buffer(void* ctx, uint32_t size);
/**
- * Transmits the allocated buffer and deallocates the memory region.
+ * Transmits the allocated buffer and deallocates it.
*
- * The function is responsible to verify if the range [ptr, ptr + len) is within
- * the buffer it allocated for the program when apf_transmit_buffer() is called.
+ * The apf_interpreter will not read/write from/to the buffer once it calls
+ * this function.
*
- * The content of the buffer between [ptr, ptr + len) is the transmit packet
- * bytes, starting from the 802.3 header and not including any CRC bytes at the
- * end.
- *
- * The firmware must guarantee the transmit packet is not modified after the APF
- * calls the apf_transmit_buffer().
+ * The content of the buffer between [ptr, ptr + len) are the bytes to be
+ * transmitted, starting from the ethernet header and not including any
+ * CRC bytes at the end.
*
* The firmware is expected to make its best effort to transmit. If it
* exhausts retries, or if there is no channel for too long and the transmit
- * queue is full, then it is OK for the packet to be dropped.
- *
- * @param ptr pointer to the transmit buffer
- * @param len the length of buffer to be transmitted, 0 means don't transmit the
- * buffer but only deallocate it
- * @param dscp the first 6 bits of the TOS field in the IPv4 header or traffic
+ * queue is full, then it is OK for the packet to be dropped. The firmware should
+ * prefer to fail allocation if transmit is likely to fail.
+ *
+ * apf_transmit_buffer() should be asynchronous, which means the actual packet
+ * transmission can happen sometime after the function returns.
+ *
+ * @param ctx - unmodified ctx pointer passed into apf_run().
+ * @param ptr - pointer to the transmit buffer, must have been previously
+ * returned by apf_allocate_buffer and not deallocated.
+ * @param len - the number of bytes to be transmitted (possibly less than
+ * the allocated buffer), 0 means don't transmit the buffer
+ * but only deallocate it
+ * @param dscp - the upper 6 bits of the TOS field in the IPv4 header or traffic
* class field in the IPv6 header.
+ * @return non-zero if the firmware *knows* the transmit will fail, zero if
+ * the firmware thinks the transmit will succeed. Returning an error
+ * will likely result in apf_run() returning PASS.
*/
-void apf_transmit_buffer(uint8_t *ptr, uint32_t len, uint8_t dscp);
+int apf_transmit_buffer(void* ctx, uint8_t* ptr, uint32_t len, uint8_t dscp);
/**
- * Runs a packet filtering program over a packet.
+ * Runs an APF program over a packet.
*
- * The return value of the apf_run indicates whether the packet should be
- * passed to AP or not. As a part of apf_run execution, the packet filtering
+ * The return value of apf_run indicates whether the packet should
+ * be passed or dropped. As a part of apf_run execution, the APF
* program can call apf_allocate_buffer()/apf_transmit_buffer() to construct
- * an egress packet to transmit it.
+ * a reply packet and transmit it.
*
* The text section containing the program instructions starts at address
* program and stops at + program_len - 1, and the writable data section
* begins at program + program_len and ends at program + ram_len - 1,
* as described in the following diagram:
*
- *     program         program + program_len    program + ram_len
- *        |    text section    | data section    |
- *    +--------------------+------------------------+
+ * program program + program_len program + ram_len
+ * | text section | data section |
+ * +--------------------+------------------------+
*
- * @param program the program bytecode, followed by the writable data region.
- * @param program_len the length in bytes of the read-only portion of the APF
+ * @param ctx - pointer to any additional context required for allocation and transmit.
+ may be null if no such context is required. this is opaque to
+ the interpreter and will be passed through unmodified
+ to apf_allocate_buffer() and apf_transmit_buffer() calls.
+ * @param program - the program bytecode, followed by the writable data region.
+ * @param program_len - the length in bytes of the read-only portion of the APF
* buffer pointed to by {@code program}.
- * @param ram_len total length of the APF buffer pointed to by {@code program},
- * including the read-only bytecode portion and the read-write
- * data portion.
- * @param packet the packet bytes, starting from the 802.3 header and not
- * including any CRC bytes at the end.
- * @param packet_len the length of {@code packet} in bytes.
- * @param filter_age the number of seconds since the filter was programmed.
- *
- * @return non-zero if packet should be passed to AP, zero if
- * packet should be dropped. Return 1 indicating the packet is accepted
- * without error. Negative return values are reserved for error code.
+ * @param ram_len - total length of the APF buffer pointed to by
+ * {@code program}, including the read-only bytecode
+ * portion and the read-write data portion.
+ * @param packet - the packet bytes, starting from the ethernet header.
+ * @param packet_len - the length of {@code packet} in bytes, not
+ * including trailers/CRC.
+ * @param filter_age_16384ths - the number of 1/16384 seconds since the filter
+ * was programmed.
+ *
+ * @return non-zero if packet should be passed, zero if packet should
+ * be dropped.
*/
-int apf_run(uint8_t* program, uint32_t program_len, uint32_t ram_len,
- const uint8_t* packet, uint32_t packet_len,
- uint32_t filter_age);
+int apf_run(void* ctx, uint8_t* const program, const uint32_t program_len,
+ const uint32_t ram_len, const uint8_t* const packet,
+ const uint32_t packet_len, const uint32_t filter_age_16384ths);
#ifdef __cplusplus
}
diff --git a/v5/test_buf_allocator.c b/v5/test_buf_allocator.c
index 1358063..a889dea 100644
--- a/v5/test_buf_allocator.c
+++ b/v5/test_buf_allocator.c
@@ -25,18 +25,11 @@ uint32_t apf_test_tx_packet_len;
uint8_t apf_test_tx_dscp;
/**
- * Test implementation of apf_version()
- */
-uint32_t apf_version() {
- return 5;
-}
-
-/**
* Test implementation of apf_allocate_buffer()
*
* Clean up the apf_test_buffer and return the pointer to beginning of the buffer region.
*/
-uint8_t* apf_allocate_buffer(uint32_t size) {
+uint8_t* apf_allocate_buffer(__attribute__ ((unused)) void* ctx, uint32_t size) {
if (size > APF_TX_BUFFER_SIZE) {
return NULL;
}
@@ -49,8 +42,10 @@ uint8_t* apf_allocate_buffer(uint32_t size) {
*
* Copy the content of allocated buffer to the apf_test_tx_packet region.
*/
-void apf_transmit_buffer(uint8_t* ptr, uint32_t len, uint8_t dscp) {
+int apf_transmit_buffer(__attribute__((unused)) void* ctx, uint8_t* ptr,
+ uint32_t len, uint8_t dscp) {
apf_test_tx_packet_len = len;
apf_test_tx_dscp = dscp;
- memcpy(apf_test_tx_packet, ptr, len);
+ memcpy(apf_test_tx_packet, ptr, (size_t) len);
+ return 0;
}