Android 数据包过滤器

借助 Android 数据包过滤器 (APF),框架可以在运行时控制硬件数据包过滤逻辑。这样一来,系统就可以通过丢弃硬件中的数据包来节省电量,同时允许 Android 框架在运行时根据网络条件更改过滤规则。

APF 概览

APF 包含两个主要组件:

  • APF 解释器:在网络硬件(通常是 Wi-Fi 芯片组)上运行。APF 解释器会对硬件收到的数据包运行 APF 字节码,据此决定是接受、丢弃还是回复这些数据包。
  • APF 程序生成代码:在主 CPU 上运行。该代码会根据网络状态和设备状态创建和更新 APF 程序。

Wi-Fi HAL 方法允许 Android 框架安装 APF 程序字节码并读取当前计数器。网络栈 Mainline 模块可在 APF 运行期间随时更新 APF 程序字节码。

现已实现多种 APF 过滤器。例如,APF 包含用于以下用途的过滤器:丢弃不被允许的以太类型;过滤 IPv6 路由器通告 (RA) 数据包;在多播未锁定时过滤多播和广播流量;丢弃其他主机的 DHCP 数据包;丢弃主动发送的地址解析协议 (ARP) 和邻居发现 (ND) 数据包。如果固件支持 APFv6,ApfFilter 还会生成规则来回复常见的数据包类型,否则需要 CPU 唤醒才能做出响应,例如 ARP 查询和 NS 查询。过滤器的完整列表在 ApfFilter 中定义。

由于 APF 程序生成代码是网络栈模块的一部分,因此您可以使用每月 [Mainline 更新] 来添加新的过滤器和更新过滤逻辑。

APF 修订记录

以下列表介绍了 APF 的修订历史记录:

  • APF6:此版本在 Android 15 中引入,支持数据包过滤,包含用于调试和指标的计数器,并支持数据包传输。
  • APFv4:此版本在 Android 10 中引入,支持数据包过滤,并包含用于调试和指标的计数器。
  • APFv2:此版本在 Android 7 中引入,支持数据包过滤。

APF 集成

APF 解释器与硬件之间的 APF API 在 apf_interpreter.h 中定义(APFv4APFv6)。Wi-Fi 固件代码会在 APFv4 中调用 accept_packet(),在 APFv6 中调用 apf_run(),以确定是丢弃数据包(返回值为零)还是将数据包传递给应用处理器(返回非零值)。如果需要传输数据包,apf_run() 也会返回零,因为其数据包不需要传递给应用处理器。如果固件支持 APFv6,则必须实现 apf_allocate_buffer() API 和 apf_transmit_buffer() API。APF 解释器会在执行数据包传输逻辑过程中调用这两个 API。APF 指令的长度可变。每条指令的长度应至少为 1 个字节。对于 APFv4,APF 指令代码在 apf.h 中定义;对于 APFv6,APF 指令代码直接内嵌在 apf_interpreter.c 中。

APF 依赖于专用内存。该内存既用于 APF 程序本身,又用于数据存储。此外,芯片组不得清除或写入内存,使用 APF HAL 方法时除外。APF 字节码使用数据存储区来存储接受和丢弃的数据包的计数器。数据区域可从 Android 框架中读取。APF 指令的内存效率很高,但要最大限度地提高其节能和功能方面的潜力,就需要设计复杂的动态过滤规则。而要解决这种复杂性,就需要在芯片组上分配一部分专用内存。APFv4 的内存要求下限为 1024 字节,而 APFv6 则需要 2048 字节。不过,我们强烈建议为 APFv6 分配 4096 字节,以确保实现最佳性能。APF 解释器必须编译到固件中。APFv4 解释器和 APFv6 解释器都针对代码大小进行了优化。在 arm32 架构下,编译后的 APFv4 解释器大约为 1.8 KB,而更为复杂的 APFv6 解释器(具有额外的功能,例如原生校验和支持、原生 DNS 解压缩代码)大约为 4 KB。

APF 过滤器可以与固件中的其他芯片组供应商专用过滤器一起使用。芯片组供应商可以选择在 APF 过滤流程之前或之后运行其自己的过滤逻辑。如果某个数据包在到达 APF 过滤器之前就丢失,APF 过滤器不会处理该数据包。

为确保 APF 过滤器正常运行,在 APF 处于启用状态时,固件必须向 APF 过滤器提供对整个数据包(而不仅仅是头文件)的访问权限。

