本系列詳細解析 Packet32(WinPcap 核心層)的 API 與資料結構。前三篇已涵蓋封包獲取、介面卡列舉、資料結構定義。本文聚焦 硬體過濾器、核心緩衝區、讀取超時、封包記憶體管理、封包接收與統計 六大核心函數。
BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject, ULONG Filter);
常用 Filter 常數(定義於 ntddndis.h):
| 常數 | 用途 |
|---|---|
NDIS_PACKET_TYPE_PROMISCUOUS | 混雜模式:接收所有封包(監聽核心) |
NDIS_PACKET_TYPE_DIRECTED | 僅接收發給本機 MAC 的單播封包 |
NDIS_PACKET_TYPE_BROADCAST | 僅接收廣播封包 |
NDIS_PACKET_TYPE_MULTICAST | 接收本機加入之多播群組封包 |
NDIS_PACKET_TYPE_ALL_MULTICAST | 接收所有多播封包 |
NDIS_PACKET_TYPE_ALL_LOCAL | 接收所有本地封包 |
實作:填充 PACKET_OID_DATA 的 Oid = OID_GEN_CURRENT_PACKET_FILTER、Data = Filter,呼叫 PacketRequest 下發 OID 請求。
BOOLEAN PacketSetBuff(LPADAPTER AdapterObject, int dim); // dim: bytes
關鍵行為:
實作:DeviceIoControl(hFile, pBIOCSETBUFFERSIZE, ...),控制碼 #define pBIOCSETBUFFERSIZE 9592。
BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject, int timeout); // ms
特殊值語意:
0:永不超時(封包到達前永久阻塞)-1:立即返回(非阻塞輪詢)>0:毫秒級超時,超時喚醒 ReadEvent亦用於統計模式下的報告間隔控制。實作同樣透過 DeviceIoControl 送控制碼。
LPPACKET PacketAllocatePacket(void); // 僅配置 _PACKET 結構
VOID PacketInitPacket(LPPACKET lpPacket, PVOID Buffer, UINT Length); // 關聯使用者緩衝區
設計哲學:分離結構配置與資料緩衝,允許應用層自行管理大緩衝區(如 256 KB),一次 PacketReceivePacket 可讀回多個封包,大幅減少系統呼叫開銷。
BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject, LPPACKET lpPacket, BOOLEAN Sync);
流程:
AdapterObject->ReadTimeOut:WaitForSingleObject(ReadEvent, ReadTimeOut)ReadFile 讀取驅動程式緩衝區資料返回資料:lpPacket->Buffer 含一或多個封包(含 bpf_hdr 頭),lpPacket->Length 為實際位元組數。統計模式下則回傳 bpf_stat 結構。
BOOLEAN PacketGetStats(LPADAPTER AdapterObject, struct bpf_stat* s);
bpf_stat 關鍵欄位:
bs_recv:驅動程式從網卡收到的總封包數(含驅動丟棄)bs_drop:驅動緩衝區滿導致丟棄的封包數bs_capt:通過 BPF 過濾器的封包數實作:DeviceIoControl(pBIOCGSTATS) 取得完整結構後擷取上述三欄位。
VOID PacketCloseAdapter(LPADAPTER lpAdapter);
依序執行:CloseHandle(hFile) → SetEvent/CloseHandle(ReadEvent) → 解鎖並釋放 ADAPTER 結構記憶體。
PacketSetBuff(1024*1024) 避免高流量丟包PacketSetReadTimeout(100~500) 並搭配 ReadEvent 以 MsgWaitForMultipleObjects 整合訊息迴圈PacketInitPacketPacketGetStats 監控 bs_drop,動態調整緩衝區或優化過濾器