Android 封包篩選器

Android 封包篩選器 (APF) 可讓架構在執行階段控制硬體封包篩選邏輯。這樣一來,系統就能透過在硬體中捨棄封包來節省電力,同時讓 Android 架構在執行階段根據網路狀況變更篩選規則。

APF 簡介

APF 包含兩個主要元件:

  • APF 轉譯器會在網路硬體 (通常是 Wi-Fi 晶片組) 上執行。APF 轉譯器會針對硬體接收的封包執行 APF 位元碼,並決定是否接受、捨棄或回覆這些封包。
  • APF 程式產生程式碼會在主要 CPU 上執行。程式碼會根據網路和裝置狀態建立及更新 APF 程式。

Wi-Fi HAL 方法可讓 Android 架構安裝 APF 程式位元碼,並讀取目前的計數器。網路堆疊主線程模組可在 APF 執行期間隨時更新 APF 程式位元碼。

實作了多個 APF 篩選器。舉例來說,APF 包含篩選器,可用於捨棄不允許的乙太網路類型、篩除 IPv6 路由器廣告 (RA) 封包、篩除多播和廣播流量 (如果未保留多播鎖定)、捨棄其他主機的 DHCP 封包,以及捨棄未經請求的位址解析通訊協定 (ARP) 和鄰居探索 (ND) 封包。如果韌體支援 APFv6,ApfFilter 也會產生規則,用於回應一般封包類型,否則需要 CPU 喚醒才能回應,例如 ARP 查詢和 NS 查詢。完整的篩選器清單定義在 ApfFilter 中。

由於 APF 程式產生程式碼是網路堆疊模組的一部分,您可以使用每月 [Mainline 更新新增篩選器並更新篩選邏輯。

APF 修訂版本

以下清單說明 APF 的修訂版本記錄:

  • APFv6:這個版本在 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()apf_transmit_buffer() API。APF 轉譯器會在封包傳輸邏輯期間呼叫這兩個 API。APF 指令的長度會有所變動。每個指令的長度至少為 1 個位元組。APF 指令碼是在 APFv4 的 apf.h 中定義,並直接在 APFv6 的 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 轉譯器則約為 4 KB,並提供額外功能 (例如原生總和檢查支援和原生 DNS 解壓縮程式碼)。

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,即可讓 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

如要檢查 APF 結果與 tcpdump 擷取的 pcap 檔案是否相符,請使用 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 工具會針對轉譯器執行作業中的每個步驟提供詳細輸出內容,這有助於進行偵錯。在本例中,我們會將 ARP 查詢封包輸入 APF 程式。輸出內容顯示 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 連線情境中驗證適當的 APF 功能 (例如 make-before-break 或漫遊 Wi-Fi 連線情境) 至關重要。如需執行整合測試的詳細操作說明,請參閱下一個章節。

必要條件

執行整合測試時,請執行下列操作:

  • 必須在所有整合測試案例中啟用 APF (例如漫遊、先建立再中斷)。
  • 在每項測試開始時,請清除 APF 記憶體。
  • 在測試期間,每 5 分鐘安裝或重新安裝 APF 程式。

測試情境

在整個整合測試期間,必須啟用 APF。本文提供兩個 APF 程式,可在測試期間安裝。程式採用十六進位字串格式,因此測試人員必須將十六進位字串轉換為二進位,並安裝至韌體,以便讓程式可由 apf_interpreter 執行。在整合測試期間,測試人員應傳送預期會觸發程式 1 和程式 2 中的篩選邏輯的封包。

APF 計畫 1

在裝置螢幕開啟時,安裝 APF 程式 1。這個程式可以捨棄不會影響裝置功能的無害封包。這些封包可用於測試 APF 是否正確篩除網路流量。

APF 方案 1 的邏輯如下:

  1. 放棄並遞增計數器:
    1. EtherType 值:0x88A20x88A40x88B80x88CD0x88E10x88E3
    2. IPv4 DHCP 探索或要求封包
    3. RS 封包
  2. 傳遞並遞增計數器:所有其他封包。

APF 程式 1 位元組代碼如下:

6BF0B03A01B86BF8AA0FB86BF4AA09B8120C6BEC7C005D88A27C005888A47C005388B87C004E88CD7C004988E17C004488E3120C84002008001A1A821B001A1E8600000010FFFFFFFF0A17820B11AB0D2A108204436BE8721D120C84000E86DD0A1482093A0A368204856BE072086BDCB03A01B87206B03A01B87201
APF 計畫 2

在裝置螢幕關閉時,安裝 APF 程式 2。這個程式會篩除 APF 程式 1 篩選的所有封包,以及 ping 要求封包。如要確認 APF 程式 2 已正確安裝,請將 ICMP 封包傳送至受測裝置。

APF 方案 2 的邏輯如下:

  1. 放棄並遞增計數器:
    1. EtherType 值:0x88A20x88A40x88B80x88CD0x88E10x88E3
    2. IPv4 DHCP 探索或要求封包
    3. RS 封包
  2. 捨棄並遞增計數器:ICMP 封包要求
  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