APF 程序示例

ApfTestApfFilterTest 包含用于说明每个 APF 过滤器如何运作的示例测试程序。如需研究实际生成的程序,请修改测试用例,以将程序输出为十六进制字符串。

testdata 文件夹包含适用于 APF RA 过滤器的 APFv4 示例程序。samples 文件夹包含用于生成 APFv6 分流程序的 Python 实用程序。如需了解详情,请参阅 Python 实用程序文件中的文档。

调试 APF

如需检查设备上是否启用了 APF,请显示当前程序和当前计数器,然后运行 adb shell dumpsys network_stack 命令。以下是此命令的示例:

adb shell dumpsys network_stack
......
IpClient.wlan0 APF dump:
    Capabilities: ApfCapabilities{version: 4, maxSize: 4096, format: 1}
......
    Last program:
      6bfcb03a01b8120c6b9494026506006b907c025e88a27c025988a47c025488b87c024f88cd7c024a88e17c024588e384004408066a0e6bdca4022b000600010800060412147a1e016bd884021f00021a1c6b8c7c021c0000686bd4a402080006ffffffffffff6a266bbca402010004c0a801eb6bf87401f6120c84005f08000a17821f1112149c00181fffab0d2a108211446a3239a20506c2fc393057dd6bf47401cb0a1e52f06bac7c01c600e06bb41a1e7e000001b9ffffffff6bb07e000001aec0a801ff6be868a4019a0006ffffffffffff6bb874019b6bf07401907c001386dd686bd0a4017d0006ffffffffffff6bc874017e0a147a0e3a6b980a267c017000ff6be07401650a366ba87c016200858219886a26a2050fff02000000000000000000000000006ba4740146aa0e84013700e6aa0f8c0130006068a4011b000f33330000000184c9b26aed4c86dd606a12a2f02600b03afffe8000000000000086c9b2fffe6aed4cff02000000000000000000000000000186006a3aa2e9024000123c92e4606a3ea2d70800000000000000006a56a2ce04030440c01a5a92c9601a5e92c4606a62a2bb04000000006a66a2a6102401fa00049c048400000000000000006a76a29d04030440c01a7a9298601a7e9293606c0082a28904000000006c0086a27310fdfd9ed67950000400000000000000006c0096a2690418033c001a9a9264606c009ea24e102401fa00049c048000000000000000006c00aea24404180330001ab2923f606c00b6a22910fdfd9ed67950000000000000000000006c00c6a21f04190300001aca921a606c00cea20410fdfd9ed67950000400000000000000016bc472086be4b03a01b87206b03a01b87201
    APF packet counters:
      TOTAL_PACKETS: 469
      PASSED_DHCP: 4
      PASSED_IPV4: 65
      PASSED_IPV6_NON_ICMP: 64
      PASSED_IPV4_UNICAST: 64
      PASSED_IPV6_ICMP: 223
      PASSED_IPV6_UNICAST_NON_ICMP: 6
      PASSED_ARP_UNICAST_REPLY: 4
      PASSED_NON_IP_UNICAST: 1
      DROPPED_RA: 4
      DROPPED_IPV4_BROADCAST_ADDR: 7
      DROPPED_IPV4_BROADCAST_NET: 27

此示例 adb shell dumpsys network_stack 命令的输出内容包括:

  • ApfCapabilities{version: 4, maxSize: 4096, format: 1}:这表示 Wi-Fi 芯片支持 APF(版本 4)。
  • Last program:此部分是采用十六进制字符串格式、最新安装的 APF 程序二进制文件。
  • APF packet counters:此部分显示 APF 传递或丢弃的数据包数量以及具体原因。

如需将代码进行解码和反汇编,将其转换为人类可读的汇编程序语言,请使用 apf_disassembler 工具。如需编译可执行二进制文件,请运行 m apf_disassembler 命令。 以下示例展示了如何使用 apf_disassembler 工具:

echo "6bfcb03a01b8120c6b949401e906006b907c01e288a27c01dd88a47c01d888b87c01d388cd7c01ce88e17c01c988e384004008066a0e6bdca401af000600010800060412147a1e016bd88401a300021a1c6b8c7c01a00000686bd4a4018c0006ffffffffffff1a266bc07c018900006bf874017e120c84005408000a17821f1112149c00181fffab0d2a108211446a3239a205065a56483ac3146bf47401530a1e52f06bac7c014e00e06bb41a1e7e00000141ffffffff6be868a4012d0006ffffffffffff6bb874012e6bf07401237c001386dd686bd0a401100006ffffffffffff6bc87401110a147a0d3a6b980a267c010300ff6be072f90a366ba87af8858218886a26a2040fff02000000000000000000000000006ba472ddaa0e82d0aeaa0f8c00c9025868a2b60f5a56483ac3140c8126f3895186dd606a12a28b2600783afffe8000000000000002005efffe00026fff02000000000000000000000000000186006a3aa284024000123c94007d02586a3ea2700800000000000000006a56a26704190500001a5a94006002586a5ea23b2020014860486000000000000000006464200148604860000000000000000000646a7ea23204030440c01a8294002b02581a8694002402586c008aa21a04000000006c008ea204102a0079e10abcf60500000000000000006bc472086be4b03a01b87206b03a01b87201" | out/host/linux-x86/bin/apf_disassembler
       0: li    r1, -4
       2: lddw  r0, [r1+0]
       3: add   r0, 1
       5: stdw  r0, [r1+0]
       6: ldh   r0, [12]
       8: li    r1, -108
      10: jlt   r0, 0x600, 504
      15: li    r1, -112
      17: jeq   r0, 0x88a2, 504
      22: jeq   r0, 0x88a4, 504
      27: jeq   r0, 0x88b8, 504
      32: jeq   r0, 0x88cd, 504
      37: jeq   r0, 0x88e1, 504
      42: jeq   r0, 0x88e3, 504
      47: jne   r0, 0x806, 116
......

如需离线检查 APF 结果,请使用 apf_run 工具。如需编译可执行二进制文件,请运行 m apf_run 命令。apf_run 工具既支持 APFv4 解释器,也支持 APFv6 解释器。

以下是 apf_run 命令的手册。默认情况下,apf_run 命令在 APFv4 解释器中运行。将 --v6 参数传递给 apf_run 可让其对应 APFv6 解释器运行。所有其他参数既可用于 APFv4,又可用于 APFv6。

apf_run --help
Usage: apf_run --program <program> --pcap <file>|--packet <packet> [--data <content>] [--age <number>] [--trace]
  --program    APF program, in hex.
  --pcap       Pcap file to run through program.
  --packet     Packet to run through program.
  --data       Data memory contents, in hex.
  --age        Age of program in seconds (default: 0).
  --trace      Enable APF interpreter debug tracing
  --v6         Use APF v6
  -c, --cnt    Print the APF counters
  -h, --help   Show this message.

下面这个示例会将一个数据包传递给 APF,以检查该数据包是否可以丢弃或传递。

如需提供原始数据包的十六进制/二进制字符串呈现方式,请使用 --packet 选项。如需提供数据区域的十六进制/二进制字符串(用于存储 APF 计数器),请使用 --data option。由于每个计数器的长度为 4 个字节,因此数据区域必须足够长,以免发生缓冲区溢出。

out/host/linux-x86/bin/apf_run --program 6bfcb03a01b8120c6b9494010c06006b907c010588a27c010088a47c00fb88b87c00f688cd7c00f188e17c00ec88e384003908066a0e6bdca2d40600010800060412147a18016bd882ca021a1c6b8c7ac900686bd4a2b706ffffffffffff6a266bbca2b204c0a814656bf872a8120c84005808000a17821e1112149c00171fffab0d2a108210446a3239a204064651dbcc88ff6bf4727e0a1e52f06bac7a7be06bb41a1e7e0000006effffffff6bb07e00000063c0a814ff6be868a25106ffffffffffff6bb872536bf072497c001086dd686bd0a23806ffffffffffff6bc8723a0a147a0b3a6b980a267a2eff6be072240a366ba87a23858218886a26a2040fff02000000000000000000000000006ba472086be4b03a01b87206b03a01b87201 --packet 5ebcd79a8f0dc244efaab81408060001080006040002c244efaab814c0a8ca1e5ebcd79a8f0d --data 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Packet passed
Data: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001

如需对照由 tcpdump 抓取的 pcap 文件来检查 APF 结果,请使用 apf_run 命令,如下所示:

out/host/linux-x86/bin/apf_run --program 6bfcb03a01b8120c6b989401df06006b947c01d888a27c01d388a47c01ce88b87c01c988cd7c01c488e17c01bf88e384004408066a0e6bdca401a5000600010800060412147a1e016bd884019900021a1c6b907c01960000686bd4a401820006ffffffffffff6a266bc0a4017b0004c0a82b056bf874017084005f08000a17821f1112149c00181fffab0d2a108211446a3239a20506fabe589435936bf47401470a1e52f06bb07c014200e06bb81a1e7e00000135ffffffff6bb47e0000012ac0a82bff6be868a401160006ffffffffffff6bbc7401176bf074010c7c001086dd686bd0a2fb06ffffffffffff6bcc72fd0a147a0b3a6b9c0a267af1ff6be072e70a366bac7ae6858218886a26a2040fff02000000000000000000000000006ba872cbaa0e82be8eaa0f8c00b7025868a2a40ffabe5894359352a9874d08aa86dd606a12a2792600583afffe80000000000000f7d4e8ccd81ddb43fe80000000000000f8be58fffe94359386006a3aa272024108123c94006b02586a3ea25e0800000000000000006a56a25504030440c01a5a94004e02581a5e94004702586a62a23e04000000006a66a229102409891f9a26ae6d00000000000000006a76a22004190300001a7a94001902586a7ea204102409891f9a26ae6dba98e781ca9ef9ba6bc872086be4b03a01b87206b03a01b87201 --pcap apf.pcap --data 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
37 packets dropped
1733 packets passed
Data: 00000000000000000000000000000000000000000200000005000000000000000000000002000000000000001b000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000689000000000000003c00000000000000000000000000000000000006ea

如需测试 APFv6 传输功能,请使用 apf_run 命令,如下所示:

$ apf_run --program 75001001020304050608060001080006040002AA300E3CAA0FBA06AA09BA07AA08BA086A01BA09120C84006F08066A0EA30206000108000604032B12147A27017A020203301A1C820200032D68A30206FFFFFFFFFFFF020E1A267E000000020A000001032C020B1A267E000000020A000001032CAB24003CCA0606CB0306CB090ACB0306C60A000001CA0606CA1C04AA
0A3A12AA1AAA25FFFF032F020D120C84001708000A1782100612149C00091FFFAB0D2A10820207032A02117C000E86DD68A30206FFFFFFFFFFFF021603190A1482020002187A023A02120A36820285031F8216886A26A2020FFF020000000000000000000000000003200214 --packet FFFFFFFFFFFF112233445566080600010800060400011122334455660A0000020000000000000A0000
01 --data 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 --age 0 --v6 --trace
      R0       R1       PC  Instruction
-------------------------------------------------
       0        0        0: data        16, 01020304050608060001080006040002
       0        0       19: debugbuf    size=3644
       0        0       23: ldm         r0, m[15]
       0        0       25: stdw        counter=6, r0
       0        0       27: ldm         r0, m[9]
       0        0       29: stdw        counter=7, r0
       0        0       31: ldm         r0, m[8]
 134d811        0       33: stdw        counter=8, r0
 134d811        0       35: li          r0, 1
       1        0       37: stdw        counter=9, r0
       1        0       39: ldh         r0, [12]
     806        0       41: jne         r0, 0x806, 157
     806        0       46: li          r0, 14
       e        0       48: jbseq       r0, 0x6, 59, 000108000604
       e        0       59: ldh         r0, [20]
       1        0       61: jeq         r0, 0x1, 103
       1        0      103: ldw         r0, [38]
 a000001        0      105: jeq         r0, 0xa000001, 116
 a000001        0      116: allocate    60
 a000001        0      120: pktcopy     src=6, len=6
 a000001        0      123: datacopy    src=3, len=6
 a000001        0      126: datacopy    src=9, len=10
 a000001        0      129: datacopy    src=3, len=6
 a000001        0      132: write       0x0a000001
 a000001        0      137: pktcopy     src=6, len=6
 a000001        0      140: pktcopy     src=28, len=4
 a000001        0      143: ldm         r0, m[10]
      2a        0      145: add         r0, 18
      3c        0      147: stm         r0, m[10]
      3c        0      149: transmit    ip_ofs=255
      3c        0      153: drop        counter=47
Packet dropped
Data: 00000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000100000011d8340100000000000000000000000000000000000000000100000078563412
transmitted packet: 112233445566010203040506080600010800060400020102030405060a0000011122334455660a000002000000000000000000000000000000000000

使用 --trace 参数时,apf_run 工具会提供解释器执行过程中每一步的详细输出,这有助于调试。在此示例中,我们向 APF 程序输入 ARP 查询数据包。输出显示 ARP 查询已被丢弃,但生成了回复数据包。生成的这个数据包的详细信息显示在 transmitted packet 部分中。

有关集成的常见问题

本部分重点介绍了 APF 集成过程中可能会遇到的一些常见问题:

  • 意外的数据区域清除:APF 内存必须完全专用于 APF;只有解释器代码或框架代码(通过 HAL API)才能修改 APF 内存区域。
  • X 个字节(X <= maxLen)的 APF 程序的安装问题:固件必须支持读取或写入长度不超过 maxLen 的任何程序,且不会失败、崩溃或截断。写入操作不得更改 XmaxLen 之间的任何字节。
  • 驱动程序代码中的 APF 实现:APF 应仅在固件中实现,而非在驱动程序代码中实现。否则,就体现不出其节省电量的优势,因为 CPU 需要唤醒才能处理数据包。
  • filter_agefilter_age_16384th 值不正确:filter_age (APFv4) 和 filter_age_16384th (APFv6) 值必须正确传递给 accept_packet()apf_run() 函数。如需详细了解如何计算 filter_age_16384th,请参阅 apf_interpreter.h 的文档。
  • 未在需要时启用 APF:当屏幕处于关闭状态且 Wi-Fi 链路空闲或流量低于 10 Mbps 时,必须启用 APF。
  • 传递给 accept_packet()apf_run() 的数据包被截断:传递给 accept_packet()apf_run() 的所有单播、广播和多播数据包都必须是完整的。将截断的数据包传递到 APF 是无效的。

APF 测试

从 Android 15 开始,Android 为 APF 过滤器和 APF 解释器集成提供了单设备和多设备 CTS 测试用例,以确保 APF 功能正确无误。下面拆解了每个测试用例的用途:

  • ApfFilterapf_interpreter 集成测试:验证 ApfFilter 是否生成正确的字节码,以及 apf_interpreter 是否正确执行代码并生成预期结果。
  • APF 单设备 CTS使用单个设备在 Wi-Fi 芯片组上测试 APF 功能。确认:
    • 当屏幕开启且 Wi-Fi 流量低于 10 Mbps 时,APF 会开启。
    • APF 功能声明正确无误。
    • 对 APF 内存区域执行的读写操作成功执行,并且内存区域不会意外修改。
    • 参数正确地传递给 accept_packet()apf_run()
    • 与 APFv4/APFv6 集成的固件可以丢弃数据包。
    • 与 APFv6 集成的固件可以回复数据包。
  • APF 多设备 CTS使用两台设备(一台发送设备,一台接收设备)来测试 APF 的过滤行为。在发送端生成各种类型的数据包,并根据在 ApfFilter 中配置的规则确认这些数据包是否正确丢弃、传递或回复。

其他集成测试说明

此外,我们强烈建议芯片组供应商将 APF 测试纳入其自己的固件 Wi-Fi 集成测试套件中。

将 APF 测试集成到固件 Wi-Fi 集成测试套件中对于在复杂的 Wi-Fi 连接场景(例如 make-before-break 或漫游 Wi-Fi 连接场景)中验证适当的 APF 功能至关重要。有关如何执行集成测试的详细说明,请参阅以下部分。

前提条件

执行集成测试时,请执行以下操作:

  • 必须在所有集成测试用例(例如漫游、make-before-break)中启用 APF。
  • 在每次测试开始时,清除 APF 内存。
  • 在测试期间,每 5 分钟安装或重新安装 APF 程序一次。

测试场景

在整个集成测试过程中,APF 必须处于活跃状态。本文档中提供了两个可在测试期间安装的 APF 程序。程序采用十六进制字符串格式,测试人员必须将十六进制字符串转换为二进制字符串并将其安装到固件中,以使 apf_interpreter 能够执行这些程序。在集成测试期间,测试人员应发送按预期会触发程序 1 和程序 2 中的过滤逻辑的数据包。

APF 程序 1

当设备屏幕开启时,安装 APF 程序 1。此程序可以丢弃不会影响设备功能的无害数据包。这些数据包用于测试 APF 是否能正确过滤网络流量。

APF 程序 1 的逻辑如下:

  1. 丢弃数据包并递增计数器:
    1. 以太类型值:0x88A20x88A40x88B80x88CD0x88E10x88E3
    2. IPv4 DHCP 探测或请求数据包
    3. RS 数据包
  2. 传递数据包并递增计数器:所有其他数据包。

APF 程序 1 的字节代码如下:

6BF0B03A01B86BF8AA0FB86BF4AA09B8120C6BEC7C005D88A27C005888A47C005388B87C004E88CD7C004988E17C004488E3120C84002008001A1A821B001A1E8600000010FFFFFFFF0A17820B11AB0D2A108204436BE8721D120C84000E86DD0A1482093A0A368204856BE072086BDCB03A01B87206B03A01B87201
APF 程序 2

当设备屏幕关闭时,安装 APF 程序 2。此程序会滤除 APF 程序 1 滤出的所有数据包,以及 ping 请求数据包。如需验证 APF 程序 2 是否已正确安装,请向受测设备发送 ping 数据包。

APF 程序 2 的逻辑如下:

  1. 丢弃数据包并递增计数器:
    1. 以太类型值:0x88A20x88A40x88B80x88CD0x88E10x88E3
    2. IPv4 DHCP 探测或请求数据包
    3. RS 数据包
  2. 丢弃数据包并递增计数器:ICMP ping 请求数据包
  3. 传递数据包并递增计数器:所有其他数据包

APF 程序 2 的字节代码如下:

6BF0B03A01B86BF8AA0FB86BF4AA09B8120C6BEC7C007488A27C006F88A47C006A88B87C006588CD7C006088E17C005B88E3120C84002008001A1A821B001A1E8600000010FFFFFFFF0A17820B11AB0D2A108204436BE87234120C84000E86DD0A1482093A0A368204856BE0721F120C84001008000A17820B01AB0D220E8204086BE472086BDCB03A01B87206B03A01B87201
数据验证

如需验证 APF 程序是否已执行,以及数据包是否已正确传递或丢弃,请执行以下操作:

  • 每隔 5 分钟提取和验证 APF 数据区域一次。
  • 请勿清除计数器。
  • 生成测试数据包以触发每条过滤器规则。
  • 使用以下内存位置验证计数器递增情况:

    计数器名称 内存位置
    DROPPED_ETHERTYPE_DENYLISTED [ApfRamSize - 20, ApfRamSize - 16]
    DROPPED_DHCP_REQUEST_DISCOVERY [ApfRamSize - 24, ApfRamSize - 20]
    DROPPED_ICMP4_ECHO_REQUEST [ApfRamSize - 28, ApfRamSize - 24]
    DROPPED_RS [ApfRamSize - 32, ApfRamSize - 28]
    PASSED_PACKET [ApfRamSize - 36, ApfRamSize - 32]

APF 程序 1 和 APF 程序 2 的伪代码

以下伪代码详细说明了 APF 程序 1 和 APF 程序 2 的逻辑:

// ethertype filter
If the ethertype in [0x88A2, 0x88A4, 0x88B8, 0x88CD, 0x88E1, 0x88E3]:
    drop packet and increase counter: DROPPED_ETHERTYPE_DENYLISTED

// dhcp discover/request filter
if ethertype != ETH_P_IP:
    skip the filter
if ipv4_src_addr != 0.0.0.0:
    skip the filter
if ipv4_dst_addr != 255.255.255.255
    skip the filter
if not UDP packet:
    skip the filter
if UDP src port is not dhcp request port:
    skip the filter
else:
    drop the packet and increase the counter: DROPPED_DHCP_REQUEST_DISCOVERY

// Router Solicitation filter:
if ethertype != ETH_P_IPV6:
    skip the filter
if not ICMP6 packet:
    skip the filter
if ICMP6 type is not a Router Solicitation:
    skip the filter
else:
    drop the packet and increase the counter: DROPPED_RS

// IPv4 ping filter (only included in Program 2)
if ethertype != ETH_P_IP:
    skip the filter
if it ipv4 protocol is not ICMP:
    skip the filter
if port is not a ping request port
    skip the filter
else:
    drop the packet and increase the counter: DROPPED_ICMP4_ECHO_REQUEST

pass the packet and increase: PASSED_PACKET