标题: MSDN系列(14)--"NDIS Protocol Driver"入门 日期: 2004-07-19 16:55 更新: 2006-04-30 15:59 链接: https://scz.617.cn/windows/200408171624.txt -------------------------------------------------------------------------- ☆ NDIS Protocol Driver ☆ ntoskrnl.exe引出的一些运行时函数 ☆ 一个完整的NDIS Protocol Driver框架 a) NDIS协议驱动 1) ndisprotocol.c 2) sources 3) makefile 4) ndisprotocol.inf b) NDIS协议驱动的用户态测试程序 1) ndisprotocoltest.c 2) sources 3) makefile c) NDIS组件配置程序 d) 源代码目录结构 e) 编译 f) 安装 g) 测试 h) 卸载 i) 一些遗留问题 ☆ 参考资源 -------------------------------------------------------------------------- ☆ NDIS Protocol Driver [1]给了一张Windows网络架构图,有助于理解NDIS,推荐入门者先看看这张图。 [2]有一些关于Windows网络架构的讨论,这只是一种个人学术观点,仅供参考,不可 当成官方结论。 NDIS(Network Device Interface Specification)提供一个系统的、完整的Wrapper, NDIS Miniport Driver、NDIS ProtocolDriver等等均属于"插入"这个Wrapper中的" 模块",这些驱动调用Wrapper提供的函数,同时也向Wrapper注册回调函数,整个运 作过程由Wrapper统一调度。Wrapper对应ndis.sys。 TDI Client Driver利用协议驱动上沿引出的TDI接口(Transport Data Interface)实 现命名管道、邮槽、Winsock等等。 下面这些注册表内容对应着Network Control Panel Applet (NCPA): -------------------------------------------------------------------------- HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318} HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E973-E325-11CE-BFC1-08002BE10318} HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E974-E325-11CE-BFC1-08002BE10318} HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E975-E325-11CE-BFC1-08002BE10318} HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318} 对应GUID_DEVCLASS_NET、Miniport Driver、Net。收到包后NDIS首先调用 Miniport Driver进行处理。Miniport Driver负责控制网卡硬件特性,在协议驱 动与网卡之间传递报文。 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E973-E325-11CE-BFC1-08002BE10318} 对应GUID_DEVCLASS_NETCLIENT、Client Driver、NetClient。"Client for Microsoft Networks"即是此类型驱动。负责向用户态提供NetBIOS Client API。 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E974-E325-11CE-BFC1-08002BE10318} 对应GUID_DEVCLASS_NETSERVICE、Service Driver、NetService。"File and Printer Sharing for Microsoft Networks"即是此类型驱动。 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E975-E325-11CE-BFC1-08002BE10318} 对应GUID_DEVCLASS_NETTRANS、Protocol Driver、NetTrans。负责实现各种网 络协议,比如tcpip.sys实现了TCP/IP协议。协议驱动接收Miniport Driver上传 的报文,也接收Client Driver、Service Driver、TDI Client Driver下传的报 文。 -------------------------------------------------------------------------- 中间层驱动(Intermediate Driver)是一种混合型驱动,位于Miniport Driver与协议 驱动之间,对下看起来像协议驱动,对上看起来像Miniport Driver。 在这些不同类型的驱动之间有一种操作叫作"绑定",其本质在于向NDIS Wrapper指明 报文(Packet)的传递路线。 ☆ ntoskrnl.exe引出的一些运行时函数 > dumpbin /exports %systemroot%\system32\ntoskrnl.exe | find /I "printf" 1397 574 00052BCB _snprintf 1398 575 00052C22 _snwprintf 1406 57D 00052D73 _vsnprintf 1407 57E 00052DC9 _vsnwprintf 1430 595 00053D4D sprintf 1443 5A2 000543E0 swprintf 1450 5A9 000544F4 vsprintf > dumpbin /exports %systemroot%\system32\ntoskrnl.exe | find "_str" 1399 576 00052C92 _stricmp 1400 577 00052C97 _strlwr 1401 578 00052CBA _strnicmp 1402 579 00052CD0 _strnset 1403 57A 00052D00 _strrev 1404 57B 00052D30 _strset 1405 57C 00052D50 _strupr > dumpbin /exports %systemroot%\system32\ntoskrnl.exe | find " str" 1432 597 00053DC0 strcat 1433 598 00053EB0 strchr 1434 599 00053F70 strcmp 1435 59A 00053DB0 strcpy 1436 59B 00054000 strlen 1437 59C 00054080 strncat 1438 59D 000541B0 strncmp 1439 59E 000541F0 strncpy 1440 59F 000542F0 strrchr 1441 5A0 00054320 strspn 1442 5A1 00054360 strstr > dumpbin /exports %systemroot%\system32\ntoskrnl.exe | find "wcs" 1408 57F 00052E38 _wcsicmp 1409 580 00052E83 _wcslwr 1410 581 00052EAF _wcsnicmp 1411 582 00052F08 _wcsnset 1412 583 00052F31 _wcsrev 1413 584 00052F63 _wcsupr 1422 58D 000531DB mbstowcs 1451 5AA 0005454B wcscat 1452 5AB 00054591 wcschr 1453 5AC 000545B3 wcscmp 1454 5AD 00054575 wcscpy 1455 5AE 000545E5 wcscspn 1456 5AF 00054628 wcslen 1457 5B0 0005463E wcsncat 1458 5B1 0005467B wcsncmp 1459 5B2 000546B0 wcsncpy 1460 5B3 000546ED wcsrchr 1461 5B4 0005471D wcsspn 1462 5B5 00054763 wcsstr 1463 5B6 000547C1 wcstombs > dumpbin /exports %systemroot%\system32\ntoskrnl.exe | find "mem" 1424 58F 00053290 memchr 1425 590 00053340 memcpy 1426 591 00053680 memmove 1427 592 000539C0 memset > dumpbin /exports %systemroot%\system32\ntoskrnl.exe | find "_ito" 1393 570 00052B76 _itoa 1394 571 00052BA0 _itow ☆ 一个完整的NDIS Protocol Driver框架 a) NDIS协议驱动 XP SP1 DDK自带了一个名为ndisuio的例子(NDIS User mode I/O Protocol),但我没 有找到NT4 DDK中名为packet的例子。参[3]、[4]、[5],这些都是完整的协议驱动源 代码。 ndisuio演示了"connection-less NDIS 5.0/5.1 protocol driver",用户态程序可 简单地通过ReadFile/WriteFile直接操作链路层数据(物理帧)。对于sniffer一类的 需求,这已经足够了。ndisuio没有在其上沿提供TDI接口。ndisuio做了很多限制, 使得我们无法随心所欲地操作链路层数据。假设有如下结构: struct etherheader { unsigned char eth_dst[6]; /* destination eth addr */ unsigned char eth_src[6]; /* source ether addr */ unsigned short int eth_type; /* packet type ID field */ }; ndisuio在DispatchWrite()例程中对eth_src、eth_type进行检查,发送报文时不能 伪造源MAC,必须匹配事先指定的eth_type。 ndisuio允许用户态程序通过DeviceIoControl()指定eth_type,但其在 DispatchDeviceControl()例程中做了限制,不能任意指定eth_type。 ndisuio在ProtocolReceive()、ProtocolReceivePacket()例程中对eth_type进行检 查,只接收与事先指定的eth_type相匹配的报文。 ndisuio允许用户态程序通过DeviceIoControl()向Miniport Driver设置OID,但其在 DispatchDeviceControl()例程中做了限制,只允许设置部分OID。 从ndisuio例子所附用户态测试程序的代码来看,曾经有一个版本的ndisuio未做前述 限制,至少发送报文时可以伪造源MAC。现在我们要做的就是简单地注释掉相应代码, 使得可以随心所欲地操作链路层数据。 XP事实上缺省安装了ndisuio,可用"net start ndisuio"加载这个隐藏的协议驱动。 据tk讲,2000也缺省安装ndisuio,我不确认是某个Service Pack带进来的,还是最 初就有。由于存在前述限制,ndisuio对我们来讲没有多少意义。 下面是XP SP1中与ndisuio相关的注册表内容,NDI是"Network Device Installer"的 缩写。 -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E975-E325-11CE-BFC1-08002BE10318}\{03130807-B5F2-47A1-81B0-B870D16F272B}] "Characteristics"=dword:00000028 "InfPath"="ndisuio.inf" "InfSection"="Install" "Description"="NDIS Usermode I/O Protocol" "ComponentId"="ms_ndisuio" [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E975-E325-11CE-BFC1-08002BE10318}\{03130807-B5F2-47A1-81B0-B870D16F272B}\Ndi] "Service"="Ndisuio" "HelpText"="A driver to support user-mode I/O on NDIS devices" [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E975-E325-11CE-BFC1-08002BE10318}\{03130807-B5F2-47A1-81B0-B870D16F272B}\Ndi\Interfaces] "UpperRange"="noupper" "LowerRange"="ndis5,ndis4,ndis5_uio" -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\LEGACY_NDISUIO] "NextInstance"=dword:00000001 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\LEGACY_NDISUIO\0000] "Service"="Ndisuio" "Legacy"=dword:00000001 "ConfigFlags"=dword:00000000 "Class"="LegacyDriver" "ClassGUID"="{8ECC055D-047F-11D1-A537-0000F8753ED1}" "DeviceDesc"="NDIS Usermode I/O Protocol" "Capabilities"=dword:00000000 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\LEGACY_NDISUIO\0000\LogConf] [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\LEGACY_NDISUIO\0000\Control] "ActiveService"="Ndisuio" -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Ndisuio] "Type"=dword:00000001 "Start"=dword:00000003 "ErrorControl"=dword:00000001 "Tag"=dword:0000000c "ImagePath"=hex(2):53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,44,00,\ 52,00,49,00,56,00,45,00,52,00,53,00,5c,00,6e,00,64,00,69,00,73,00,75,00,69,\ 00,6f,00,2e,00,73,00,79,00,73,00,00,00 "DisplayName"="NDIS Usermode I/O Protocol" "Group"="NDIS" "Description"="NDIS Usermode I/O Protocol" [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Ndisuio\Linkage] "Bind"=hex(7):5c,00,44,00,65,00,76,00,69,00,63,00,65,00,5c,00,7b,00,33,00,46,\ 00,32,00,46,00,37,00,46,00,35,00,33,00,2d,00,39,00,34,00,43,00,43,00,2d,00,\ 34,00,43,00,38,00,33,00,2d,00,42,00,36,00,38,00,33,00,2d,00,34,00,33,00,30,\ 00,38,00,43,00,35,00,37,00,33,00,37,00,31,00,32,00,44,00,7d,00,00,00,5c,00,\ 44,00,65,00,76,00,69,00,63,00,65,00,5c,00,7b,00,34,00,46,00,44,00,45,00,38,\ 00,42,00,37,00,42,00,2d,00,31,00,42,00,41,00,31,00,2d,00,34,00,42,00,30,00,\ 41,00,2d,00,39,00,30,00,32,00,39,00,2d,00,31,00,34,00,31,00,45,00,31,00,33,\ 00,35,00,35,00,39,00,45,00,36,00,39,00,7d,00,00,00,00,00 "Route"=hex(7):22,00,7b,00,33,00,46,00,32,00,46,00,37,00,46,00,35,00,33,00,2d,\ 00,39,00,34,00,43,00,43,00,2d,00,34,00,43,00,38,00,33,00,2d,00,42,00,36,00,\ 38,00,33,00,2d,00,34,00,33,00,30,00,38,00,43,00,35,00,37,00,33,00,37,00,31,\ 00,32,00,44,00,7d,00,22,00,00,00,22,00,7b,00,34,00,46,00,44,00,45,00,38,00,\ 42,00,37,00,42,00,2d,00,31,00,42,00,41,00,31,00,2d,00,34,00,42,00,30,00,41,\ 00,2d,00,39,00,30,00,32,00,39,00,2d,00,31,00,34,00,31,00,45,00,31,00,33,00,\ 35,00,35,00,39,00,45,00,36,00,39,00,7d,00,22,00,00,00,00,00 "Export"=hex(7):5c,00,44,00,65,00,76,00,69,00,63,00,65,00,5c,00,4e,00,64,00,69,\ 00,73,00,75,00,69,00,6f,00,5f,00,7b,00,33,00,46,00,32,00,46,00,37,00,46,00,\ 35,00,33,00,2d,00,39,00,34,00,43,00,43,00,2d,00,34,00,43,00,38,00,33,00,2d,\ 00,42,00,36,00,38,00,33,00,2d,00,34,00,33,00,30,00,38,00,43,00,35,00,37,00,\ 33,00,37,00,31,00,32,00,44,00,7d,00,00,00,5c,00,44,00,65,00,76,00,69,00,63,\ 00,65,00,5c,00,4e,00,64,00,69,00,73,00,75,00,69,00,6f,00,5f,00,7b,00,34,00,\ 46,00,44,00,45,00,38,00,42,00,37,00,42,00,2d,00,31,00,42,00,41,00,31,00,2d,\ 00,34,00,42,00,30,00,41,00,2d,00,39,00,30,00,32,00,39,00,2d,00,31,00,34,00,\ 31,00,45,00,31,00,33,00,35,00,35,00,39,00,45,00,36,00,39,00,7d,00,00,00,00,\ 00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Ndisuio\Security] "Security"=hex:01,00,14,80,90,00,00,00,9c,00,00,00,14,00,00,00,30,00,00,00,02,\ 00,1c,00,01,00,00,00,02,80,14,00,ff,01,0f,00,01,01,00,00,00,00,00,01,00,00,\ 00,00,02,00,60,00,04,00,00,00,00,00,14,00,fd,01,02,00,01,01,00,00,00,00,00,\ 05,12,00,00,00,00,00,18,00,ff,01,0f,00,01,02,00,00,00,00,00,05,20,00,00,00,\ 20,02,00,00,00,00,14,00,8d,01,02,00,01,01,00,00,00,00,00,05,0b,00,00,00,00,\ 00,18,00,fd,01,02,00,01,02,00,00,00,00,00,05,20,00,00,00,23,02,00,00,01,01,\ 00,00,00,00,00,05,12,00,00,00,01,01,00,00,00,00,00,05,12,00,00,00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Ndisuio\Enum] "0"="Root\\LEGACY_NDISUIO\\0000" "Count"=dword:00000001 "NextInstance"=dword:00000001 -------------------------------------------------------------------------- 名为"Characteristics"的键值对应INF文件中的Characteristics项,0x28表示逻辑 或NCF_HIDDEN(0x08)、NCF_NOT_USER_REMOVABLE(0x20),即NCPA中不可见、不可通过 NCPA或设备管理器删除。调试协议驱动时,应在INF文件中指定0x00,这样才便于删 除、重新增加并测试。 1) ndisprotocol.c 本文所给完整框架(安装/卸载、驱动、用户态测试程序)完全是DDK自带例子代码,我 可写不出这么大的框架代码来。如有疑问,请问微软。 -------------------------------------------------------------------------- /* * For x86/EWindows XP SP1 & VC 7 & Windows DDK 2600.1106 */ /************************************************************************ * * * Head File * * * ************************************************************************/ #include #include #include #include #include #include /************************************************************************ * * * Macro * * * ************************************************************************/ #define INTERNALNAME L"\\Device\\NDISProtocolInternal" #define EXTERNALNAME L"\\??\\NDISProtocolExternal" #define PRIVATETAG 'OFSN' #define NDISPROTOCOL_INDEX 0x0800 #define IOCTL_NDISPROTOCOL_GET_PRIVATEFLAGS CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 0, \ METHOD_BUFFERED, \ FILE_READ_ACCESS \ ) #define IOCTL_NDISPROTOCOL_SET_PRIVATEFLAGS CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 1, \ METHOD_BUFFERED, \ FILE_WRITE_ACCESS \ ) #define IOCTL_NDISPROTOCOL_OPEN_DEVICE CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 2, \ METHOD_BUFFERED, \ FILE_READ_ACCESS | FILE_WRITE_ACCESS \ ) #define IOCTL_NDISPROTOCOL_GET_OID_VALUE CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 3, \ METHOD_BUFFERED, \ FILE_READ_ACCESS \ ) #define IOCTL_NDISPROTOCOL_SET_OID_VALUE CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 4, \ METHOD_BUFFERED, \ FILE_WRITE_ACCESS \ ) #define IOCTL_NDISPROTOCOL_SET_ETHER_TYPE CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 5, \ METHOD_BUFFERED, \ FILE_WRITE_ACCESS \ ) #define IOCTL_NDISPROTOCOL_QUERY_BINDING CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 6, \ METHOD_BUFFERED, \ FILE_READ_ACCESS \ ) #define IOCTL_NDISPROTOCOL_BIND_WAIT CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 7, \ METHOD_BUFFERED, \ FILE_READ_ACCESS | FILE_WRITE_ACCESS \ ) #define PRIVATEFLAGS_ETHERTYPE 0x00000001 #define PRIVATEFLAGS_DEFAULT 0x00000001 typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT DeviceObject; ULONG DeviceNumber; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; #define PRIVATEMIN(x,y) ((x)<(y)?(x):(y)) #define SET_FLAGS(_FlagsVar, _Mask, _BitsToSet) (_FlagsVar) = ((_FlagsVar) & ~(_Mask)) | (_BitsToSet) #define TEST_FLAGS(_FlagsVar, _Mask, _BitsToCheck) (((_FlagsVar) & (_Mask)) == (_BitsToCheck)) #define PRIVATE_BIND_IDLE 0x00000000 #define PRIVATE_BIND_OPENING 0x00000001 #define PRIVATE_BIND_FAILED 0x00000002 #define PRIVATE_BIND_ACTIVE 0x00000004 #define PRIVATE_BIND_CLOSING 0x00000008 #define PRIVATE_BIND_FLAGS 0x0000000F #define PRIVATE_OPEN_IDLE 0x00000000 #define PRIVATE_OPEN_ACTIVE 0x00000010 #define PRIVATE_OPEN_FLAGS 0x000000F0 #define PRIVATE_RESET_IN_PROGRESS 0x00000100 #define PRIVATE_NOT_RESETTING 0x00000000 #define PRIVATE_RESET_FLAGS 0x00000100 #define PRIVATE_MEDIA_CONNECTED 0x00000000 #define PRIVATE_MEDIA_DISCONNECTED 0x00000200 #define PRIVATE_MEDIA_FLAGS 0x00000200 #define PRIVATE_READ_SERVICING 0x00100000 #define PRIVATE_READ_FLAGS 0x00100000 #define PRIVATE_UNBIND_RECEIVED 0x10000000 #define PRIVATE_UNBIND_FLAGS 0x10000000 #define DEFAULT_PACKET_FILTER (NDIS_PACKET_TYPE_DIRECTED|NDIS_PACKET_TYPE_MULTICAST|NDIS_PACKET_TYPE_BROADCAST) typedef struct _ADAPTER_CONTEXT { LIST_ENTRY Link; NDIS_SPIN_LOCK Lock; ULONG ReferenceCount; ULONG Flags; PFILE_OBJECT FileObject; NDIS_STRING DeviceName; NDIS_STRING AdapterInstanceName; NDIS_STATUS BindStatus; NDIS_EVENT BindEvent; NDIS_HANDLE SendPacketPool; NDIS_HANDLE SendBufferPool; NDIS_HANDLE RecvPacketPool; NDIS_HANDLE RecvBufferPool; LIST_ENTRY PendedWrites; ULONG PendedWriteCount; LIST_ENTRY PendedReads; ULONG PendedReadCount; LIST_ENTRY RecvPacketQueue; ULONG RecvPacketCount; NDIS_HANDLE NdisBindingHandle; UCHAR CurrentAddress[6]; ULONG MacOptions; ULONG MaximumFrameSize; NET_DEVICE_POWER_STATE PowerState; NDIS_EVENT PoweredUpEvent; } ADAPTER_CONTEXT, *PADAPTER_CONTEXT; typedef struct _BINDINGINFO { ULONG BindingIndex; // 0-based binding number ULONG DeviceNameOffset; // from start of this struct ULONG DeviceNameLength; // in bytes ULONG AdapterInstanceNameOffset; // from start of this struct ULONG AdapterInstanceNameLength; // in bytes } BINDINGINFO, *PBINDINGINFO; typedef struct _OIDVALUE { NDIS_OID Oid; UCHAR Value[sizeof(ULONG)]; } OIDVALUE, *POIDVALUE; #define MIN_SEND_PACKET_NUM 20 #define MAX_SEND_PACKET_NUM 400 typedef struct _SEND_PACKET_PROTOCOLRESERVED { PIRP Irp; ULONG ReferenceCount; } SEND_PACKET_PROTOCOLRESERVED, *PSEND_PACKET_PROTOCOLRESERVED; #define MIN_RECV_PACKET_NUM 4 #define MAX_RECV_PACKET_NUM 20 #define MAX_RECV_BUFFER_NUM 20 #define MAX_RECV_QUEUE_NUM 4 typedef struct _RECV_PACKET_PROTOCOLRESERVED { LIST_ENTRY Link; PNDIS_BUFFER Buffer; } RECV_PACKET_PROTOCOLRESERVED, *PRECV_PACKET_PROTOCOLRESERVED; #define GETBUFFER(x) (((PRECV_PACKET_PROTOCOLRESERVED)(x)->ProtocolReserved)->Buffer) #define GETLINK(x) (&((PRECV_PACKET_PROTOCOLRESERVED)(x)->ProtocolReserved)->Link) #define GETRECVPACKET(x) CONTAINING_RECORD(CONTAINING_RECORD(x, RECV_PACKET_PROTOCOLRESERVED, Link), NDIS_PACKET, ProtocolReserved) #define GETREFERENCECOUNT(x) (((PSEND_PACKET_PROTOCOLRESERVED)(x)->ProtocolReserved)->ReferenceCount) #define GETIRP(x) (((PSEND_PACKET_PROTOCOLRESERVED)(x)->ProtocolReserved)->Irp) #define GETCANCELID() (HighCancelId | (NdisInterlockedIncrement(&LowCancelId) & 0x00FFFFFF)) typedef struct _REQUEST_CONTEXT { NDIS_REQUEST NdisRequest; NDIS_EVENT NdisRequestEvent; ULONG Status; } REQUEST_CONTEXT, *PREQUEST_CONTEXT; #pragma pack( push, 1 ) struct etherheader { unsigned char eth_dst[6]; /* destination eth addr */ unsigned char eth_src[6]; /* source ether addr */ unsigned short int eth_type; /* packet type ID field */ }; #pragma pack( pop ) #define swap_16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) #define swap_32(x) ((((x) >> 24) & 0xff) | (((x) & 0xff) << 24) | (((x) >> 8) & 0xff00) | (((x) & 0xff00) << 8)) #define ETH_P_IP 0x0800 /* Internet Protocol packet */ #define ETH_P_ARP 0x0806 /* Address Resolution packet */ #define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ #define ETH_P_8021P 0x8100 /* 802.1p */ #define ETH_P_DEFAULT ETH_P_ARP /************************************************************************ * * * Function Prototype * * * ************************************************************************/ static NTSTATUS NDISProtocolCreateDevice ( IN PDRIVER_OBJECT DriverObject, IN ULONG DeviceNumber ); static VOID NDISProtocolDeleteDevice ( IN PDEVICE_OBJECT DeviceObject ); static NTSTATUS NDISProtocolDispatch ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); static NTSTATUS NDISProtocolDispatchRead ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); static VOID NDISProtocolReadCancel ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); static NTSTATUS NDISProtocolDispatchWrite ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); #ifdef NDIS51 static VOID NDISProtocolWriteCancel ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); #endif static NTSTATUS NDISProtocolDispatchCleanup ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); static NTSTATUS NDISProtocolDispatchDeviceControl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); static VOID NDISProtocolDriverUnload ( IN PDRIVER_OBJECT DriverObject ); static PNDIS_PACKET PrivateAllocateReceivePacket ( IN PADAPTER_CONTEXT AdapterContext, IN UINT DataLength, OUT PUCHAR *pData ); static VOID PrivateCancelPendingReads ( IN PADAPTER_CONTEXT AdapterContext ); static NDIS_STATUS PrivateCreateBinding ( IN PADAPTER_CONTEXT AdapterContext, IN PWSTR DeviceName, IN ULONG DeviceNameLength ); static VOID PrivateDereferenceCount ( IN PADAPTER_CONTEXT AdapterContext ); static VOID PrivateFlushReceiveQueue ( IN PADAPTER_CONTEXT AdapterContext ); static VOID PrivateFreeAdapterContextResources ( IN PADAPTER_CONTEXT AdapterContext ); static VOID PrivateFreeReceivePacket ( IN PADAPTER_CONTEXT AdapterContext, IN PNDIS_PACKET Packet ); static NDIS_STATUS PrivateGetOidValue ( IN PADAPTER_CONTEXT AdapterContext, OUT PVOID OutputBuffer, IN ULONG OutputBufferLength, OUT PULONG BytesWritten ); static PADAPTER_CONTEXT PrivateLookupDevice ( IN PWSTR DeviceName, IN ULONG DeviceNameLength ); static NDIS_STATUS PrivateNdisRequest ( IN PADAPTER_CONTEXT AdapterContext, IN NDIS_REQUEST_TYPE RequestType, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN UINT InformationBufferLength, OUT PUINT BytesProcessed ); static VOID PrivateNdisStatusToNtStatus ( IN NDIS_STATUS NdisStatus, IN NTSTATUS *NtStatus ); static NTSTATUS PrivateOpenDevice ( IN PWSTR DeviceName, IN ULONG DeviceNameLength, IN PFILE_OBJECT FileObject, OUT PADAPTER_CONTEXT *pAdapterContext ); static NDIS_STATUS PrivateQueryBinding ( IN PUCHAR Buffer, IN ULONG InputBufferLength, IN ULONG OutputBufferLength, OUT PULONG BytesReturned ); static VOID PrivateQueueReceivePacket ( IN PADAPTER_CONTEXT AdapterContext, IN PNDIS_PACKET RecvPacket ); static VOID PrivateReferenceCount ( IN PADAPTER_CONTEXT AdapterContext ); static VOID PrivateSendDereferenceCount ( IN PNDIS_PACKET Packet ); static VOID PrivateSendReferenceCount ( IN PNDIS_PACKET Packet ); static VOID PrivateServiceReads ( IN PADAPTER_CONTEXT AdapterContext ); static NDIS_STATUS PrivateSetOidValue ( IN PADAPTER_CONTEXT AdapterContext, OUT PVOID InputBuffer, IN ULONG InputBufferLength ); static VOID PrivateShutdownBinding ( IN PADAPTER_CONTEXT AdapterContext ); static VOID PrivateSleep ( IN UINT seconds ); static BOOLEAN PrivateValidateOid ( IN NDIS_OID Oid ); static NDIS_STATUS PrivateValidateOpenAndDoRequest ( IN PADAPTER_CONTEXT AdapterContext, IN NDIS_REQUEST_TYPE RequestType, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN UINT InformationBufferLength, OUT PUINT BytesProcessed, IN BOOLEAN WaitForPowerOn ); static VOID PrivateWaitForPendingIO ( IN PADAPTER_CONTEXT AdapterContext, IN BOOLEAN DoCancelPendingReads ); static VOID ProtocolOpenAdapterComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status, IN NDIS_STATUS OpenErrorStatus ); static VOID ProtocolCloseAdapterComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status ); static VOID ProtocolSendComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status ); static VOID ProtocolTransferDataComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status, IN UINT BytesTransferred ); static VOID ProtocolResetComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status ); static VOID ProtocolRequestComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_REQUEST NdisRequest, IN NDIS_STATUS Status ); static NDIS_STATUS ProtocolReceive ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ); static VOID ProtocolReceiveComplete ( IN NDIS_HANDLE ProtocolBindingContext ); static VOID ProtocolStatus ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS GeneralStatus, IN PVOID StatusBuffer, IN UINT StatusBufferSize ); static VOID ProtocolStatusComplete ( IN NDIS_HANDLE ProtocolBindingContext ); static INT ProtocolReceivePacket ( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet ); static VOID ProtocolBindAdapter ( OUT PNDIS_STATUS Status, IN NDIS_HANDLE BindContext, IN PNDIS_STRING DeviceName, IN PVOID SystemSpecific1, IN PVOID SystemSpecific2 ); static VOID ProtocolUnbindAdapter ( OUT PNDIS_STATUS Status, IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE UnbindContext ); static NDIS_STATUS ProtocolPnPEvent ( IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT NetPnPEvent ); static VOID ProtocolUnload ( VOID ); NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ); #ifdef ALLOC_PRAGMA #pragma NDIS_INIT_FUNCTION ( NDISProtocolCreateDevice ) #pragma NDIS_PAGEABLE_FUNCTION ( NDISProtocolDeleteDevice ) #pragma NDIS_PAGEABLE_FUNCTION ( NDISProtocolDispatch ) #pragma NDIS_PAGEABLE_FUNCTION ( NDISProtocolDispatchRead ) #pragma NDIS_PAGEABLE_FUNCTION ( NDISProtocolDispatchWrite ) #pragma NDIS_PAGEABLE_FUNCTION ( NDISProtocolDispatchCleanup ) #pragma NDIS_PAGEABLE_FUNCTION ( NDISProtocolDispatchDeviceControl ) #pragma NDIS_PAGEABLE_FUNCTION ( NDISProtocolDriverUnload ) #pragma NDIS_INIT_FUNCTION ( DriverEntry ) #endif /************************************************************************ * * * Static Global Var * * * ************************************************************************/ static ULONG PrivateFlags = PRIVATEFLAGS_DEFAULT; static unsigned short int EtherType = ETH_P_DEFAULT; static NDIS_HANDLE NdisProtocolHandle = ( NDIS_HANDLE )NULL; static LIST_ENTRY AdapterContextList; static NDIS_SPIN_LOCK Lock; static NDIS_EVENT BindsComplete; #ifdef NDIS51 static ULONG HighCancelId; static ULONG LowCancelId = 0; #endif /************************************************************************/ static NTSTATUS NDISProtocolCreateDevice ( IN PDRIVER_OBJECT DriverObject, IN ULONG DeviceNumber ) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT DeviceObject = NULL; PDEVICE_EXTENSION DeviceExtension; UNICODE_STRING DeviceName; UNICODE_STRING SymbolicLinkName; SIZE_T InternalNameLen; SIZE_T ExternalNameLen; PWSTR InternalName = NULL; PWSTR ExternalName = NULL; KdPrint(( "Entering NDISProtocolCreateDevice()\n" )); InternalNameLen = sizeof( INTERNALNAME ) + 10 * sizeof( WCHAR ); InternalName = ( PWSTR )ExAllocatePoolWithTag ( PagedPool, InternalNameLen, PRIVATETAG ); if ( NULL == InternalName ) { status = STATUS_INSUFFICIENT_RESOURCES; goto NDISProtocolCreateDevice_exit; } swprintf( InternalName, L"%s%u", INTERNALNAME, DeviceNumber ); RtlInitUnicodeString( &DeviceName, InternalName ); status = IoCreateDevice ( DriverObject, sizeof( DEVICE_EXTENSION ), &DeviceName, FILE_DEVICE_NETWORK, FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject ); if ( !NT_SUCCESS( status ) ) { goto NDISProtocolCreateDevice_exit; } DeviceObject->Flags |= DO_DIRECT_IO; DeviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension; DeviceExtension->DeviceObject = DeviceObject; DeviceExtension->DeviceNumber = DeviceNumber; ExternalNameLen = sizeof( EXTERNALNAME ) + 10 * sizeof( WCHAR ); ExternalName = ( PWSTR )ExAllocatePoolWithTag ( PagedPool, ExternalNameLen, PRIVATETAG ); if ( NULL == ExternalName ) { status = STATUS_INSUFFICIENT_RESOURCES; goto NDISProtocolCreateDevice_exit; } swprintf( ExternalName, L"%s%u", EXTERNALNAME, DeviceNumber + 1 ); RtlInitUnicodeString( &SymbolicLinkName, ExternalName ); status = IoCreateSymbolicLink ( &SymbolicLinkName, &DeviceName ); NDISProtocolCreateDevice_exit: if ( NULL != ExternalName ) { ExFreePoolWithTag ( ExternalName, PRIVATETAG ); ExternalName = NULL; } if ( ( !NT_SUCCESS( status ) ) && ( NULL != DeviceObject ) ) { IoDeleteDevice( DeviceObject ); DeviceObject = NULL; } if ( NULL != InternalName ) { ExFreePoolWithTag ( InternalName, PRIVATETAG ); InternalName = NULL; } return( status ); } /* end of NDISProtocolCreateDevice */ static VOID NDISProtocolDeleteDevice ( IN PDEVICE_OBJECT DeviceObject ) { NTSTATUS status; PDEVICE_EXTENSION DeviceExtension; UNICODE_STRING SymbolicLinkName; SIZE_T ExternalNameLen; PWSTR ExternalName = NULL; KdPrint(( "Entering NDISProtocolDeleteDevice()\n" )); DeviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension; ExternalNameLen = sizeof( EXTERNALNAME ) + 10 * sizeof( WCHAR ); ExternalName = ( PWSTR )ExAllocatePoolWithTag ( PagedPool, ExternalNameLen, PRIVATETAG ); if ( NULL == ExternalName ) { status = STATUS_INSUFFICIENT_RESOURCES; KdPrint(( "ExAllocatePoolWithTag() for ExternalName failed (0x%08X)\n", status )); goto NDISProtocolDeleteDevice_exit; } swprintf( ExternalName, L"%s%u", EXTERNALNAME, DeviceExtension->DeviceNumber + 1 ); RtlInitUnicodeString( &SymbolicLinkName, ExternalName ); status = IoDeleteSymbolicLink ( &SymbolicLinkName ); if ( !NT_SUCCESS( status ) ) { KdPrint(( "IoDeleteSymbolicLink() failed\n" )); return; } NDISProtocolDeleteDevice_exit: IoDeleteDevice( DeviceObject ); if ( NULL != ExternalName ) { ExFreePoolWithTag ( ExternalName, PRIVATETAG ); ExternalName = NULL; } return; } /* end of NDISProtocolDeleteDevice */ static NTSTATUS NDISProtocolDispatch ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS status; PIO_STACK_LOCATION IrpStackLocation; ULONG IoControlCode; ULONG InputBufferLength; ULONG OutputBufferLength; ULONG TransferSize; PVOID TransferBuffer; PADAPTER_CONTEXT AdapterContext; KdPrint(( "Entering NDISProtocolDispatch()\n" )); status = STATUS_SUCCESS; TransferSize = 0; TransferBuffer = Irp->AssociatedIrp.SystemBuffer; IrpStackLocation = IoGetCurrentIrpStackLocation( Irp ); IoControlCode = IrpStackLocation->Parameters.DeviceIoControl.IoControlCode; InputBufferLength = IrpStackLocation->Parameters.DeviceIoControl.InputBufferLength; OutputBufferLength = IrpStackLocation->Parameters.DeviceIoControl.OutputBufferLength; AdapterContext = IrpStackLocation->FileObject->FsContext; switch ( IrpStackLocation->MajorFunction ) { case IRP_MJ_CLOSE: KdPrint(( "NDISProtocolDispatch( IRP_MJ_CLOSE )\n" )); if ( NULL != AdapterContext ) { PrivateDereferenceCount( AdapterContext ); } IrpStackLocation->FileObject->FsContext = NULL; break; case IRP_MJ_CREATE: KdPrint(( "NDISProtocolDispatch( IRP_MJ_CREATE )\n" )); IrpStackLocation->FileObject->FsContext = NULL; break; default: KdPrint(( "NDISProtocolDispatch( 0x%02X )\n", IrpStackLocation->MajorFunction )); status = STATUS_NOT_SUPPORTED; break; } /* end of switch */ Irp->IoStatus.Status = status; Irp->IoStatus.Information = TransferSize; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return( status ); } /* end of NDISProtocolDispatch */ static NTSTATUS NDISProtocolDispatchRead ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PIO_STACK_LOCATION IrpStackLocation; NTSTATUS status; PADAPTER_CONTEXT AdapterContext; KdPrint(( "Entering NDISProtocolDispatchRead()\n" )); IrpStackLocation = IoGetCurrentIrpStackLocation( Irp ); AdapterContext = IrpStackLocation->FileObject->FsContext; if ( NULL == AdapterContext ) { status = STATUS_INVALID_HANDLE; goto NDISProtocolDispatchRead_exit; } if ( NULL == Irp->MdlAddress ) { status = STATUS_INVALID_PARAMETER; goto NDISProtocolDispatchRead_exit; } if ( NULL == MmGetSystemAddressForMdlSafe ( Irp->MdlAddress, NormalPagePriority ) ) { status = STATUS_INSUFFICIENT_RESOURCES; goto NDISProtocolDispatchRead_exit; } NdisAcquireSpinLock( &AdapterContext->Lock ); if ( !TEST_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_ACTIVE ) ) { NdisReleaseSpinLock( &AdapterContext->Lock ); status = STATUS_INVALID_HANDLE; goto NDISProtocolDispatchRead_exit; } IoMarkIrpPending( Irp ); status = STATUS_PENDING; InsertTailList ( &AdapterContext->PendedReads, &Irp->Tail.Overlay.ListEntry ); AdapterContext->PendedReadCount++; PrivateReferenceCount( AdapterContext ); Irp->Tail.Overlay.DriverContext[0] = ( PVOID )AdapterContext; IoSetCancelRoutine ( Irp, NDISProtocolReadCancel ); NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateServiceReads( AdapterContext ); NDISProtocolDispatchRead_exit: if ( STATUS_PENDING != status ) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NO_INCREMENT ); } return( status ); } /* end of NDISProtocolDispatchRead */ static VOID NDISProtocolReadCancel ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PADAPTER_CONTEXT AdapterContext; PLIST_ENTRY IrpEntry; BOOLEAN Found; KdPrint(( "Entering NDISProtocolReadCancel()\n" )); IoReleaseCancelSpinLock( Irp->CancelIrql ); Found = FALSE; AdapterContext = ( PADAPTER_CONTEXT )Irp->Tail.Overlay.DriverContext[0]; NdisAcquireSpinLock( &AdapterContext->Lock ); for ( IrpEntry = AdapterContext->PendedReads.Flink; IrpEntry != &AdapterContext->PendedReads; IrpEntry = IrpEntry->Flink ) { if ( Irp == CONTAINING_RECORD( IrpEntry, IRP, Tail.Overlay.ListEntry ) ) { RemoveEntryList( &Irp->Tail.Overlay.ListEntry ); AdapterContext->PendedReadCount--; Found = TRUE; break; } } /* end of for */ NdisReleaseSpinLock( &AdapterContext->Lock ); if ( Found ) { Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NO_INCREMENT ); PrivateDereferenceCount( AdapterContext ); } return; } /* end of NDISProtocolReadCancel */ static NTSTATUS NDISProtocolDispatchWrite ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PIO_STACK_LOCATION IrpStackLocation; NTSTATUS status; NDIS_STATUS ndis_status; PADAPTER_CONTEXT AdapterContext; PNDIS_PACKET Packet; PNDIS_BUFFER Buffer; struct etherheader *etherh; unsigned short int eth_type; ULONG ByteCount; #ifdef NDIS51 ULONG CancelId; #endif KdPrint(( "Entering NDISProtocolDispatchWrite()\n" )); IrpStackLocation = IoGetCurrentIrpStackLocation( Irp ); AdapterContext = IrpStackLocation->FileObject->FsContext; Packet = NULL; if ( NULL == AdapterContext ) { status = STATUS_INVALID_HANDLE; goto NDISProtocolDispatchWrite_exit; } if ( NULL == Irp->MdlAddress ) { status = STATUS_INVALID_PARAMETER; goto NDISProtocolDispatchWrite_exit; } etherh = MmGetSystemAddressForMdlSafe ( Irp->MdlAddress, NormalPagePriority ); if ( NULL == etherh ) { status = STATUS_INSUFFICIENT_RESOURCES; goto NDISProtocolDispatchWrite_exit; } ByteCount = MmGetMdlByteCount( Irp->MdlAddress ); if ( ByteCount < sizeof( struct etherheader ) ) { status = STATUS_BUFFER_TOO_SMALL; goto NDISProtocolDispatchWrite_exit; } if ( ByteCount > ( AdapterContext->MaximumFrameSize + sizeof( struct etherheader ) ) ) { status = STATUS_INVALID_BUFFER_SIZE; goto NDISProtocolDispatchWrite_exit; } eth_type = swap_16( etherh->eth_type ); if ( ( PrivateFlags & PRIVATEFLAGS_ETHERTYPE ) && ( EtherType != eth_type ) ) { status = STATUS_INVALID_PARAMETER; goto NDISProtocolDispatchWrite_exit; } NdisAcquireSpinLock( &AdapterContext->Lock ); if ( !TEST_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_ACTIVE ) ) { NdisReleaseSpinLock( &AdapterContext->Lock ); status = STATUS_INVALID_HANDLE; goto NDISProtocolDispatchWrite_exit; } NdisAllocatePacket ( &ndis_status, &Packet, AdapterContext->SendPacketPool ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { NdisReleaseSpinLock( &AdapterContext->Lock ); status = STATUS_INSUFFICIENT_RESOURCES; goto NDISProtocolDispatchWrite_exit; } Buffer = Irp->MdlAddress; NdisInterlockedIncrement( &AdapterContext->PendedWriteCount ); PrivateReferenceCount( AdapterContext ); IoMarkIrpPending( Irp ); GETREFERENCECOUNT( Packet ) = 1; #ifdef NDIS51 CancelId = GETCANCELID(); NDIS_SET_PACKET_CANCEL_ID( Packet, ( PVOID )CancelId ); Irp->Tail.Overlay.DriverContext[0] = ( PVOID )AdapterContext; Irp->Tail.Overlay.DriverContext[1] = ( PVOID )Packet; InsertTailList ( &AdapterContext->PendedWrites, &Irp->Tail.Overlay.ListEntry ); IoSetCancelRoutine( Irp, NDISProtocolWriteCancel ); #endif NdisReleaseSpinLock( &AdapterContext->Lock ); GETIRP( Packet ) = Irp; status = STATUS_PENDING; Buffer->Next = NULL; NdisChainBufferAtFront ( Packet, Buffer ); NdisSendPackets ( AdapterContext->NdisBindingHandle, &Packet, 1 ); NDISProtocolDispatchWrite_exit: if ( STATUS_PENDING != status ) { Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); } return( status ); } /* end of NDISProtocolDispatchWrite */ #ifdef NDIS51 static VOID NDISProtocolWriteCancel ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PADAPTER_CONTEXT AdapterContext; PLIST_ENTRY IrpEntry; PNDIS_PACKET Packet; KdPrint(( "Entering NDISProtocolWriteCancel()\n" )); IoReleaseCancelSpinLock( Irp->CancelIrql ); Packet = NULL; AdapterContext = ( PADAPTER_CONTEXT )Irp->Tail.Overlay.DriverContext[0]; NdisAcquireSpinLock( &AdapterContext->Lock ); for ( IrpEntry = AdapterContext->PendedWrites.Flink; IrpEntry != &AdapterContext->PendedWrites; IrpEntry = IrpEntry->Flink ) { if ( Irp == CONTAINING_RECORD( IrpEntry, IRP, Tail.Overlay.ListEntry ) ) { Packet = ( PNDIS_PACKET )Irp->Tail.Overlay.DriverContext[1]; PrivateSendReferenceCount( Packet ); break; } } /* end of for */ NdisReleaseSpinLock( &AdapterContext->Lock ); if ( NULL != Packet ) { NdisCancelSendPackets ( AdapterContext->NdisBindingHandle, NDIS_GET_PACKET_CANCEL_ID( Packet ) ); PrivateSendDereferenceCount( Packet ); } return; } /* end of NDISProtocolWriteCancel */ #endif static NTSTATUS NDISProtocolDispatchCleanup ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PADAPTER_CONTEXT AdapterContext; PIO_STACK_LOCATION IrpStackLocation; NTSTATUS status; NDIS_STATUS ndis_status; ULONG PacketFilter; ULONG BytesProcessed; KdPrint(( "Entering NDISProtocolDispatchCleanup()\n" )); IrpStackLocation = IoGetCurrentIrpStackLocation( Irp ); AdapterContext = IrpStackLocation->FileObject->FsContext; if ( NULL != AdapterContext ) { NdisAcquireSpinLock( &AdapterContext->Lock ); SET_FLAGS( AdapterContext->Flags, PRIVATE_OPEN_FLAGS, PRIVATE_OPEN_IDLE ); AdapterContext->FileObject = NULL; NdisReleaseSpinLock( &AdapterContext->Lock ); PacketFilter = 0; ndis_status = PrivateValidateOpenAndDoRequest ( AdapterContext, NdisRequestSetInformation, OID_GEN_CURRENT_PACKET_FILTER, &PacketFilter, sizeof( PacketFilter ), &BytesProcessed, FALSE ); if ( NDIS_STATUS_SUCCESS != ndis_status) { ndis_status = NDIS_STATUS_SUCCESS; } PrivateCancelPendingReads( AdapterContext ); } status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return( status ); } /* end of NDISProtocolDispatchCleanup */ static NTSTATUS NDISProtocolDispatchDeviceControl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PADAPTER_CONTEXT AdapterContext; PIO_STACK_LOCATION IrpStackLocation; NDIS_STATUS ndis_status; NTSTATUS status; ULONG IoControlCode; ULONG InputBufferLength; ULONG OutputBufferLength; ULONG TransferSize; PVOID TransferBuffer; KdPrint(( "Entering NDISProtocolDispatchDeviceControl()\n" )); TransferBuffer = Irp->AssociatedIrp.SystemBuffer; IrpStackLocation = IoGetCurrentIrpStackLocation(Irp); IoControlCode = IrpStackLocation->Parameters.DeviceIoControl.IoControlCode; InputBufferLength = IrpStackLocation->Parameters.DeviceIoControl.InputBufferLength; OutputBufferLength = IrpStackLocation->Parameters.DeviceIoControl.OutputBufferLength; AdapterContext = ( PADAPTER_CONTEXT )IrpStackLocation->FileObject->FsContext; TransferSize = 0; switch ( IoControlCode ) { case IOCTL_NDISPROTOCOL_BIND_WAIT: if ( NdisWaitEvent( &BindsComplete, 5000 ) ) { status = STATUS_SUCCESS; } else { status = STATUS_TIMEOUT; } break; case IOCTL_NDISPROTOCOL_QUERY_BINDING: ndis_status = PrivateQueryBinding ( TransferBuffer, InputBufferLength, OutputBufferLength, &TransferSize ); PrivateNdisStatusToNtStatus( ndis_status, &status ); break; case IOCTL_NDISPROTOCOL_OPEN_DEVICE: if ( NULL != AdapterContext ) { status = STATUS_DEVICE_BUSY; break; } status = PrivateOpenDevice ( TransferBuffer, InputBufferLength, IrpStackLocation->FileObject, &AdapterContext ); if ( NT_SUCCESS( status ) ) { IrpStackLocation->FileObject->FsContext = ( PVOID )AdapterContext; } break; case IOCTL_NDISPROTOCOL_GET_OID_VALUE: if ( NULL != AdapterContext ) { ndis_status = PrivateGetOidValue ( AdapterContext, TransferBuffer, OutputBufferLength, &TransferSize ); PrivateNdisStatusToNtStatus( ndis_status, &status ); } else { status = STATUS_DEVICE_NOT_CONNECTED; } break; case IOCTL_NDISPROTOCOL_SET_OID_VALUE: if ( NULL != AdapterContext ) { TransferSize = InputBufferLength; ndis_status = PrivateSetOidValue ( AdapterContext, TransferBuffer, TransferSize ); PrivateNdisStatusToNtStatus( ndis_status, &status ); } else { status = STATUS_DEVICE_NOT_CONNECTED; } break; case IOCTL_NDISPROTOCOL_SET_ETHER_TYPE: if ( InputBufferLength < sizeof( EtherType ) ) { status = STATUS_BUFFER_TOO_SMALL; } else { EtherType = *( unsigned short int * )TransferBuffer; TransferSize = sizeof( unsigned short int ); status = STATUS_SUCCESS; } break; case IOCTL_NDISPROTOCOL_GET_PRIVATEFLAGS: if ( OutputBufferLength != sizeof( PrivateFlags ) ) { status = STATUS_INVALID_BUFFER_SIZE; } else { TransferSize = OutputBufferLength; RtlCopyMemory ( TransferBuffer, &PrivateFlags, TransferSize ); status = STATUS_SUCCESS; } break; case IOCTL_NDISPROTOCOL_SET_PRIVATEFLAGS: if ( InputBufferLength != sizeof( PrivateFlags ) ) { status = STATUS_INVALID_BUFFER_SIZE; } else { TransferSize = InputBufferLength; RtlCopyMemory ( &PrivateFlags, TransferBuffer, TransferSize ); status = STATUS_SUCCESS; } break; default: status = STATUS_NOT_SUPPORTED; break; } /* end of switch */ if ( STATUS_PENDING != status ) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = TransferSize; IoCompleteRequest( Irp, IO_NO_INCREMENT ); } return( status ); } /* end of NDISProtocolDispatchDeviceControl */ static VOID NDISProtocolDriverUnload ( IN PDRIVER_OBJECT DriverObject ) { PDEVICE_OBJECT NextDeviceObject; PDEVICE_EXTENSION DeviceExtension; NDIS_STATUS ndis_status; KdPrint(( "Entering NDISProtocolDriverUnload()\n" )); NextDeviceObject = DriverObject->DeviceObject; while ( NextDeviceObject ) { DeviceExtension = ( PDEVICE_EXTENSION )NextDeviceObject->DeviceExtension; NextDeviceObject = NextDeviceObject->NextDevice; NDISProtocolDeleteDevice( DeviceExtension->DeviceObject ); } /* end of while */ if ( NULL != NdisProtocolHandle ) { NdisDeregisterProtocol ( &ndis_status, NdisProtocolHandle ); NdisProtocolHandle = NULL; } NdisFreeSpinLock( &Lock ); return; } /* end of NDISProtocolDriverUnload */ static PNDIS_PACKET PrivateAllocateReceivePacket ( IN PADAPTER_CONTEXT AdapterContext, IN UINT DataLength, OUT PUCHAR *pData ) { NDIS_STATUS ndis_status; PNDIS_PACKET Packet; PNDIS_BUFFER Buffer; PUCHAR Data; Packet = NULL; Buffer = NULL; Data = NULL; NdisAllocateMemoryWithTag ( &Data, DataLength, PRIVATETAG ); if ( NULL == Data ) { goto PrivateAllocateReceivePacket_exit; } NdisAllocateBuffer ( &ndis_status, &Buffer, AdapterContext->RecvBufferPool, Data, DataLength ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { goto PrivateAllocateReceivePacket_exit; } NdisAllocatePacket ( &ndis_status, &Packet, AdapterContext->RecvPacketPool ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { goto PrivateAllocateReceivePacket_exit; } NDIS_SET_PACKET_STATUS ( Packet, NDIS_STATUS_SUCCESS ); GETBUFFER( Packet ) = NULL; NdisChainBufferAtFront ( Packet, Buffer ); *pData = Data; PrivateAllocateReceivePacket_exit: if ( NULL == Packet ) { if ( NULL != Buffer ) { NdisFreeBuffer( Buffer ); Buffer = NULL; } if ( NULL != Data ) { NdisFreeMemory( Data, 0, 0 ); Data = NULL; } } return( Packet ); } /* end of PrivateAllocateReceivePacket */ static VOID PrivateCancelPendingReads ( IN PADAPTER_CONTEXT AdapterContext ) { PIRP Irp; PLIST_ENTRY IrpEntry; PrivateReferenceCount( AdapterContext ); NdisAcquireSpinLock( &AdapterContext->Lock ); while ( !IsListEmpty( &AdapterContext->PendedReads ) ) { IrpEntry = AdapterContext->PendedReads.Flink; Irp = CONTAINING_RECORD( IrpEntry, IRP, Tail.Overlay.ListEntry ); if ( IoSetCancelRoutine( Irp, NULL ) ) { RemoveEntryList( IrpEntry ); NdisReleaseSpinLock( &AdapterContext->Lock ); Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NO_INCREMENT ); PrivateDereferenceCount( AdapterContext ); NdisAcquireSpinLock( &AdapterContext->Lock ); AdapterContext->PendedReadCount--; } else { NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateSleep( 1 ); NdisAcquireSpinLock( &AdapterContext->Lock ); } } /* end of while */ NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateDereferenceCount( AdapterContext ); return; } /* end of PrivateCancelPendingReads */ static NDIS_STATUS PrivateCreateBinding ( IN PADAPTER_CONTEXT AdapterContext, IN PWSTR DeviceName, IN ULONG DeviceNameLength ) { NDIS_STATUS ndis_status = NDIS_STATUS_SUCCESS; PADAPTER_CONTEXT TmpAdapterContext; BOOLEAN DoNotDisturb = FALSE; BOOLEAN BindComplete = FALSE; NDIS_STATUS OpenErrorStatus; UINT SelectedMediumIndex; NDIS_MEDIUM MediumArray[1] = { NdisMedium802_3 }; UINT BytesProcessed; ULONG MediaConnectStatus; KdPrint (( "Entering PrivateCreateBinding(): %ws\n", DeviceName )); TmpAdapterContext = PrivateLookupDevice( DeviceName, DeviceNameLength ); if ( NULL != TmpAdapterContext ) { PrivateDereferenceCount( TmpAdapterContext ); ndis_status = NDIS_STATUS_FAILURE; goto PrivateCreateBinding_exit; } NdisAcquireSpinLock( &AdapterContext->Lock ); if ( ( !TEST_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_IDLE ) ) || ( TEST_FLAGS( AdapterContext->Flags, PRIVATE_UNBIND_FLAGS, PRIVATE_UNBIND_RECEIVED ) ) ) { NdisReleaseSpinLock( &AdapterContext->Lock ); ndis_status = NDIS_STATUS_NOT_ACCEPTED; DoNotDisturb = TRUE; goto PrivateCreateBinding_exit; } SET_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_OPENING ); NdisReleaseSpinLock( &AdapterContext->Lock ); ndis_status = NdisAllocateMemoryWithTag ( &AdapterContext->DeviceName.Buffer, DeviceNameLength + sizeof( WCHAR ), PRIVATETAG ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { ndis_status = NDIS_STATUS_RESOURCES; goto PrivateCreateBinding_exit; } NdisMoveMemory ( AdapterContext->DeviceName.Buffer, DeviceName, DeviceNameLength ); *( PWCHAR )( ( PUCHAR )AdapterContext->DeviceName.Buffer + DeviceNameLength ) = L'\0'; NdisInitUnicodeString ( &AdapterContext->DeviceName, AdapterContext->DeviceName.Buffer ); NdisAllocatePacketPoolEx ( &ndis_status, &AdapterContext->SendPacketPool, MIN_SEND_PACKET_NUM, MAX_SEND_PACKET_NUM - MIN_SEND_PACKET_NUM, sizeof( SEND_PACKET_PROTOCOLRESERVED ) ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { KdPrint(( "NdisAllocatePacketPoolEx() for SendPacketPool failed\n" )); goto PrivateCreateBinding_exit; } NdisAllocatePacketPoolEx ( &ndis_status, &AdapterContext->RecvPacketPool, MIN_RECV_PACKET_NUM, MAX_RECV_PACKET_NUM - MIN_RECV_PACKET_NUM, sizeof( RECV_PACKET_PROTOCOLRESERVED ) ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { KdPrint(( "NdisAllocatePacketPoolEx() for RecvPacketPool failed\n" )); goto PrivateCreateBinding_exit; } NdisAllocateBufferPool ( &ndis_status, &AdapterContext->RecvBufferPool, MAX_RECV_BUFFER_NUM ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { KdPrint(( "NdisAllocateBufferPool() for RecvBufferPool failed\n" )); goto PrivateCreateBinding_exit; } NdisInitializeEvent( &AdapterContext->BindEvent ); NdisOpenAdapter ( &ndis_status, &OpenErrorStatus, &AdapterContext->NdisBindingHandle, &SelectedMediumIndex, MediumArray, sizeof( MediumArray ) / sizeof( NDIS_MEDIUM ), NdisProtocolHandle, ( NDIS_HANDLE )AdapterContext, &AdapterContext->DeviceName, 0, NULL ); if ( NDIS_STATUS_PENDING == ndis_status ) { NdisWaitEvent( &AdapterContext->BindEvent, 0 ); ndis_status = AdapterContext->BindStatus; } if ( NDIS_STATUS_SUCCESS != ndis_status ) { KdPrint(( "NdisOpenAdapter() failed (0x%08X)\n", ndis_status )); goto PrivateCreateBinding_exit; } BindComplete = TRUE; ( VOID )NdisQueryAdapterInstanceName ( &AdapterContext->AdapterInstanceName, AdapterContext->NdisBindingHandle ); ndis_status = PrivateNdisRequest ( AdapterContext, NdisRequestQueryInformation, OID_802_3_CURRENT_ADDRESS, AdapterContext->CurrentAddress, sizeof( AdapterContext->CurrentAddress ), &BytesProcessed ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { KdPrint(( "PrivateNdisRequest( OID_802_3_CURRENT_ADDRESS ) failed (0x%08X)\n", ndis_status )); goto PrivateCreateBinding_exit; } KdPrint (( "OID_802_3_CURRENT_ADDRESS: %02X-%02X-%02X-%02X-%02X-%02X\n", AdapterContext->CurrentAddress[0], AdapterContext->CurrentAddress[1], AdapterContext->CurrentAddress[2], AdapterContext->CurrentAddress[3], AdapterContext->CurrentAddress[4], AdapterContext->CurrentAddress[5] )); ndis_status = PrivateNdisRequest ( AdapterContext, NdisRequestQueryInformation, OID_GEN_MAC_OPTIONS, &AdapterContext->MacOptions, sizeof( AdapterContext->MacOptions ), &BytesProcessed ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { KdPrint(( "PrivateNdisRequest( OID_GEN_MAC_OPTIONS ) failed (0x%08X)\n", ndis_status )); goto PrivateCreateBinding_exit; } ndis_status = PrivateNdisRequest ( AdapterContext, NdisRequestQueryInformation, OID_GEN_MAXIMUM_FRAME_SIZE, &AdapterContext->MaximumFrameSize, sizeof( AdapterContext->MaximumFrameSize ), &BytesProcessed ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { KdPrint(( "PrivateNdisRequest( OID_GEN_MAXIMUM_FRAME_SIZE ) failed (0x%08X)\n", ndis_status )); goto PrivateCreateBinding_exit; } ndis_status = PrivateNdisRequest ( AdapterContext, NdisRequestQueryInformation, OID_GEN_MEDIA_CONNECT_STATUS, &MediaConnectStatus, sizeof( MediaConnectStatus ), &BytesProcessed ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { KdPrint(( "PrivateNdisRequest( OID_GEN_MEDIA_CONNECT_STATUS ) failed (0x%08X)\n", ndis_status )); goto PrivateCreateBinding_exit; } if ( NdisMediaStateConnected == MediaConnectStatus ) { SET_FLAGS( AdapterContext->Flags, PRIVATE_MEDIA_FLAGS, PRIVATE_MEDIA_CONNECTED ); } else { SET_FLAGS( AdapterContext->Flags, PRIVATE_MEDIA_FLAGS, PRIVATE_MEDIA_DISCONNECTED ); } AdapterContext->PowerState = NetDeviceStateD0; NdisAcquireSpinLock( &AdapterContext->Lock ); SET_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_ACTIVE ); if ( TEST_FLAGS( AdapterContext->Flags, PRIVATE_UNBIND_FLAGS, PRIVATE_UNBIND_RECEIVED ) ) { ndis_status = NDIS_STATUS_FAILURE; } NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateCreateBinding_exit: if ( ( NDIS_STATUS_SUCCESS != ndis_status ) && ( !DoNotDisturb ) ) { NdisAcquireSpinLock( &AdapterContext->Lock ); if ( BindComplete ) { SET_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_ACTIVE ); } else if ( TEST_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_OPENING ) ) { SET_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_FAILED ); } NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateShutdownBinding( AdapterContext ); } return ( ndis_status ); } /* end of PrivateCreateBinding */ static VOID PrivateDereferenceCount ( IN PADAPTER_CONTEXT AdapterContext ) { #if 0 KdPrint (( "PrivateDereferenceCount: 0x%08X 0x%08X 0x%08X\n", AdapterContext, &AdapterContext->ReferenceCount, AdapterContext->ReferenceCount )); #endif if ( 0 == NdisInterlockedDecrement( &AdapterContext->ReferenceCount ) ) { NdisFreeMemory( AdapterContext, 0, 0 ); } return; } /* end of PrivateDereferenceCount */ static VOID PrivateFlushReceiveQueue ( IN PADAPTER_CONTEXT AdapterContext ) { PLIST_ENTRY RecvPacketEntry; PNDIS_PACKET RecvPacket; PrivateReferenceCount( AdapterContext ); NdisAcquireSpinLock( &AdapterContext->Lock ); while ( !IsListEmpty( &AdapterContext->RecvPacketQueue ) ) { RecvPacketEntry = AdapterContext->RecvPacketQueue.Flink; RemoveEntryList( RecvPacketEntry ); AdapterContext->RecvPacketCount--; NdisReleaseSpinLock( &AdapterContext->Lock ); RecvPacket = GETRECVPACKET( RecvPacketEntry ); PrivateFreeReceivePacket( AdapterContext, RecvPacket ); PrivateDereferenceCount( AdapterContext ); NdisAcquireSpinLock( &AdapterContext->Lock ); } /* end of while */ NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateDereferenceCount( AdapterContext ); return; } /* end of PrivateFlushReceiveQueue */ static VOID PrivateFreeAdapterContextResources ( IN PADAPTER_CONTEXT AdapterContext ) { if ( NULL != AdapterContext->SendPacketPool ) { NdisFreePacketPool( AdapterContext->SendPacketPool ); AdapterContext->SendPacketPool = NULL; } if ( NULL != AdapterContext->RecvPacketPool ) { NdisFreePacketPool( AdapterContext->RecvPacketPool ); AdapterContext->RecvPacketPool = NULL; } if ( NULL != AdapterContext->RecvBufferPool ) { NdisFreeBufferPool( AdapterContext->RecvBufferPool ); AdapterContext->RecvBufferPool = NULL; } if ( NULL != AdapterContext->SendBufferPool ) { NdisFreeBufferPool( AdapterContext->SendBufferPool ); AdapterContext->SendBufferPool = NULL; } if ( NULL != AdapterContext->DeviceName.Buffer ) { NdisFreeMemory( AdapterContext->DeviceName.Buffer, 0, 0 ); AdapterContext->DeviceName.Buffer = NULL; AdapterContext->DeviceName.Length = AdapterContext->DeviceName.MaximumLength = 0; } if ( NULL != AdapterContext->AdapterInstanceName.Buffer ) { NdisFreeMemory( AdapterContext->AdapterInstanceName.Buffer, 0, 0 ); AdapterContext->AdapterInstanceName.Buffer = NULL; AdapterContext->AdapterInstanceName.Length = AdapterContext->AdapterInstanceName.MaximumLength = 0; } return; } /* end of PrivateFreeAdapterContextResources */ static VOID PrivateFreeReceivePacket ( IN PADAPTER_CONTEXT AdapterContext, IN PNDIS_PACKET Packet ) { PNDIS_BUFFER FirstBuffer; UINT TotalBufferLength; UINT FirstBufferLength; PVOID FirstBufferVA; if ( NdisGetPoolFromPacket( Packet ) == AdapterContext->RecvPacketPool ) { #ifdef NDIS51 NdisGetFirstBufferFromPacketSafe ( Packet, &FirstBuffer, &FirstBufferVA, &FirstBufferLength, &TotalBufferLength, NormalPagePriority ); #else NdisGetFirstBufferFromPacket ( Packet, &FirstBuffer, &FirstBufferVA, &FirstBufferLength, &TotalBufferLength ); #endif NdisFreePacket( Packet ); NdisFreeBuffer( FirstBuffer ); NdisFreeMemory ( FirstBufferVA, 0, 0 ); } else { NdisReturnPackets ( &Packet, 1 ); } return; } /* end of PrivateFreeReceivePacket */ static NDIS_STATUS PrivateGetOidValue ( IN PADAPTER_CONTEXT AdapterContext, OUT PVOID OutputBuffer, IN ULONG OutputBufferLength, OUT PULONG BytesWritten ) { NDIS_STATUS ndis_status; NDIS_OID Oid; POIDVALUE OidValue; KdPrint(( "Entering PrivateGetOidValue()\n" )); if ( OutputBufferLength < sizeof( OIDVALUE ) ) { ndis_status = NDIS_STATUS_BUFFER_TOO_SHORT; goto PrivateGetOidValue_exit; } OidValue = ( POIDVALUE )OutputBuffer; Oid = OidValue->Oid; NdisAcquireSpinLock( &AdapterContext->Lock ); if ( !TEST_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_ACTIVE ) ) { NdisReleaseSpinLock( &AdapterContext->Lock ); ndis_status = NDIS_STATUS_FAILURE; goto PrivateGetOidValue_exit; } NdisInterlockedIncrement( &AdapterContext->PendedWriteCount ); NdisReleaseSpinLock( &AdapterContext->Lock ); ndis_status = PrivateNdisRequest ( AdapterContext, NdisRequestQueryInformation, Oid, OidValue->Value, OutputBufferLength - FIELD_OFFSET( OIDVALUE, Value ), BytesWritten ); NdisAcquireSpinLock( &AdapterContext->Lock ); NdisInterlockedDecrement( &AdapterContext->PendedWriteCount ); NdisReleaseSpinLock( &AdapterContext->Lock ); if ( NDIS_STATUS_SUCCESS == ndis_status ) { *BytesWritten += FIELD_OFFSET( OIDVALUE, Value ); } PrivateGetOidValue_exit: return( ndis_status ); } /* end of PrivateGetOidValue */ static PADAPTER_CONTEXT PrivateLookupDevice ( IN PWSTR DeviceName, IN ULONG DeviceNameLength ) { PADAPTER_CONTEXT AdapterContext = NULL; PLIST_ENTRY Link; KdPrint(( "Entering PrivateLookupDevice()\n" )); NdisAcquireSpinLock( &Lock ); for ( Link = AdapterContextList.Flink; Link != &AdapterContextList; Link = Link->Flink ) { AdapterContext = CONTAINING_RECORD( Link, ADAPTER_CONTEXT, Link ); if ( ( AdapterContext->DeviceName.Length == DeviceNameLength ) && ( 1 == NdisEqualMemory( AdapterContext->DeviceName.Buffer, DeviceName, DeviceNameLength ) ) ) { PrivateReferenceCount( AdapterContext ); break; } AdapterContext = NULL; } /* end of for */ NdisReleaseSpinLock( &Lock ); return( AdapterContext ); } /* end of PrivateLookupDevice */ static NDIS_STATUS PrivateNdisRequest ( IN PADAPTER_CONTEXT AdapterContext, IN NDIS_REQUEST_TYPE RequestType, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN UINT InformationBufferLength, OUT PUINT BytesProcessed ) { REQUEST_CONTEXT RequestContext; PNDIS_REQUEST Request; NDIS_STATUS ndis_status; NdisInitializeEvent( &RequestContext.NdisRequestEvent ); Request = &RequestContext.NdisRequest; Request->RequestType = RequestType; switch ( RequestType ) { case NdisRequestQueryInformation: Request->DATA.QUERY_INFORMATION.Oid = Oid; Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer; Request->DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength; break; case NdisRequestSetInformation: Request->DATA.SET_INFORMATION.Oid = Oid; Request->DATA.SET_INFORMATION.InformationBuffer = InformationBuffer; Request->DATA.SET_INFORMATION.InformationBufferLength = InformationBufferLength; break; case NdisRequestQueryStatistics: default: break; } /* end of switch */ NdisRequest ( &ndis_status, AdapterContext->NdisBindingHandle, Request ); if ( NDIS_STATUS_PENDING == ndis_status ) { NdisWaitEvent( &RequestContext.NdisRequestEvent, 0 ); ndis_status = RequestContext.Status; } if ( NDIS_STATUS_SUCCESS == ndis_status ) { *BytesProcessed = ( NdisRequestQueryInformation == RequestType ) ? Request->DATA.QUERY_INFORMATION.BytesWritten: Request->DATA.SET_INFORMATION.BytesRead; if ( *BytesProcessed > InformationBufferLength ) { *BytesProcessed = InformationBufferLength; } } return ( ndis_status ); } /* end of PrivateNdisRequest */ static VOID PrivateNdisStatusToNtStatus ( IN NDIS_STATUS NdisStatus, IN NTSTATUS *NtStatus ) { if ( ( NDIS_STATUS_SUCCESS == NdisStatus ) || ( NDIS_STATUS_PENDING == NdisStatus ) || ( NDIS_STATUS_BUFFER_OVERFLOW == NdisStatus ) || ( NDIS_STATUS_FAILURE == NdisStatus ) || ( NDIS_STATUS_RESOURCES == NdisStatus ) || ( NDIS_STATUS_NOT_SUPPORTED == NdisStatus ) ) { *NtStatus = ( NTSTATUS )NdisStatus; } else if ( NDIS_STATUS_BUFFER_TOO_SHORT == NdisStatus ) { /* * The above NDIS status codes require a little special casing. */ *NtStatus = STATUS_BUFFER_TOO_SMALL; } else if ( NDIS_STATUS_INVALID_LENGTH == NdisStatus ) { *NtStatus = STATUS_INVALID_BUFFER_SIZE; } else if ( NDIS_STATUS_INVALID_DATA == NdisStatus ) { *NtStatus = STATUS_INVALID_PARAMETER; } else if ( NDIS_STATUS_ADAPTER_NOT_FOUND == NdisStatus ) { *NtStatus = STATUS_NO_MORE_ENTRIES; } else if ( NDIS_STATUS_ADAPTER_NOT_READY == NdisStatus ) { *NtStatus = STATUS_DEVICE_NOT_READY; } else { *NtStatus = STATUS_UNSUCCESSFUL; } return; } /* end of PrivateNdisStatusToNtStatus */ static NTSTATUS PrivateOpenDevice ( IN PWSTR DeviceName, IN ULONG DeviceNameLength, IN PFILE_OBJECT FileObject, OUT PADAPTER_CONTEXT *pAdapterContext ) { PADAPTER_CONTEXT AdapterContext; NTSTATUS status; ULONG PacketFilter; NDIS_STATUS ndis_status; ULONG BytesProcessed; KdPrint(( "Entering PrivateOpenDevice()\n" )); AdapterContext = NULL; AdapterContext = PrivateLookupDevice ( DeviceName, DeviceNameLength ); if ( NULL == AdapterContext ) { status = STATUS_OBJECT_NAME_NOT_FOUND; goto PrivateOpenDevice_exit; } NdisAcquireSpinLock( &AdapterContext->Lock ); if ( !TEST_FLAGS( AdapterContext->Flags, PRIVATE_OPEN_FLAGS, PRIVATE_OPEN_IDLE ) ) { NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateDereferenceCount( AdapterContext ); status = STATUS_DEVICE_BUSY; goto PrivateOpenDevice_exit; } AdapterContext->FileObject = FileObject; SET_FLAGS( AdapterContext->Flags, PRIVATE_OPEN_FLAGS, PRIVATE_OPEN_ACTIVE ); NdisReleaseSpinLock( &AdapterContext->Lock ); PacketFilter = DEFAULT_PACKET_FILTER; ndis_status = PrivateValidateOpenAndDoRequest ( AdapterContext, NdisRequestSetInformation, OID_GEN_CURRENT_PACKET_FILTER, &PacketFilter, sizeof( PacketFilter ), &BytesProcessed, TRUE ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { NdisAcquireSpinLock( &AdapterContext->Lock ); SET_FLAGS( AdapterContext->Flags, PRIVATE_OPEN_FLAGS, PRIVATE_OPEN_IDLE ); AdapterContext->FileObject = NULL; NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateDereferenceCount( AdapterContext ); PrivateNdisStatusToNtStatus( ndis_status, &status ); goto PrivateOpenDevice_exit; } *pAdapterContext = AdapterContext; status = STATUS_SUCCESS; PrivateOpenDevice_exit: return( status ); } /* end of PrivateOpenDevice */ static NDIS_STATUS PrivateQueryBinding ( IN PUCHAR Buffer, IN ULONG InputBufferLength, IN ULONG OutputBufferLength, OUT PULONG BytesReturned ) { PADAPTER_CONTEXT AdapterContext; NDIS_STATUS ndis_status; PBINDINGINFO BindingInfo; PLIST_ENTRY ListEntry; ULONG Remaining; ULONG BindingIndex; KdPrint(( "Entering PrivateQueryBinding()\n" )); if ( InputBufferLength < sizeof( BINDINGINFO ) ) { ndis_status = NDIS_STATUS_RESOURCES; goto PrivateQueryBinding_exit; } if ( OutputBufferLength < sizeof( BINDINGINFO ) ) { ndis_status = NDIS_STATUS_BUFFER_OVERFLOW; goto PrivateQueryBinding_exit; } Remaining = OutputBufferLength - sizeof( BINDINGINFO ); BindingInfo = ( PBINDINGINFO )Buffer; BindingIndex = BindingInfo->BindingIndex; ndis_status = NDIS_STATUS_ADAPTER_NOT_FOUND; AdapterContext = NULL; NdisAcquireSpinLock( &Lock ); for ( ListEntry = AdapterContextList.Flink; ListEntry != &AdapterContextList; ListEntry = ListEntry->Flink ) { AdapterContext = CONTAINING_RECORD( ListEntry, ADAPTER_CONTEXT, Link ); NdisAcquireSpinLock( &AdapterContext->Lock ); if ( !TEST_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_ACTIVE ) ) { NdisReleaseSpinLock( &AdapterContext->Lock ); continue; } if ( 0 == BindingIndex ) { BindingInfo->DeviceNameLength = AdapterContext->DeviceName.Length + sizeof( WCHAR ); BindingInfo->AdapterInstanceNameLength = AdapterContext->AdapterInstanceName.Length + sizeof( WCHAR ); if ( Remaining < BindingInfo->DeviceNameLength + BindingInfo->AdapterInstanceNameLength ) { NdisReleaseSpinLock( &AdapterContext->Lock ); ndis_status = NDIS_STATUS_BUFFER_OVERFLOW; break; } NdisZeroMemory ( ( PUCHAR )Buffer + sizeof( BINDINGINFO ), BindingInfo->DeviceNameLength + BindingInfo->AdapterInstanceNameLength ); BindingInfo->DeviceNameOffset = sizeof( BINDINGINFO ); NdisMoveMemory ( ( PUCHAR )Buffer + BindingInfo->DeviceNameOffset, AdapterContext->DeviceName.Buffer, AdapterContext->DeviceName.Length ); BindingInfo->AdapterInstanceNameOffset = BindingInfo->DeviceNameOffset + BindingInfo->DeviceNameLength; NdisMoveMemory ( ( PUCHAR )Buffer + BindingInfo->AdapterInstanceNameOffset, AdapterContext->AdapterInstanceName.Buffer, AdapterContext->AdapterInstanceName.Length ); NdisReleaseSpinLock( &AdapterContext->Lock ); *BytesReturned = BindingInfo->AdapterInstanceNameOffset + BindingInfo->AdapterInstanceNameLength; ndis_status = NDIS_STATUS_SUCCESS; break; } NdisReleaseSpinLock( &AdapterContext->Lock ); BindingIndex--; } /* end of for */ NdisReleaseSpinLock( &Lock ); PrivateQueryBinding_exit: return( ndis_status ); } /* end of PrivateQueryBinding */ static VOID PrivateQueueReceivePacket ( IN PADAPTER_CONTEXT AdapterContext, IN PNDIS_PACKET RecvPacket ) { PLIST_ENTRY ListEntry; PLIST_ENTRY DiscardEntry; PNDIS_PACKET DiscardPacket; KdPrint(( "Entering PrivateQueueReceivePacket()\n" )); ListEntry = GETLINK( RecvPacket ); PrivateReferenceCount( AdapterContext ); NdisAcquireSpinLock( &AdapterContext->Lock ); if ( TEST_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_ACTIVE ) && ( AdapterContext->PowerState == NetDeviceStateD0 ) ) { InsertTailList ( &AdapterContext->RecvPacketQueue, ListEntry ); AdapterContext->RecvPacketCount++; } else { NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateFreeReceivePacket( AdapterContext, RecvPacket ); PrivateDereferenceCount( AdapterContext ); goto PrivateQueueReceivePacket_exit; } if ( AdapterContext->RecvPacketCount > MAX_RECV_QUEUE_NUM ) { DiscardEntry = AdapterContext->RecvPacketQueue.Flink; RemoveEntryList( DiscardEntry ); AdapterContext->RecvPacketCount--; NdisReleaseSpinLock( &AdapterContext->Lock ); DiscardPacket = GETRECVPACKET( DiscardEntry ); PrivateFreeReceivePacket( AdapterContext, DiscardPacket ); PrivateDereferenceCount( AdapterContext ); } else { NdisReleaseSpinLock( &AdapterContext->Lock ); } PrivateServiceReads( AdapterContext ); PrivateQueueReceivePacket_exit: return; } /* end of PrivateQueueReceivePacket */ static VOID PrivateReferenceCount ( IN PADAPTER_CONTEXT AdapterContext ) { #if 0 KdPrint (( "PrivateReferenceCount: 0x%08X 0x%08X 0x%08X\n", AdapterContext, &AdapterContext->ReferenceCount, AdapterContext->ReferenceCount )); #endif /* * LONG NdisInterlockedIncrement * ( * IN PLONG Addend * ); */ NdisInterlockedIncrement( &AdapterContext->ReferenceCount ); return; } /* end of PrivateReferenceCount */ static VOID PrivateSendDereferenceCount ( IN PNDIS_PACKET Packet ) { #if 0 KdPrint (( "PrivateSendDereferenceCount: 0x%08X 0x%08X 0x%08X\n", Packet, &GETREFERENCECOUNT( Packet ), GETREFERENCECOUNT( Packet ) )); #endif if ( 0 == NdisInterlockedDecrement( &GETREFERENCECOUNT( Packet ) ) ) { /* * Free it. */ NdisFreePacket( Packet ); } return; } /* end of PrivateSendDereferenceCount */ static VOID PrivateSendReferenceCount ( IN PNDIS_PACKET Packet ) { #if 0 KdPrint (( "PrivateSendReferenceCount: 0x%08X 0x%08X 0x%08X\n", Packet, &GETREFERENCECOUNT( Packet ), GETREFERENCECOUNT( Packet ) )); #endif NdisInterlockedIncrement( &GETREFERENCECOUNT( Packet ) ); return; } /* end of PrivateSendReferenceCount */ static VOID PrivateServiceReads ( IN PADAPTER_CONTEXT AdapterContext ) { PIRP Irp; PLIST_ENTRY IrpEntry; PNDIS_PACKET RecvPacket; PLIST_ENTRY RecvPacketEntry; PNDIS_BUFFER Buffer; PUCHAR src, dst; ULONG srclen, dstlen, len; KdPrint(( "Entering PrivateServiceReads()\n" )); PrivateReferenceCount( AdapterContext ); NdisAcquireSpinLock( &AdapterContext->Lock ); while ( !IsListEmpty( &AdapterContext->PendedReads ) && !IsListEmpty( &AdapterContext->RecvPacketQueue ) ) { IrpEntry = AdapterContext->PendedReads.Flink; Irp = CONTAINING_RECORD( IrpEntry, IRP, Tail.Overlay.ListEntry ); if ( IoSetCancelRoutine( Irp, NULL ) ) { RemoveEntryList( IrpEntry ); } else { continue; } RecvPacketEntry = AdapterContext->RecvPacketQueue.Flink; RemoveEntryList( RecvPacketEntry ); AdapterContext->RecvPacketCount--; NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateDereferenceCount( AdapterContext ); RecvPacket = GETRECVPACKET( RecvPacketEntry ); dst = MmGetSystemAddressForMdlSafe ( Irp->MdlAddress, NormalPagePriority ); dstlen = MmGetMdlByteCount( Irp->MdlAddress ); Buffer = RecvPacket->Private.Head; while ( ( 0 != dstlen ) && ( NULL != Buffer ) ) { NdisQueryBufferSafe ( Buffer, &src, &srclen, NormalPagePriority ); if ( NULL == src ) { break; } if ( srclen ) { len = PRIVATEMIN ( srclen, dstlen ); NdisMoveMemory ( dst, src, len ); dstlen -= len; dst += len; } NdisGetNextBuffer ( Buffer, &Buffer ); } /* end of while */ Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = MmGetMdlByteCount( Irp->MdlAddress ) - dstlen; IoCompleteRequest( Irp, IO_NO_INCREMENT ); PrivateFreeReceivePacket( AdapterContext, RecvPacket ); PrivateDereferenceCount( AdapterContext ); NdisAcquireSpinLock( &AdapterContext->Lock ); AdapterContext->PendedReadCount--; } /* end of while */ NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateDereferenceCount( AdapterContext ); return; } /* end of PrivateServiceReads */ static NDIS_STATUS PrivateSetOidValue ( IN PADAPTER_CONTEXT AdapterContext, OUT PVOID InputBuffer, IN ULONG InputBufferLength ) { NDIS_STATUS ndis_status; NDIS_OID Oid; POIDVALUE OidValue; ULONG BytesWritten; if ( InputBufferLength < sizeof( OIDVALUE ) ) { ndis_status = NDIS_STATUS_BUFFER_TOO_SHORT; goto PrivateSetOidValue_exit; } OidValue = ( POIDVALUE )InputBuffer; Oid = OidValue->Oid; if ( !PrivateValidateOid( Oid ) ) { ndis_status = NDIS_STATUS_INVALID_DATA; goto PrivateSetOidValue_exit; } NdisAcquireSpinLock( &AdapterContext->Lock ); if ( !TEST_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_ACTIVE ) ) { NdisReleaseSpinLock( &AdapterContext->Lock ); ndis_status = NDIS_STATUS_FAILURE; goto PrivateSetOidValue_exit; } NdisInterlockedIncrement( &AdapterContext->PendedWriteCount ); NdisReleaseSpinLock( &AdapterContext->Lock ); ndis_status = PrivateNdisRequest ( AdapterContext, NdisRequestSetInformation, Oid, OidValue->Value, InputBufferLength - FIELD_OFFSET( OIDVALUE, Value ), &BytesWritten ); NdisAcquireSpinLock( &AdapterContext->Lock ); NdisInterlockedDecrement( &AdapterContext->PendedWriteCount ); NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateSetOidValue_exit: return( ndis_status ); } /* end of PrivateSetOidValue */ static VOID PrivateShutdownBinding ( IN PADAPTER_CONTEXT AdapterContext ) { NDIS_STATUS ndis_status; BOOLEAN DoBindClosing = FALSE; KdPrint(( "Entering PrivateShutdownBinding()\n" )); NdisAcquireSpinLock( &AdapterContext->Lock ); if ( TEST_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_OPENING ) ) { NdisReleaseSpinLock( &AdapterContext->Lock ); goto PrivateShutdownBinding_exit; } if ( TEST_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_ACTIVE ) ) { SET_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_CLOSING ); DoBindClosing = TRUE; } NdisReleaseSpinLock( &AdapterContext->Lock ); if ( DoBindClosing ) { PrivateWaitForPendingIO( AdapterContext, TRUE ); PrivateFlushReceiveQueue( AdapterContext ); NdisInitializeEvent( &AdapterContext->BindEvent ); NdisCloseAdapter ( &ndis_status, AdapterContext->NdisBindingHandle ); if ( NDIS_STATUS_PENDING == ndis_status ) { NdisWaitEvent( &AdapterContext->BindEvent, 0 ); ndis_status = AdapterContext->BindStatus; } AdapterContext->NdisBindingHandle = NULL; NdisAcquireSpinLock( &AdapterContext->Lock ); SET_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_IDLE ); SET_FLAGS( AdapterContext->Flags, PRIVATE_UNBIND_FLAGS, 0 ); NdisReleaseSpinLock( &AdapterContext->Lock ); } NdisAcquireSpinLock( &Lock ); RemoveEntryList( &AdapterContext->Link ); NdisReleaseSpinLock( &Lock ); NdisFreeSpinLock( &AdapterContext->Lock ); PrivateFreeAdapterContextResources( AdapterContext ); PrivateDereferenceCount( AdapterContext ); PrivateShutdownBinding_exit: return; } /* end of PrivateShutdownBinding */ static VOID PrivateSleep ( IN UINT seconds ) { NDIS_EVENT SleepEvent; KdPrint(( "Entering PrivateSleep()\n" )); NdisInitializeEvent( &SleepEvent ); ( VOID )NdisWaitEvent( &SleepEvent, seconds * 1000 ); return; } /* end of PrivateSleep */ static BOOLEAN PrivateValidateOid ( IN NDIS_OID Oid ) { KdPrint(( "Entering PrivateValidateOid()\n" )); return( TRUE ); } /* end of PrivateValidateOid */ static NDIS_STATUS PrivateValidateOpenAndDoRequest ( IN PADAPTER_CONTEXT AdapterContext, IN NDIS_REQUEST_TYPE RequestType, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN UINT InformationBufferLength, OUT PUINT BytesProcessed, IN BOOLEAN WaitForPowerOn ) { NDIS_STATUS ndis_status; KdPrint(( "Entering PrivateValidateOpenAndDoRequest()\n" )); if ( NULL == AdapterContext ) { ndis_status = NDIS_STATUS_INVALID_DATA; goto PrivateValidateOpenAndDoRequest_exit; } NdisAcquireSpinLock( &AdapterContext->Lock ); if ( !TEST_FLAGS( AdapterContext->Flags, PRIVATE_BIND_FLAGS, PRIVATE_BIND_ACTIVE ) ) { NdisReleaseSpinLock( &AdapterContext->Lock ); ndis_status = NDIS_STATUS_INVALID_DATA; goto PrivateValidateOpenAndDoRequest_exit; } NdisInterlockedIncrement( &AdapterContext->PendedWriteCount ); NdisReleaseSpinLock( &AdapterContext->Lock ); if ( WaitForPowerOn ) { NdisWaitEvent( &AdapterContext->PoweredUpEvent, 4500 ); } ndis_status = PrivateNdisRequest ( AdapterContext, RequestType, Oid, InformationBuffer, InformationBufferLength, BytesProcessed ); NdisInterlockedDecrement( &AdapterContext->PendedWriteCount ); PrivateValidateOpenAndDoRequest_exit: return( ndis_status ); } /* end of PrivateValidateOpenAndDoRequest */ static VOID PrivateWaitForPendingIO ( IN PADAPTER_CONTEXT AdapterContext, IN BOOLEAN DoCancelPendingReads ) { NDIS_STATUS ndis_status; ULONG i; ULONG IoCount; KdPrint(( "Entering PrivateWaitForPendingIO()\n" )); #ifdef NDIS51 for ( i = 0; i < 60; i++ ) { /* * NDIS_STATUS NdisQueryPendingIoCount * ( * IN PVOID NdisBindingHandle * OUT PULONG IoCount * ); * * System support for NdisQueryPendingIoCount is available in * Windows XP and later OS versions. */ ndis_status = NdisQueryPendingIOCount ( AdapterContext->NdisBindingHandle, &IoCount ); if ( ( NDIS_STATUS_SUCCESS != ndis_status ) || ( 0 == IoCount ) ) { break; } PrivateSleep( 2 ); } /* end of for */ #endif for ( i = 0; i < 60; i++ ) { if ( 0 == AdapterContext->PendedWriteCount ) { break; } PrivateSleep( 1 ); } /* end of for */ if ( DoCancelPendingReads ) { while ( 0 != AdapterContext->PendedReadCount ) { PrivateCancelPendingReads( AdapterContext ); PrivateSleep( 1 ); } } KdPrint(( "Exiting PrivateWaitForPendingIO()\n" )); return; } /* end of PrivateWaitForPendingIO */ static VOID ProtocolOpenAdapterComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status, IN NDIS_STATUS OpenErrorStatus ) { PADAPTER_CONTEXT AdapterContext; KdPrint(( "Entering ProtocolOpenAdapterComplete()\n" )); AdapterContext = ( PADAPTER_CONTEXT )ProtocolBindingContext; AdapterContext->BindStatus = Status; NdisSetEvent( &AdapterContext->BindEvent ); return; } /* end of ProtocolOpenAdapterComplete */ static VOID ProtocolCloseAdapterComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status ) { PADAPTER_CONTEXT AdapterContext; KdPrint(( "Entering ProtocolCloseAdapterComplete()\n" )); AdapterContext = ( PADAPTER_CONTEXT )ProtocolBindingContext; AdapterContext->BindStatus = Status; NdisSetEvent( &AdapterContext->BindEvent ); return; } /* end of ProtocolCloseAdapterComplete */ static VOID ProtocolSendComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status ) { PIRP Irp; PIO_STACK_LOCATION IrpStackLocation; PADAPTER_CONTEXT AdapterContext; KdPrint(( "Entering ProtocolSendComplete()\n" )); AdapterContext = ( PADAPTER_CONTEXT )ProtocolBindingContext; Irp = GETIRP( Packet ); #ifdef NDIS51 IoSetCancelRoutine( Irp, NULL ); NdisAcquireSpinLock( &AdapterContext->Lock ); RemoveEntryList( &Irp->Tail.Overlay.ListEntry ); NdisReleaseSpinLock( &AdapterContext->Lock ); #endif PrivateSendDereferenceCount( Packet ); IrpStackLocation = IoGetCurrentIrpStackLocation( Irp ); if ( NDIS_STATUS_SUCCESS == Status ) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = IrpStackLocation->Parameters.Write.Length; } else { Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; Irp->IoStatus.Information = 0; } IoCompleteRequest( Irp, IO_NO_INCREMENT ); NdisInterlockedDecrement( &AdapterContext->PendedWriteCount ); PrivateDereferenceCount( AdapterContext ); return; } /* end of ProtocolSendComplete */ static VOID ProtocolTransferDataComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status, IN UINT BytesTransferred ) { PADAPTER_CONTEXT AdapterContext; PNDIS_BUFFER OriginalBuffer, PartialBuffer; KdPrint(( "Entering ProtocolTransferDataComplete()\n" )); AdapterContext = ( PADAPTER_CONTEXT )ProtocolBindingContext; OriginalBuffer = GETBUFFER( Packet ); if ( NULL != OriginalBuffer ) { NdisUnchainBufferAtFront ( Packet, &PartialBuffer ); NdisChainBufferAtBack ( Packet, OriginalBuffer ); NdisFreeBuffer( PartialBuffer ); } if ( NDIS_STATUS_SUCCESS == Status ) { PrivateQueueReceivePacket( AdapterContext, Packet ); } else { PrivateFreeReceivePacket( AdapterContext, Packet ); } return; } /* end of ProtocolTransferDataComplete */ static VOID ProtocolResetComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status ) { KdPrint(( "Entering ProtocolResetComplete()\n" )); return; } /* end of ProtocolResetComplete */ static VOID ProtocolRequestComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_REQUEST NdisRequest, IN NDIS_STATUS Status ) { PADAPTER_CONTEXT AdapterContext; PREQUEST_CONTEXT RequestContext; KdPrint(( "Entering ProtocolRequestComplete()\n" )); AdapterContext = ( PADAPTER_CONTEXT )ProtocolBindingContext; RequestContext = CONTAINING_RECORD( NdisRequest, REQUEST_CONTEXT, NdisRequest ); RequestContext->Status = Status; NdisSetEvent( &RequestContext->NdisRequestEvent ); return; } /* end of ProtocolRequestComplete */ static NDIS_STATUS ProtocolReceive ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ) { PADAPTER_CONTEXT AdapterContext; NDIS_STATUS ndis_status; struct etherheader *etherh; unsigned short int eth_type; PNDIS_PACKET RecvPacket; PNDIS_BUFFER OriginalBuffer, PartialBuffer; PUCHAR RecvData; UINT BytesTransferred; KdPrint(( "Entering ProtocolReceive ()\n" )); AdapterContext = ( PADAPTER_CONTEXT )ProtocolBindingContext; RecvPacket = NULL; RecvData = NULL; ndis_status = NDIS_STATUS_SUCCESS; if ( sizeof( struct etherheader ) != HeaderBufferSize ) { ndis_status = NDIS_STATUS_NOT_ACCEPTED; goto ProtocolReceive_exit; } etherh = ( struct etherheader * )HeaderBuffer; eth_type = swap_16( etherh->eth_type ); if ( ETH_P_8021P == eth_type ) { eth_type = *( unsigned short * )( ( unsigned char * )ðerh->eth_type + 4 ); } if ( ( PrivateFlags & PRIVATEFLAGS_ETHERTYPE ) && ( EtherType != eth_type ) ) { ndis_status = NDIS_STATUS_NOT_ACCEPTED; goto ProtocolReceive_exit; } RecvPacket = PrivateAllocateReceivePacket ( AdapterContext, HeaderBufferSize + PacketSize, &RecvData ); if ( NULL == RecvPacket ) { ndis_status = NDIS_STATUS_NOT_ACCEPTED; goto ProtocolReceive_exit; } NdisMoveMappedMemory ( RecvData, HeaderBuffer, HeaderBufferSize ); if( AdapterContext->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND ) { LookaheadBufferSize = PacketSize; } if ( PacketSize == LookaheadBufferSize ) { NdisCopyLookaheadData ( RecvData + HeaderBufferSize, LookAheadBuffer, LookaheadBufferSize, AdapterContext->MacOptions ); PrivateQueueReceivePacket( AdapterContext, RecvPacket ); } else { NdisAllocateBuffer ( &ndis_status, &PartialBuffer, AdapterContext->RecvBufferPool, RecvData + HeaderBufferSize, PacketSize ); if ( NDIS_STATUS_SUCCESS == ndis_status ) { NdisUnchainBufferAtFront ( RecvPacket, &OriginalBuffer ); GETBUFFER( RecvPacket ) = OriginalBuffer; NdisChainBufferAtBack ( RecvPacket, PartialBuffer ); NdisTransferData ( &ndis_status, AdapterContext->NdisBindingHandle, MacReceiveContext, 0, PacketSize, RecvPacket, &BytesTransferred ); } else { BytesTransferred = 0; } if ( NDIS_STATUS_PENDING != ndis_status ) { ProtocolTransferDataComplete ( ( NDIS_HANDLE )AdapterContext, RecvPacket, ndis_status, BytesTransferred ); } } ProtocolReceive_exit: return( ndis_status ); } /* end of ProtocolReceive */ static VOID ProtocolReceiveComplete ( IN NDIS_HANDLE ProtocolBindingContext ) { KdPrint(( "Entering ProtocolReceiveComplete()\n" )); return; } /* end of ProtocolReceiveComplete */ static VOID ProtocolStatus ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS GeneralStatus, IN PVOID StatusBuffer, IN UINT StatusBufferSize ) { PADAPTER_CONTEXT AdapterContext; KdPrint(( "Entering ProtocolStatus()\n" )); AdapterContext = ( PADAPTER_CONTEXT )ProtocolBindingContext; NdisAcquireSpinLock( &AdapterContext->Lock ); if ( NetDeviceStateD0 != AdapterContext->PowerState ) { goto ProtocolStatus_exit; } switch( GeneralStatus ) { case NDIS_STATUS_RESET_START: SET_FLAGS( AdapterContext->Flags, PRIVATE_RESET_FLAGS, PRIVATE_RESET_IN_PROGRESS ); break; case NDIS_STATUS_RESET_END: SET_FLAGS( AdapterContext->Flags, PRIVATE_RESET_FLAGS, PRIVATE_NOT_RESETTING ); break; case NDIS_STATUS_MEDIA_CONNECT: SET_FLAGS( AdapterContext->Flags, PRIVATE_MEDIA_FLAGS, PRIVATE_MEDIA_CONNECTED ); break; case NDIS_STATUS_MEDIA_DISCONNECT: SET_FLAGS( AdapterContext->Flags, PRIVATE_MEDIA_FLAGS, PRIVATE_MEDIA_DISCONNECTED ); break; default: break; } /* end of switch */ ProtocolStatus_exit: NdisReleaseSpinLock( &AdapterContext->Lock ); return; } /* end of ProtocolStatus */ static VOID ProtocolStatusComplete ( IN NDIS_HANDLE ProtocolBindingContext ) { KdPrint(( "Entering ProtocolStatusComplete()\n" )); return; } /* end of ProtocolStatusComplete */ static INT ProtocolReceivePacket ( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet ) { PADAPTER_CONTEXT AdapterContext; PNDIS_BUFFER FirstBuffer; UINT FirstBufferLength; UINT TotalBufferLength; struct etherheader *etherh; unsigned short int eth_type; NDIS_STATUS ndis_status; INT ReferenceCount = 0; PNDIS_PACKET RecvPacket; PUCHAR RecvData; UINT BytesCopied; KdPrint(( "Entering ProtocolReceivePacket()\n" )); AdapterContext = (PADAPTER_CONTEXT)ProtocolBindingContext; #ifdef NDIS51 NdisGetFirstBufferFromPacketSafe ( Packet, &FirstBuffer, ðerh, &FirstBufferLength, &TotalBufferLength, NormalPagePriority ); if ( NULL == etherh ) { FirstBufferLength = 0; } #else NdisGetFirstBufferFromPacket ( Packet, &FirstBuffer, ðerh, &FirstBufferLength, &TotalBufferLength ); #endif if ( FirstBufferLength < sizeof( struct etherheader ) ) { ndis_status = NDIS_STATUS_NOT_ACCEPTED; goto ProtocolReceivePacket_exit; } eth_type = swap_16( etherh->eth_type ); if ( ETH_P_8021P == eth_type ) { eth_type = *( unsigned short * )( ( unsigned char * )ðerh->eth_type + 4 ); } if ( ( PrivateFlags & PRIVATEFLAGS_ETHERTYPE ) && ( EtherType != eth_type ) ) { ndis_status = NDIS_STATUS_NOT_ACCEPTED; goto ProtocolReceivePacket_exit; } if ( NDIS_STATUS_RESOURCES == NDIS_GET_PACKET_STATUS( Packet ) ) { RecvPacket = PrivateAllocateReceivePacket ( AdapterContext, TotalBufferLength, &RecvData ); if ( NULL == RecvPacket ) { goto ProtocolReceivePacket_exit; } NdisCopyFromPacketToPacketSafe ( RecvPacket, 0, TotalBufferLength, Packet, 0, &BytesCopied, NormalPagePriority ); Packet = RecvPacket; } else { ReferenceCount = 1; } PrivateQueueReceivePacket( AdapterContext, Packet ); ProtocolReceivePacket_exit: return ( ReferenceCount ); } /* end of ProtocolReceivePacket */ static VOID ProtocolBindAdapter ( OUT PNDIS_STATUS Status, IN NDIS_HANDLE BindContext, IN PNDIS_STRING DeviceName, IN PVOID SystemSpecific1, IN PVOID SystemSpecific2 ) { PADAPTER_CONTEXT AdapterContext = NULL; NDIS_STATUS ndis_status; NDIS_STATUS ConfigurationStatus; NDIS_HANDLE ConfigurationHandle; KdPrint(( "Entering ProtocolBindAdapter()\n" )); ndis_status = NdisAllocateMemoryWithTag ( &AdapterContext, /* * 2006-04-30 15:59 明匡 * * 这个地方有一个低级而隐蔽的错误: * * sizeof( AdapterContext ), */ sizeof( ADAPTER_CONTEXT ), PRIVATETAG ); if ( NDIS_STATUS_SUCCESS != ndis_status ) { ndis_status = NDIS_STATUS_RESOURCES; goto ProtocolBindAdapter_exit; } NdisZeroMemory ( AdapterContext, sizeof( ADAPTER_CONTEXT ) ); NdisAllocateSpinLock( &AdapterContext->Lock ); InitializeListHead( &AdapterContext->PendedReads ); InitializeListHead( &AdapterContext->PendedWrites ); InitializeListHead( &AdapterContext->RecvPacketQueue ); NdisInitializeEvent( &AdapterContext->PoweredUpEvent ); NdisSetEvent( &AdapterContext->PoweredUpEvent ); KdPrint(( "SystemSpecific1: [%wZ]\n", ( PUNICODE_STRING )SystemSpecific1 )); NdisOpenProtocolConfiguration ( &ConfigurationStatus, &ConfigurationHandle, ( PNDIS_STRING )SystemSpecific1 ); if ( NDIS_STATUS_SUCCESS == ConfigurationStatus ) { PNDIS_CONFIGURATION_PARAMETER ParameterValue; NDIS_STRING Keyword = NDIS_STRING_CONST( "OnlyForSczTest" ); NdisReadConfiguration ( &ConfigurationStatus, &ParameterValue, ConfigurationHandle, &Keyword, NdisParameterString ); if ( ( NDIS_STATUS_SUCCESS == ConfigurationStatus ) && ( NdisParameterString == ParameterValue->ParameterType ) ) { KdPrint (( "NdisReadConfiguration(): %wZ", &ParameterValue->ParameterData.StringData )); } NdisCloseConfiguration( ConfigurationHandle ); } PrivateReferenceCount( AdapterContext ); NdisAcquireSpinLock( &Lock ); InsertTailList ( &AdapterContextList, &AdapterContext->Link ); NdisReleaseSpinLock( &Lock ); ndis_status = PrivateCreateBinding ( AdapterContext, DeviceName->Buffer, DeviceName->Length ); ProtocolBindAdapter_exit: *Status = ndis_status; KdPrint(( "Exiting ProtocolBindAdapter() = 0x%08X\n", ndis_status )); return; } /* end of ProtocolBindAdapter */ static VOID ProtocolUnbindAdapter ( OUT PNDIS_STATUS Status, IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE UnbindContext ) { PADAPTER_CONTEXT AdapterContext; KdPrint(( "Entering ProtocolUnbindAdapter()\n" )); AdapterContext = ( PADAPTER_CONTEXT )ProtocolBindingContext; NdisAcquireSpinLock( &AdapterContext->Lock ); SET_FLAGS( AdapterContext->Flags, PRIVATE_UNBIND_FLAGS, PRIVATE_UNBIND_RECEIVED ); NdisSetEvent( &AdapterContext->PoweredUpEvent ); NdisReleaseSpinLock( &AdapterContext->Lock ); PrivateShutdownBinding( AdapterContext ); *Status = NDIS_STATUS_SUCCESS; return; } /* end of ProtocolUnbindAdapter */ static NDIS_STATUS ProtocolPnPEvent ( IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT NetPnPEvent ) { PADAPTER_CONTEXT AdapterContext; NDIS_STATUS ndis_status; KdPrint(( "Entering ProtocolPnPEvent()\n" )); AdapterContext = ( PADAPTER_CONTEXT )ProtocolBindingContext; switch ( NetPnPEvent->NetEvent ) { case NetEventSetPower: AdapterContext->PowerState = *( PNET_DEVICE_POWER_STATE )NetPnPEvent->Buffer; if ( AdapterContext->PowerState > NetDeviceStateD0 ) { NdisInitializeEvent( &AdapterContext->PoweredUpEvent ); PrivateWaitForPendingIO( AdapterContext, FALSE ); PrivateFlushReceiveQueue( AdapterContext ); } else { NdisSetEvent( &AdapterContext->PoweredUpEvent ); } ndis_status = NDIS_STATUS_SUCCESS; break; case NetEventQueryPower: ndis_status = NDIS_STATUS_SUCCESS; break; case NetEventBindsComplete: NdisSetEvent( &BindsComplete ); ndis_status = NDIS_STATUS_SUCCESS; break; case NetEventQueryRemoveDevice: case NetEventCancelRemoveDevice: case NetEventReconfigure: case NetEventBindList: case NetEventPnPCapabilities: ndis_status = NDIS_STATUS_SUCCESS; break; default: ndis_status = NDIS_STATUS_NOT_SUPPORTED; break; } /* end of switch */ return( ndis_status ); } /* end of ProtocolPnPEvent */ static VOID ProtocolUnload ( VOID ) { KdPrint(( "Entering ProtocolUnload()\n" )); return; } /* end of ProtocolUnload */ NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NTSTATUS status; DWORD ExceptionCode; DWORD i; NDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics; NDIS_STATUS ndis_status; NDIS_STRING Name = NDIS_STRING_CONST( "NDISPROTOCOL" ); KdPrint(( "Entering DriverEntry()\n" )); __try { KdPrint(( "You should see this message [0]\n" )); NdisInitializeEvent( &BindsComplete ); InitializeListHead( &AdapterContextList ); NdisAllocateSpinLock( &Lock ); NdisZeroMemory ( &ProtocolCharacteristics, sizeof( ProtocolCharacteristics ) ); ProtocolCharacteristics.MajorNdisVersion = 5; ProtocolCharacteristics.MinorNdisVersion = 0; ProtocolCharacteristics.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete; ProtocolCharacteristics.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete; ProtocolCharacteristics.SendCompleteHandler = ProtocolSendComplete; ProtocolCharacteristics.TransferDataCompleteHandler = ProtocolTransferDataComplete; ProtocolCharacteristics.ResetCompleteHandler = ProtocolResetComplete; ProtocolCharacteristics.RequestCompleteHandler = ProtocolRequestComplete; ProtocolCharacteristics.ReceiveHandler = ProtocolReceive; ProtocolCharacteristics.ReceiveCompleteHandler = ProtocolReceiveComplete; ProtocolCharacteristics.StatusHandler = ProtocolStatus; ProtocolCharacteristics.StatusCompleteHandler = ProtocolStatusComplete; ProtocolCharacteristics.Name = Name; ProtocolCharacteristics.ReceivePacketHandler = ProtocolReceivePacket; ProtocolCharacteristics.BindAdapterHandler = ProtocolBindAdapter; ProtocolCharacteristics.UnbindAdapterHandler = ProtocolUnbindAdapter; ProtocolCharacteristics.PnPEventHandler = ProtocolPnPEvent; ProtocolCharacteristics.UnloadHandler = ProtocolUnload; NdisRegisterProtocol ( &ndis_status, &NdisProtocolHandle, &ProtocolCharacteristics, sizeof( ProtocolCharacteristics ) ); switch ( ndis_status ) { case NDIS_STATUS_SUCCESS: break; case NDIS_STATUS_BAD_CHARACTERISTICS: KdPrint(( "NdisRegisterProtocol() failed for NDIS_STATUS_BAD_CHARACTERISTICS\n" )); status = STATUS_UNSUCCESSFUL; __leave; case NDIS_STATUS_BAD_VERSION: KdPrint(( "NdisRegisterProtocol() failed for NDIS_STATUS_BAD_VERSION\n" )); status = STATUS_UNSUCCESSFUL; __leave; case NDIS_STATUS_RESOURCES: KdPrint(( "NdisRegisterProtocol() failed for NDIS_STATUS_RESOURCES\n" )); status = STATUS_UNSUCCESSFUL; __leave; default: KdPrint(( "NdisRegisterProtocol() failed for ndis_status(0x%08X)\n", ndis_status )); status = STATUS_UNSUCCESSFUL; __leave; } #ifdef NDIS51 HighCancelId = NdisGeneratePartialCancelId() << ( ( sizeof( ULONG ) - 1 ) * 8 ); KdPrint(( "DriverEntry: HighCancelId(0x%08X)\n", HighCancelId )); #endif DriverObject->DriverUnload = NDISProtocolDriverUnload; for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) { DriverObject->MajorFunction[i] = NDISProtocolDispatch; } /* end of for */ DriverObject->MajorFunction[IRP_MJ_READ ] = NDISProtocolDispatchRead; DriverObject->MajorFunction[IRP_MJ_WRITE ] = NDISProtocolDispatchWrite; DriverObject->MajorFunction[IRP_MJ_CLEANUP ] = NDISProtocolDispatchCleanup; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL ] = NDISProtocolDispatchDeviceControl; status = NDISProtocolCreateDevice ( DriverObject, 0 ); if ( !NT_SUCCESS( status ) ) { if ( NULL != NdisProtocolHandle ) { NdisDeregisterProtocol ( &ndis_status, NdisProtocolHandle ); NdisProtocolHandle = NULL; } } KdPrint(( "You should see this message [1]\n" )); } __except ( /* * filter-expression code */ ExceptionCode = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER ) { KdPrint(( "ExceptionCode: 0x%08X\n", ExceptionCode )); status = STATUS_UNSUCCESSFUL; } KdPrint(( "Exiting DriverEntry()\n" )); return( status ); } /* end of DriverEntry */ /************************************************************************/ -------------------------------------------------------------------------- NdisSetPacketPoolProtocolId()第二形参与eth_type有何关系,是一回事吗? 一定要留心KdPrint()出现的场合,否则可能面临BSOD: > the Unicode format codes (%C, %S, %lc, %ls, %wc, %ws, %wZ) can only be > used at IRQL PASSIVE_LEVEL. 参看NdisMRegisterDevice()的说明,例子代码ndisuio与文档有出入,并未调用该函 数。难道该函数只用于IMD、Miniport Driver,而不用于协议驱动? NdisAllocateSpinLock应该与NdisFreeSpinLock()配对出现吧,ndisuio中始终没有 出现NdisFreeSpinLock(),诡异。 NetDeviceStateD0是NET_DEVICE_POWER_STATE型枚举常量,在ndis.h中定义,我未查 到其具体涵义。 [7]介绍了NDIS_PACKET、NDIS_BUFFER之间的关系,很形象,非常不错,推荐阅读。 实现ProtocolReceive()时可能需要参看[8],ndisuio没有考虑[8]中所说情形。 ProtocolReceivePacket()与ProtocolReceive()的关系参看[9]。 [10]介绍了802.1p的帧格式,ndisuio接收报文时考虑了802.1p。 ProtocolBindAdapter()例程的第四形参SystemSpecific1可能如下: SystemSpecific1: [NDISUIO\Parameters\Adapters\{3F2F7F53-94CC-4C83-B683-4308C573712D}] 之所以说可能如下,是指{3F...2D}对应(虚拟)网卡,非固定值。这个串位于 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services下。缺省没有 Parameters\Adapters\{...},可以手工创建,并用NdisReadConfiguration()读取其 下的键值,已经测试通过。这个与协议驱动实无必然联系,盖因有人曾问起过 NdisReadConfiguration()的第四形参究竟在哪里,就实测了一次。显然这个问题的 答案是驱动相关的,记录于此仅为多一分感性认识。 -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NDISUIO\Parameters\Adapters\{3F2F7F53-94CC-4C83-B683-4308C573712D}] "OnlyForSczTest"="scz is here" -------------------------------------------------------------------------- 从调试过程中看到,先退出ProtocolBindAdapter(),再进入ProtocolPnPEvent()。 如果不通过Network Control Panel Applet (NCPA)安装协议驱动,而简单地在服务 列表中增加一项,则net start NDISProtocol加载协议驱动时,NDIS不会调用 ProtocolBindAdapter(),但仍会调用ProtocolPnPEvent()。 从DDK例子代码看,可以在ProtocolUnload()例程中做DriverUnload()例程所做的事, 但DDK文档未明确表示可以这样做。 2) sources [11]讨论了NDIS驱动的编译选项,建议阅读。 -------------------------------------------------------------------------- TARGETNAME=ndisprotocol TARGETPATH=obj TARGETTYPE=DRIVER TARGETLIBS=\ $(DDK_LIB_PATH)\ntoskrnl.lib \ $(DDK_LIB_PATH)\ndis.lib C_DEFINES=$(C_DEFINES) -DNDIS51=1 USE_PDB=1 INCLUDES= MSC_WARNING_LEVEL=-W3 -WX SOURCES=ndisprotocol.c -------------------------------------------------------------------------- 3) makefile -------------------------------------------------------------------------- !INCLUDE $(NTMAKEENV)\makefile.def -------------------------------------------------------------------------- 4) ndisprotocol.inf ; ------------------------------------------------------------------------ ; ; Copyright to satisfy the CHKINF utility ; [Version] Signature = "$Windows NT$" Class = NetTrans ClassGuid = {4D36E975-E325-11CE-BFC1-08002BE10318} Provider = %INFCreator% DriverVer = 08/10/2004,1.00.1993.9 ; ------------------------------------------------------------------------ [Manufacturer] %INFCreator% = NDISProtocolSection ; ------------------------------------------------------------------------ [NDISProtocolSection] %DESCRIPTION% = DDInstall,nsfocus_ndisprotocol ; ------------------------------------------------------------------------ [SourceDisksNames.x86] 1 = %DiskDescription%,,, [SourceDisksFiles.x86] ndisprotocol.sys = 1 [DestinationDirs] DefaultDestDir = 10,system32\drivers FileList = 10,system32\drivers ; ------------------------------------------------------------------------ [DDInstall.NTx86] AddReg = DDInstall.NTx86.Reg Characteristics = 0x00 Copyfiles = FileList [FileList] ndisprotocol.sys,,,0x00000002 ; ------------------------------------------------------------------------ [DDInstall.NTx86.Services] AddService = NDISProtocol,,ServiceInstall [ServiceInstall] DisplayName = %FriendlyName% ; friendly name ServiceType = 0x00000001 ; SERVICE_KERNEL_DRIVER StartType = 0x3 ; SERVICE_DEMAND_START ErrorControl = 0x1 ; SERVICE_ERROR_NORMAL ServiceBinary = %10%\system32\drivers\ndisprotocol.sys LoadOrderGroup = NDIS Description = %DESCRIPTION% ; ------------------------------------------------------------------------ [DDInstall.NTx86.Remove.Services] DelService = NDISProtocol ; ------------------------------------------------------------------------ [DDInstall.NTx86.Reg] HKR,Ndi,Service,,NDISProtocol HKR,Ndi,HelpText,,%DESCRIPTION% HKR,Ndi\Interfaces,UpperRange,,noupper HKR,Ndi\Interfaces,LowerRange,,"ndis5" ; ------------------------------------------------------------------------ [Strings] INFCreator = "The NDISProtocol Software" DESCRIPTION = "The NDISProtocol Driver" DiskDescription = "The NDISProtocol Software Disk" FriendlyName = "NDISProtocol" ; ------------------------------------------------------------------------ 编写INF文件时,参看DDK中"Installation Requirements for Network Protocols"。 如果安装失败,请检查%systemroot%\setupapi.log文件。 假设用FastInst.exe或NCPA安装INF文件时碰到如下错误信息: > Error E000020B in UpdateDriverForPlugAndPlayDevices: ERROR_NO_SUCH_DEVINST > #E154 类别安装程式失败。 错误 0xe0000208: 操作无法在尚未注册的设备信息元素上运行。 请立即用chkinf.bat(DDK自带工具)检查一下INF文件,此时可能有低级错误出现,比 如我就碰上"AddReg项不在正确的节内"。 HKR可能对应: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E975-E325-11CE-BFC1-08002BE10318}\{03130807-B5F2-47A1-81B0-B870D16F272B} 最后的{03130807-B5F2-47A1-81B0-B870D16F272B}不固定。 调试过程中不要给Characteristics指定NCF_HIDDEN、NCF_NOT_USER_REMOVABLE,这 样可以通过NCPA反安装该协议驱动。 DelService项不是必须的,当安装INF文件失败时系统会用到这一项。 以ndisuio.inf为例: %NDISUIO_Desc%=Install, MS_NDISUIO 这里的MS_NDISUIO对应INetCfgClassSetup::Install()第一形参,如果二者不匹配, 安装将失败。 b) NDIS协议驱动的用户态测试程序 1) ndisprotocoltest.c -------------------------------------------------------------------------- /* * For x86/EWindows XP SP1 & VC 7 & Windows DDK 2600.1106 */ /************************************************************************ * * * Head File * * * ************************************************************************/ #include #include #include #include #include #include /************************************************************************ * * * Macro * * * ************************************************************************/ #pragma comment( linker, "/INCREMENTAL:NO" ) #pragma comment( linker, "/subsystem:console" ) #define VERSION "1.00" #define EXTERNALNAME "\\\\.\\NDISProtocolExternal1" #define PRIVATETAG 'OFSN' #define NDISPROTOCOL_INDEX 0x0800 #define IOCTL_NDISPROTOCOL_GET_PRIVATEFLAGS CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 0, \ METHOD_BUFFERED, \ FILE_READ_ACCESS \ ) #define IOCTL_NDISPROTOCOL_SET_PRIVATEFLAGS CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 1, \ METHOD_BUFFERED, \ FILE_WRITE_ACCESS \ ) #define IOCTL_NDISPROTOCOL_OPEN_DEVICE CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 2, \ METHOD_BUFFERED, \ FILE_READ_ACCESS | FILE_WRITE_ACCESS \ ) #define IOCTL_NDISPROTOCOL_GET_OID_VALUE CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 3, \ METHOD_BUFFERED, \ FILE_READ_ACCESS \ ) #define IOCTL_NDISPROTOCOL_SET_OID_VALUE CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 4, \ METHOD_BUFFERED, \ FILE_WRITE_ACCESS \ ) #define IOCTL_NDISPROTOCOL_SET_ETHER_TYPE CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 5, \ METHOD_BUFFERED, \ FILE_WRITE_ACCESS \ ) #define IOCTL_NDISPROTOCOL_QUERY_BINDING CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 6, \ METHOD_BUFFERED, \ FILE_READ_ACCESS \ ) #define IOCTL_NDISPROTOCOL_BIND_WAIT CTL_CODE \ ( \ FILE_DEVICE_NETWORK, \ NDISPROTOCOL_INDEX + 7, \ METHOD_BUFFERED, \ FILE_READ_ACCESS | FILE_WRITE_ACCESS \ ) #define PRIVATEFLAGS_ETHERTYPE 0x00000001 #define PRIVATEFLAGS_DEFAULT 0x00000001 typedef struct _BINDINGINFO { ULONG BindingIndex; // 0-based binding number ULONG DeviceNameOffset; // from start of this struct ULONG DeviceNameLength; // in bytes ULONG AdapterInstanceNameOffset; // from start of this struct ULONG AdapterInstanceNameLength; // in bytes } BINDINGINFO, *PBINDINGINFO; typedef struct _OIDVALUE { NDIS_OID Oid; UCHAR Value[sizeof(ULONG)]; } OIDVALUE, *POIDVALUE; #pragma pack( push, 1 ) struct etherheader { unsigned char eth_dst[6]; /* destination eth addr */ unsigned char eth_src[6]; /* source ether addr */ unsigned short int eth_type; /* packet type ID field */ }; #pragma pack( pop ) #define swap_16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) #define swap_32(x) ((((x) >> 24) & 0xff) | (((x) & 0xff) << 24) | (((x) >> 8) & 0xff00) | (((x) & 0xff00) << 8)) #define ETH_P_IP 0x0800 /* Internet Protocol packet */ #define ETH_P_ARP 0x0806 /* Address Resolution packet */ #define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ #define ETH_P_8021P 0x8100 /* 802.1p */ #define ETH_P_DEFAULT ETH_P_ARP /************************************************************************ * * * Function Prototype * * * ************************************************************************/ static WCHAR * AnsiToUnicode ( unsigned char *str ); static BOOL EnablePromiscuousMode ( HANDLE DeviceHandle ); static void EnumerateDevices ( HANDLE DeviceHandle ); static BOOL GetCurrentAddress ( HANDLE DeviceHandle, unsigned char *CurrentAddress ); static void outputBinary ( FILE *out, unsigned char *byteArray, size_t byteArrayLen ); static void PrintWin32ErrorCLI ( char *message, DWORD dwMessageId ); static BOOL PrivateOpenDevice ( HANDLE DeviceHandle, unsigned char *cardname ); static void PrivateRead ( HANDLE DeviceHandle, DWORD TotalNum ); static void PrivateWrite ( HANDLE DeviceHandle, unsigned char *sendmac, unsigned char *recvmac, unsigned short int EtherType, unsigned char *data, unsigned int datalen ); static void usage ( char *arg ); /************************************************************************ * * * Static Global Var * * * ************************************************************************/ /************************************************************************/ static WCHAR * AnsiToUnicode ( unsigned char *str ) { int i = 0, j = 0; WCHAR *unistr = NULL; if ( NULL != str ) { j = strlen( str ) + 1; i = MultiByteToWideChar ( CP_ACP, 0, str, j, NULL, 0 ); if ( 0 == i ) { PrintWin32ErrorCLI( "MultiByteToWideChar() failed for unistr [0]", GetLastError() ); goto AnsiToUnicode_exit; } unistr = ( WCHAR * )HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, i * sizeof( WCHAR ) ); if ( NULL == unistr ) { PrintWin32ErrorCLI( "HeapAlloc() failed for unistr", ERROR_NOT_ENOUGH_MEMORY ); goto AnsiToUnicode_exit; } if ( 0 == MultiByteToWideChar ( CP_ACP, 0, str, j, unistr, i ) ) { PrintWin32ErrorCLI( "MultiByteToWideChar() failed for unistr [1]", GetLastError() ); goto AnsiToUnicode_exit; } } AnsiToUnicode_exit: return( unistr ); } /* end of AnsiToUnicode */ static BOOL EnablePromiscuousMode ( HANDLE DeviceHandle ) { BOOL ret; DWORD BytesReturned; unsigned char buf[sizeof(OIDVALUE)]; POIDVALUE OidValue; OidValue = ( POIDVALUE )buf; OidValue->Oid = OID_GEN_CURRENT_PACKET_FILTER; *( PDWORD )&OidValue->Value = NDIS_PACKET_TYPE_PROMISCUOUS; ret = DeviceIoControl ( DeviceHandle, IOCTL_NDISPROTOCOL_SET_OID_VALUE, buf, sizeof( buf ), buf, sizeof( buf ), &BytesReturned, NULL ); if ( FALSE == ret ) { PrintWin32ErrorCLI( "DeviceIoControl( IOCTL_NDISPROTOCOL_SET_OID_VALUE ) for NDIS_PACKET_TYPE_PROMISCUOUS failed", GetLastError() ); } return( ret ); } /* end of EnablePromiscuousMode */ static void EnumerateDevices ( HANDLE DeviceHandle ) { unsigned char *buf = NULL; unsigned int buflen; DWORD BytesReturned; DWORD error; DWORD i; PBINDINGINFO BindingInfo; buflen = 1024; buf = ( unsigned char * )HeapAlloc ( GetProcessHeap(), HEAP_ZERO_MEMORY, buflen ); if ( NULL == buf ) { PrintWin32ErrorCLI( "HeapAlloc() failed for buf", ERROR_NOT_ENOUGH_MEMORY ); goto EnumerateDevices_exit; } BindingInfo = ( PBINDINGINFO )buf; for ( BindingInfo->BindingIndex = i = 0; ; BindingInfo->BindingIndex = ++i ) { if ( FALSE == DeviceIoControl ( DeviceHandle, IOCTL_NDISPROTOCOL_QUERY_BINDING, BindingInfo, sizeof( BINDINGINFO ), buf, buflen, &BytesReturned, NULL ) ) { error = GetLastError(); if ( ERROR_NO_MORE_ITEMS != error ) { PrintWin32ErrorCLI( "DeviceIoControl( IOCTL_NDISPROTOCOL_QUERY_BINDING ) failed", error ); } else { printf ( "0x%08X [EnumerateDevices() finished]\n", i ); } goto EnumerateDevices_exit; } printf ( "0x%08X [%ws]\n" " [%ws]\n", BindingInfo->BindingIndex, buf + BindingInfo->DeviceNameOffset, buf + BindingInfo->AdapterInstanceNameOffset ); ZeroMemory( buf, BytesReturned ); } /* end of for */ EnumerateDevices_exit: if ( NULL != buf ) { HeapFree( GetProcessHeap(), 0, buf ); buf = NULL; } return; } /* end of EnumerateDevices */ static BOOL GetCurrentAddress ( HANDLE DeviceHandle, unsigned char *CurrentAddress ) { BOOL ret; DWORD BytesReturned; unsigned char buf[sizeof(OIDVALUE)+6]; POIDVALUE OidValue; OidValue = ( POIDVALUE )buf; OidValue->Oid = OID_802_3_CURRENT_ADDRESS; ret = DeviceIoControl ( DeviceHandle, IOCTL_NDISPROTOCOL_GET_OID_VALUE, buf, sizeof( buf ), buf, sizeof( buf ), &BytesReturned, NULL ); if ( FALSE == ret ) { PrintWin32ErrorCLI( "DeviceIoControl( IOCTL_NDISPROTOCOL_GET_OID_VALUE ) for OID_802_3_CURRENT_ADDRESS failed", GetLastError() ); } else { CopyMemory( CurrentAddress, OidValue->Value, 6 ); } return( ret ); } /* end of GetCurrentAddress */ static void outputBinary ( FILE *out, unsigned char *byteArray, size_t byteArrayLen ) { size_t offset, k, j, i; fprintf( out, "byteArray [ %u bytes ] ->\n", byteArrayLen ); if ( byteArrayLen <= 0 ) { return; } i = 0; offset = 0; for ( k = byteArrayLen / 16; k > 0; k--, offset += 16 ) { fprintf( out, "%08X ", offset ); for ( j = 0; j < 16; j++, i++ ) { if ( j == 8 ) { fprintf( out, "-%02X", byteArray[i] ); } else { fprintf( out, " %02X", byteArray[i] ); } } fprintf( out, " " ); i -= 16; for ( j = 0; j < 16; j++, i++ ) { /* * if ( isprint( (int)byteArray[i] ) ) */ #if 0 if ( ( byteArray[i] >= ' ' ) && ( byteArray[i] <= 255 ) && ( byteArray[i] != 0x7F ) ) #else if ( ( byteArray[i] >= ' ' ) && ( byteArray[i] < 0x7F ) ) #endif { fprintf( out, "%c", byteArray[i] ); } else { fprintf( out, "." ); } } fprintf( out, "\n" ); } /* end of for */ k = byteArrayLen - i; if ( k <= 0 ) { return; } fprintf( out, "%08X ", offset ); for ( j = 0 ; j < k; j++, i++ ) { if ( j == 8 ) { fprintf( out, "-%02X", byteArray[i] ); } else { fprintf( out, " %02X", byteArray[i] ); } } i -= k; for ( j = 16 - k; j > 0; j-- ) { fprintf( out, " " ); } fprintf( out, " " ); for ( j = 0; j < k; j++, i++ ) { #if 0 if ( ( byteArray[i] >= ' ' ) && ( byteArray[i] <= 255 ) && ( byteArray[i] != 0x7F ) ) #else if ( ( byteArray[i] >= ' ' ) && ( byteArray[i] < 0x7F ) ) #endif { fprintf( out, "%c", byteArray[i] ); } else { fprintf( out, "." ); } } fprintf( out, "\n" ); return; } /* end of outputBinary */ static void PrintWin32ErrorCLI ( char *message, DWORD dwMessageId ) { char *errMsg; FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwMessageId, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), ( LPTSTR )&errMsg, 0, NULL ); fprintf( stderr, "%s: %s", message, errMsg ); LocalFree( errMsg ); return; } /* end of PrintWin32ErrorCLI */ static BOOL PrivateOpenDevice ( HANDLE DeviceHandle, unsigned char *cardname ) { BOOL ret; WCHAR *unicodecardname = NULL; DWORD BytesReturned; unicodecardname = AnsiToUnicode( cardname ); if ( NULL == unicodecardname ) { goto PrivateOpenDevice_exit; } ret = DeviceIoControl ( DeviceHandle, IOCTL_NDISPROTOCOL_OPEN_DEVICE, unicodecardname, wcslen( unicodecardname) * sizeof( WCHAR ), NULL, 0, &BytesReturned, NULL ); if ( FALSE == ret ) { PrintWin32ErrorCLI( "DeviceIoControl( IOCTL_NDISPROTOCOL_OPEN_DEVICE ) failed", GetLastError() ); goto PrivateOpenDevice_exit; } PrivateOpenDevice_exit: if ( NULL != unicodecardname ) { HeapFree( GetProcessHeap(), 0, unicodecardname ); unicodecardname = NULL; } return( ret ); } /* end of PrivateOpenDevice */ static void PrivateRead ( HANDLE DeviceHandle, DWORD TotalNum ) { unsigned char buf[1514]; DWORD NumberOfBytes; DWORD Num = 0; while ( ( 0 == TotalNum ) || ( Num < TotalNum ) ) { Num++; if ( FALSE == ReadFile ( DeviceHandle, buf, sizeof( buf ), &NumberOfBytes, NULL ) ) { PrintWin32ErrorCLI( "ReadFile() failed", GetLastError() ); break; } outputBinary ( stdout, buf, NumberOfBytes ); } /* end of while */ return; } /* end of PrivateRead */ static void PrivateWrite ( HANDLE DeviceHandle, unsigned char *sendmac, unsigned char *recvmac, unsigned short int EtherType, unsigned char *data, unsigned int datalen ) { unsigned char *buf = NULL; unsigned int buflen; DWORD NumberOfBytes; buflen = 14 + datalen; buf = ( unsigned char * )HeapAlloc ( GetProcessHeap(), HEAP_ZERO_MEMORY, buflen ); if ( NULL == buf ) { PrintWin32ErrorCLI( "HeapAlloc() failed for buf", ERROR_NOT_ENOUGH_MEMORY ); goto PrivateWrite_exit; } CopyMemory ( buf, recvmac, 6 ); CopyMemory ( buf + 6, sendmac, 6 ); CopyMemory ( buf + 12, &EtherType, 2 ); CopyMemory ( buf + 14, data, datalen ); if ( FALSE == WriteFile ( DeviceHandle, buf, buflen, &NumberOfBytes, NULL ) ) { PrintWin32ErrorCLI( "WriteFile() failed", GetLastError() ); goto PrivateWrite_exit; } PrivateWrite_exit: if ( NULL != buf ) { HeapFree( GetProcessHeap(), 0, buf ); buf = NULL; } return; } /* end of PrivateWrite */ static void usage ( char *arg ) { fprintf ( stderr, "Usage: %s [-h] [-v] [-w] [-e] [-p] [-c cardname]\n" " [-t EtherType] [-f PrivateFlags] [-n TotalNum]\n" " [-s sendmac] [-r recvmac]\n", arg ); exit( EXIT_FAILURE ); } /* end of usage */ int __cdecl main ( int argc, char * argv[] ) { int c, ret = EXIT_FAILURE; HANDLE Device = INVALID_HANDLE_VALUE; ULONG PrivateFlags = PRIVATEFLAGS_DEFAULT; unsigned short int EtherType = ETH_P_DEFAULT; ULONG OrigPrivateFlags; DWORD BytesReturned; unsigned char *cardname = NULL; BOOLEAN DoEnum = FALSE; BOOLEAN PromiscFlag = FALSE; BOOLEAN DoWrite = FALSE; unsigned char mac[6]; unsigned char sendmac[6] = { 'N', 'S', 'N', 'S', 'N', 'S' }; unsigned char recvmac[6] = { 'N', 'S', 'N', 'S', 'N', 'S' }; unsigned int macaddr[6]; unsigned int i; DWORD TotalNum = 1; unsigned char data[] = "Copyleft (c) 2002, 2012\n" "The NSFOCUS INFORMATION TECHNOLOGY CO.,LTD.\n" "NSFocus Security Team \n" "http://www.nsfocus.com\n" "scz \n"; if ( 1 == argc ) { usage( argv[0] ); } for ( c = 1; c < argc; c++ ) { if ( ( ( argv[c][0] != '-' ) && ( argv[c][0] != '/' ) ) || ( strlen( argv[c] ) < 2 ) ) { usage( argv[0] ); } else { switch ( tolower( argv[c][1] ) ) { case 'c': if ( ( c + 1 ) >= argc ) { usage( argv[0] ); } cardname = argv[++c]; break; case 'e': DoEnum = TRUE; break; case 'f': if ( ( c + 1 ) >= argc ) { usage( argv[0] ); } PrivateFlags = strtoul( argv[++c], NULL, 0 ); break; case 'n': if ( ( c + 1 ) >= argc ) { usage( argv[0] ); } TotalNum = strtoul( argv[++c], NULL, 0 ); break; case 'p': PromiscFlag = TRUE; break; case 'r': if ( ( c + 1 ) >= argc ) { usage( argv[0] ); } if ( 6 != sscanf ( argv[++c], "%02x-%02x-%02x-%02x-%02x-%02x", macaddr, macaddr + 1, macaddr + 2, macaddr + 3, macaddr + 4, macaddr + 5 ) ) { fprintf( stderr, "Checking your [-r recvmac]\n" ); goto main_exit; } for ( i = 0; i < 6; i++ ) { recvmac[i] = ( unsigned char )macaddr[i]; } break; case 's': if ( ( c + 1 ) >= argc ) { usage( argv[0] ); } if ( 6 != sscanf ( argv[++c], "%02x-%02x-%02x-%02x-%02x-%02x", macaddr, macaddr + 1, macaddr + 2, macaddr + 3, macaddr + 4, macaddr + 5 ) ) { fprintf( stderr, "Checking your [-s sendmac]\n" ); goto main_exit; } for ( i = 0; i < 6; i++ ) { sendmac[i] = ( unsigned char )macaddr[i]; } break; case 't': if ( ( c + 1 ) >= argc ) { usage( argv[0] ); } EtherType = ( unsigned short int )strtoul( argv[++c], NULL, 0 ); break; case 'v': fprintf( stderr, "%s ver "VERSION"\n", argv[0] ); return( EXIT_SUCCESS ); case 'w': DoWrite = TRUE; break; case 'h': case '?': default: usage( argv[0] ); break; } /* end of switch */ } } /* end of for */ Device = CreateFile ( EXTERNALNAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, // If lpSecurityAttributes is NULL, the handle cannot be inherited OPEN_EXISTING, // The function fails if the file does not exist FILE_ATTRIBUTE_NORMAL, NULL ); if ( INVALID_HANDLE_VALUE == Device ) { PrintWin32ErrorCLI( "CreateFile() failed", GetLastError() ); goto main_exit; } if ( FALSE == DeviceIoControl ( Device, IOCTL_NDISPROTOCOL_BIND_WAIT, NULL, 0, NULL, 0, &BytesReturned, NULL ) ) { PrintWin32ErrorCLI( "DeviceIoControl( IOCTL_NDISPROTOCOL_BIND_WAIT ) failed", GetLastError() ); goto main_exit; } if ( DoEnum ) { EnumerateDevices( Device ); } else { if ( FALSE == DeviceIoControl ( Device, IOCTL_NDISPROTOCOL_SET_PRIVATEFLAGS, &PrivateFlags, sizeof( PrivateFlags ), NULL, 0, &BytesReturned, NULL ) ) { PrintWin32ErrorCLI( "DeviceIoControl( IOCTL_NDISPROTOCOL_SET_PRIVATEFLAGS ) failed", GetLastError() ); goto main_exit; } if ( FALSE == DeviceIoControl ( Device, IOCTL_NDISPROTOCOL_GET_PRIVATEFLAGS, NULL, 0, &PrivateFlags, sizeof( PrivateFlags ), &BytesReturned, NULL ) ) { PrintWin32ErrorCLI( "DeviceIoControl( IOCTL_NDISPROTOCOL_GET_PRIVATEFLAGS ) for PrivateFlags failed", GetLastError() ); goto main_exit; } printf( "PrivateFlags = 0x%08X\n", PrivateFlags ); if ( FALSE == DeviceIoControl ( Device, IOCTL_NDISPROTOCOL_SET_ETHER_TYPE, &EtherType, sizeof( EtherType ), NULL, 0, &BytesReturned, NULL ) ) { PrintWin32ErrorCLI( "DeviceIoControl( IOCTL_NDISPROTOCOL_SET_ETHER_TYPE ) failed", GetLastError() ); goto main_exit; } if ( NULL == cardname ) { fprintf( stderr, "Checking your [-c cardname]\n" ); goto main_exit; } if ( FALSE == PrivateOpenDevice( Device, cardname ) ) { goto main_exit; } if ( FALSE == GetCurrentAddress( Device, mac ) ) { goto main_exit; } printf ( "MAC = %02X-%02X-%02X-%02X-%02X-%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); if ( PromiscFlag ) { EnablePromiscuousMode( Device ); } if ( DoWrite ) { PrivateWrite ( Device, sendmac, recvmac, swap_16( EtherType ), data, sizeof( data ) ); } else { PrivateRead( Device, TotalNum ); } } ret = EXIT_SUCCESS; main_exit: if ( INVALID_HANDLE_VALUE != Device ) { CloseHandle( Device ); Device = INVALID_HANDLE_VALUE; } return( ret ); } /* end of main */ /************************************************************************/ -------------------------------------------------------------------------- 如果去掉前述ndisuio的限制,可在用户态测试程序中任意读写链路层数据。 2) sources -------------------------------------------------------------------------- TARGETNAME=ndisprotocoltest TARGETPATH=obj TARGETTYPE=PROGRAM UMTYPE=console USE_MSVCRT=1 TARGETLIBS=\ $(SDK_LIB_PATH)\kernel32.lib C_DEFINES=$(C_DEFINES) -D_WIN32WIN_ USE_PDB=1 INCLUDES= MSC_WARNING_LEVEL=-W3 -WX SOURCES=ndisprotocoltest.c -------------------------------------------------------------------------- 3) makefile -------------------------------------------------------------------------- # # XP DDK自带了编译器,不再依赖VC # !INCLUDE $(NTMAKEENV)\makefile.def -------------------------------------------------------------------------- c) NDIS组件配置程序 不能用installdriver.c安装NDIS协议驱动,网络组件的安装远比普通KMD的安装来得 复杂。一般是用NCPA安装相应的INF文件,如果想命令行安装,可参看DDK例子代码中 的netcfg(Network Configuration Sample)。netcfg演示了利用INetCfg API枚举、 安装、卸载网络组件。 HRESULT_FROM_WIN32( GetLastError() )的返回值类型是HRESULT,但我没有找到与 之相应的逆函数/宏。这个宏在crt\winerror.h中定义,另有两个用到了的宏也在该 文件中定义: #define SUCCEEDED(Status) ((HRESULT)(Status) >= 0) #define FAILED(Status) ((HRESULT)(Status)<0) SetupCopyOEMInf()第三形参如果用SPOST_NONE,将弹出一个对话框,让你选择目录。 从命令行安装的初衷来看,应该指定SPOST_PATH。 如果INetCfgClassSetup::Install()失败,其返回值为0x8004A024,请确认之前是否 已经调用过INetCfgLock::AcquireWriteLock()。我有个疑问,如何将0x8004A024转 换成可阅读的错误信息,这次是HRESULT啊。 d) 源代码目录结构 J:\source\driver\ndisprotocol>tree /f /a ndisprotocol | dirs | +---driver | makefile | ndisprotocol.c | ndisprotocol.inf | sources | +---install | makefile | ndisconfig.cpp | ndisconfig.idl | ndisconfig_idl.c | sources | \---test makefile ndisprotocoltest.c sources dirs文件内容如下: -------------------------------------------------------------------------- DIRS=\ driver \ test \ install -------------------------------------------------------------------------- e) 编译 假设进入了"Win XP Checked Build Environment": J:\source\driver\ndisprotocol> set DDK_LIB_PATH DDK_LIB_PATH=J:\WINDDK\2600~1.110\lib\wxp\* J:\source\driver\ndisprotocol> set BUILD_ALT_DIR BUILD_ALT_DIR=chk_wxp_x86 J:\source\driver\ndisprotocol> build -cZ -x86 J:\source\driver\ndisprotocol> tree /f /a ndisprotocol | buildchk_wxp_x86.log | dirs | +---driver | | makefile | | ndisprotocol.c | | ndisprotocol.inf | | sources | | | \---objchk_wxp_x86 | | _objects.mac | | | \---i386 | ndisprotocol.obj | ndisprotocol.pdb | ndisprotocol.sys | +---install | | dlldata.c | | makefile | | ndisconfig.cpp | | ndisconfig.h | | ndisconfig.idl | | ndisconfig_i.c | | ndisconfig_idl.c | | ndisconfig_p.c | | sources | | | \---objchk_wxp_x86 | | _objects.mac | | | \---i386 | ndisconfig.exe | ndisconfig.obj | ndisconfig.pdb | ndisconfig_idl.obj | \---test | makefile | ndisprotocoltest.c | sources | \---objchk_wxp_x86 | _objects.mac | \---i386 ndisprotocoltest.exe ndisprotocoltest.obj ndisprotocoltest.pdb f) 安装 将ndisprotocol.sys、ndisprotocol.inf、ndisconfig.exe、ndisprotocoltest.exe 四个文件复制到测试机的c:\onlytemp\目录下,执行如下命令进行安装: c:\onlytemp> ndisconfig.exe -i nsfocus_ndisprotocol -t protocol -f c:\onlytemp\ndisprotocol.inf c:\onlytemp\ndisprotocol.inf was copied to C:\WINDOWS\INF\oem3.inf Succeeded 用户界面友好些的话,应该由程序自动分析ndisprotocol.inf,析取出诸如protocol、 nsfocus_ndisprotocol相关信息,但我的目的是了解协议驱动而非解析INF文件,所 以简单处理成靠命令行参数指定相应信息。 如果[-i installid]指定有误的话,%systemroot%\setupapi.log中可看到相应错误 信息。 现在查看%systemroot%\inf目录,多出三个文件,oem3.inf、oem3.pnf、infcache.1。 oem3.inf内容与ndisprotocol.inf完全一样,oem3.pnf是为了提高安装效率而生成的 预编译信息,infcache.1自然是一些cache信息了。 c:\onlytemp> ndisconfig.exe -e protocol nsfocus_ndisprotocol The NDISProtocol Driver ms_ndisuio NDIS Usermode I/O Protocol ms_pppoe Point to Point Protocol Over Ethernet ms_pptp Point to Point Tunneling Protocol ms_l2tp Layer 2 Tunneling Protocol ms_ndiswan Remote Access NDIS WAN Driver ms_netbt_smb Message-oriented TCP/IP Protocol (SMB session) ms_netbt WINS Client(TCP/IP) Protocol ms_tcpip Internet Protocol (TCP/IP) 在NCPA中可以看到多出一项"The NDISProtocol Driver"。与此次安装相关的注册表 内容如下: -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E975-E325-11CE-BFC1-08002BE10318}\{DE772806-0150-4F4B-84BC-2C0FDFAF2CA2}] "Characteristics"=dword:00000000 "InfPath"="oem3.inf" "InfSection"="DDInstall.NTx86" "Description"="The NDISProtocol Driver" "ComponentId"="nsfocus_ndisprotocol" [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E975-E325-11CE-BFC1-08002BE10318}\{DE772806-0150-4F4B-84BC-2C0FDFAF2CA2}\Ndi] "Service"="NDISProtocol" "HelpText"="The NDISProtocol Driver" [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E975-E325-11CE-BFC1-08002BE10318}\{DE772806-0150-4F4B-84BC-2C0FDFAF2CA2}\Ndi\Interfaces] "UpperRange"="noupper" "LowerRange"="ndis5" -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NDISProtocol] "Type"=dword:00000001 "Start"=dword:00000003 "ErrorControl"=dword:00000001 "Tag"=dword:0000001d "ImagePath"=hex(2):73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,64,00,\ 72,00,69,00,76,00,65,00,72,00,73,00,5c,00,6e,00,64,00,69,00,73,00,70,00,72,\ 00,6f,00,74,00,6f,00,63,00,6f,00,6c,00,2e,00,73,00,79,00,73,00,00,00 "DisplayName"="NDISProtocol" "Group"="NDIS" "Description"="The NDISProtocol Driver" [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NDISProtocol\Linkage] "Bind"=hex(7):5c,00,44,00,65,00,76,00,69,00,63,00,65,00,5c,00,7b,00,33,00,46,\ 00,32,00,46,00,37,00,46,00,35,00,33,00,2d,00,39,00,34,00,43,00,43,00,2d,00,\ 34,00,43,00,38,00,33,00,2d,00,42,00,36,00,38,00,33,00,2d,00,34,00,33,00,30,\ 00,38,00,43,00,35,00,37,00,33,00,37,00,31,00,32,00,44,00,7d,00,00,00,00,00 "Route"=hex(7):22,00,7b,00,33,00,46,00,32,00,46,00,37,00,46,00,35,00,33,00,2d,\ 00,39,00,34,00,43,00,43,00,2d,00,34,00,43,00,38,00,33,00,2d,00,42,00,36,00,\ 38,00,33,00,2d,00,34,00,33,00,30,00,38,00,43,00,35,00,37,00,33,00,37,00,31,\ 00,32,00,44,00,7d,00,22,00,00,00,00,00 "Export"=hex(7):5c,00,44,00,65,00,76,00,69,00,63,00,65,00,5c,00,4e,00,44,00,49,\ 00,53,00,50,00,72,00,6f,00,74,00,6f,00,63,00,6f,00,6c,00,5f,00,7b,00,33,00,\ 46,00,32,00,46,00,37,00,46,00,35,00,33,00,2d,00,39,00,34,00,43,00,43,00,2d,\ 00,34,00,43,00,38,00,33,00,2d,00,42,00,36,00,38,00,33,00,2d,00,34,00,33,00,\ 30,00,38,00,43,00,35,00,37,00,33,00,37,00,31,00,32,00,44,00,7d,00,00,00,00,\ 00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NDISProtocol\Security] "Security"=hex:01,00,14,80,90,00,00,00,9c,00,00,00,14,00,00,00,30,00,00,00,02,\ 00,1c,00,01,00,00,00,02,80,14,00,ff,01,0f,00,01,01,00,00,00,00,00,01,00,00,\ 00,00,02,00,60,00,04,00,00,00,00,00,14,00,fd,01,02,00,01,01,00,00,00,00,00,\ 05,12,00,00,00,00,00,18,00,ff,01,0f,00,01,02,00,00,00,00,00,05,20,00,00,00,\ 20,02,00,00,00,00,14,00,8d,01,02,00,01,01,00,00,00,00,00,05,0b,00,00,00,00,\ 00,18,00,fd,01,02,00,01,02,00,00,00,00,00,05,20,00,00,00,23,02,00,00,01,01,\ 00,00,00,00,00,05,12,00,00,00,01,01,00,00,00,00,00,05,12,00,00,00 -------------------------------------------------------------------------- g) 测试 很有可能需要用SoftICE对ndisprotocol.sys进行源码级调试: net start PrivateExt nmsym.exe /translate:always,source,package /output:ndisprotocol.nms ndisprotocol.sys nmsym.exe /symload:ndisprotocol.nms (卸载用nmsym.exe /unload:ndisprotocol.nms) sync.exe bpx ndisprotocol!DriverEntry bpx ndisprotocol!ProtocolBindAdapter net start ndisprotocol 事实上果然用SoftICE发现一处低级但致命的错误,NdisZeroMemory()第二形参不正 确。现在提供的版本是修正后的。关于BSOD,参看[12]、[13]。 至此,注册表内容有一些增加: -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0003\Linkage] "UpperBind"=hex(7):4e,00,44,00,49,00,53,00,50,00,72,00,6f,00,74,00,6f,00,63,00,\ 6f,00,6c,00,00,00,52,00,61,00,73,00,50,00,70,00,70,00,6f,00,65,00,00,00,4e,\ 00,64,00,69,00,73,00,75,00,69,00,6f,00,00,00,54,00,63,00,70,00,69,00,70,00,\ 00,00,00,00 -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\LEGACY_NDISPROTOCOL] "NextInstance"=dword:00000001 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\LEGACY_NDISPROTOCOL\0000] "Service"="NDISProtocol" "Legacy"=dword:00000001 "ConfigFlags"=dword:00000000 "Class"="LegacyDriver" "ClassGUID"="{8ECC055D-047F-11D1-A537-0000F8753ED1}" "DeviceDesc"="NDISProtocol" [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\LEGACY_NDISPROTOCOL\0000\Control] "*NewlyCreated*"=dword:00000000 "ActiveService"="NDISProtocol" -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NDISProtocol\Enum] "0"="Root\\LEGACY_NDISPROTOCOL\\0000" "Count"=dword:00000001 "NextInstance"=dword:00000001 -------------------------------------------------------------------------- Usage: ndisprotocoltest.exe [-h] [-v] [-w] [-e] [-p] [-c cardname] [-t EtherType] [-f PrivateFlags] [-n TotalNum] [-s sendmac] [-r recvmac] > ndisprotocoltest.exe -e 0x00000000 [\DEVICE\{3F2F7F53-94CC-4C83-B683-4308C573712D}] [AMD PCNET Family PCI Ethernet Adapter #2] 0x00000001 [EnumerateDevices() finished] > ndisprotocoltest.exe -w -c \DEVICE\{3F2F7F53-94CC-4C83-B683-4308C573712D} -s 00-11-00-11-00-11 -r FF-FF-FF-FF-FF-FF -t 0x0806 PrivateFlags = 0x00000001 MAC = 00-50-56-41-C0-A7 用Ethereal从别的机器上抓取上述命令发送到网络上的链路帧,确认发送成功。 > ndisprotocoltest.exe -c \DEVICE\{3F2F7F53-94CC-4C83-B683-4308C573712D} -f 0 -p -n 0 PrivateFlags = 0x00000000 MAC = 00-50-56-41-C0-A7 byteArray [ 173 bytes ] -> 00000000 FF FF FF FF FF FF 00 11-00 11 00 11 08 06 43 6F ..............Co 00000010 70 79 6C 65 66 74 20 28-63 29 20 32 30 30 32 2C pyleft (c) 2002, 00000020 20 32 30 31 32 0A 54 68-65 20 4E 53 46 4F 43 55 2012.The NSFOCU 00000030 53 20 49 4E 46 4F 52 4D-41 54 49 4F 4E 20 54 45 S INFORMATION TE 00000040 43 48 4E 4F 4C 4F 47 59-20 43 4F 2E 2C 4C 54 44 CHNOLOGY CO.,LTD 00000050 2E 0A 4E 53 46 6F 63 75-73 20 53 65 63 75 72 69 ..NSFocus Securi 00000060 74 79 20 54 65 61 6D 20-3C 73 65 63 75 72 69 74 ty Team .h 00000080 74 74 70 3A 2F 2F 77 77-77 2E 6E 73 66 6F 63 75 ttp://www.nsfocu 00000090 73 2E 63 6F 6D 0A 73 63-7A 20 3C 73 63 7A 40 6E s.com.scz .. byteArray [ 60 bytes ] -> 00000000 00 0D 58 0A BD C8 00 0D-58 0A BD C8 90 00 00 00 ..X.....X....... 00000010 01 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00000030 00 00 00 00 00 00 00 00-00 00 00 00 ............ byteArray [ 342 bytes ] -> 00000000 FF FF FF FF FF FF 00 50-56 41 C0 A6 08 00 45 00 .......PVA....E. 00000010 01 48 23 4A 00 00 FF 11-97 5B 00 00 00 00 FF FF .H#J.....[...... 00000020 FF FF 00 44 00 43 01 34-FF B7 01 01 06 00 02 75 ...D.C.4.......u 00000030 C8 0E 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00000040 00 00 00 00 00 00 00 50-56 41 C0 A6 00 00 00 00 .......PVA...... 00000050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00000060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00000070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00000080 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00000090 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000000A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000000B0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000000C0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000000D0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000000E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000000F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00000100 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00000110 00 00 00 00 00 00 63 82-53 63 35 01 01 3D 07 01 ......c.Sc5..=.. 00000120 00 50 56 41 C0 A6 C0 07-53 6F 66 74 49 43 45 FF .PVA....SoftICE. 00000130 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00000140 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00000150 00 00 00 00 00 00 ...... byteArray [ 60 bytes ] -> 00000000 01 80 C2 00 00 00 00 0D-58 0A BD C8 00 26 42 42 ........X....&BB 00000010 03 00 00 00 00 00 80 00-00 07 EB 99 2C 83 00 00 ............,... 00000020 00 39 80 07 00 0D 58 0A-BD C0 80 08 03 00 14 00 .9....X......... 00000030 02 00 0F 00 00 00 00 00-00 00 00 00 ............ ^C 上述命令进入混杂模式抓取所有链路帧,不对eth_type进行过滤,这正是sniffer所 需要的。 h) 卸载 > net stop ndisprotocol 与普通KMD不同,卸载网络组件不能简单地执行"sc delete ndisprotocol"。可以在 NCPA中卸载"The NDISProtocol Driver",也可以命令行卸载: > ndisconfig.exe -u nsfocus_ndisprotocol Succeeded 卸载完成后,前述注册表内容全部删除了。oem3.inf、oem3.pnf、infcache.1以及驱 动目录(%systemroot%\system32\drivers)下的ndisprotocol.sys未被删除。再次执 行如下命令进行安装: > ndisconfig.exe -i nsfocus_ndisprotocol -t protocol -f c:\onlytemp\ndisprotocol.inf c:\onlytemp\ndisprotocol.inf was copied to C:\WINDOWS\INF\oem3.inf Succeeded %systemroot%\inf目录下仍是oem3.inf、oem3.pnf、infcache.1,不会出现想像中的 oem4.inf。如果觉得别扭,卸载完成后可以删除残留的这四个文件。 i) 一些遗留问题 可以考虑先加载ndisuio,然后动态修改取消MS所加的那些限制。好像没什么实际意 义,懒得弄了。 再就是,对BSOD还是很畏惧,好在也不真要写什么驱动,以后慢慢增进了解吧。 ☆ 参考资源 [ 1] Windows Network Data And Packet Filtering Frequently Asked Questions(这里有一张Network Architecture Diagram) http://www.pcausa.com/resources/winpktfilter.htm [ 2] Network Architecture in Windows NT-based Operating Systems http://plasmic.com/~vizzini/ntnetarch.html [ 3] Ntpacket.exe: Updated Windows NT 4.0 NDIS 3.0 Packet Sample Available http://support.microsoft.com/default.aspx?scid=kb;EN-US;238652 ftp://ftp.microsoft.com/Softlib/MSLFILES/Ntpacket.exe Bugs in the NT DDK Packet Protocol Driver Sample http://www.panix.com/~perin/packetbugs.html [ 4] EthernetSpy http://telemat.det.unifi.it/book/EthernetSpy/EthernetSpy.zip [ 5] BriProto NDIS Protocol Driver Project Files http://adaptive4.ucsd.edu/projects/briproto_driver/files/BriProto.2003.08.01.1218.zip http://adaptive4.ucsd.edu/projects/briproto_driver/doc/ [ 6] A RARP Server(source code) http://www.panix.com/~perin/rarpd.zip [ 7] NDIS "Packet" Discussion(介绍了NDIS_PACKET、NDIS_BUFFER) http://www.pcausa.com/resources/ndispacket.htm http://www.pcausa.com/resources/ndispacket_decode.htm http://www.pcausa.com/resources/readonpacket.htm NDIS_PACKET Discussion Part 2 - NDIS_PACKET Reserved Areas http://www.ndis.com/papers/ndispacket/ndispacket2.htm [ 8] Workaround To Circumvent ProtocolReceive Faults Caused By Some Faulty NDIS Miniport Drivers http://www.pcausa.com/support/KB03080201.htm [ 9] Conditions Needed For ReceivePacketHandler To Be Called http://www.pcausa.com/support/KB07130001.htm [10] http://www.rhyshaden.com/ethernet.htm(介绍了802.1p的帧格式) [11] NDIS Driver Compile Flags - Stephan Wolf[2004-03-15] http://www.wd-3.com/031504/NDISCompile.htm [12] KNOWLEDGE BASE LINKS STOP MESSAGES(理解BSOD) http://aumha.org/win5/kbestop.htm [13] Stop 0x0000000A or IRQL_NOT_LESS_OR_EQUAL(介绍了Stop Message的四个参数) http://www.microsoft.com/resources/documentation/Windows/XP/all/reskit/en-us/prmd_stp_hwpg.asp [14] Network Devices and Protocols: Windows DDK [15] Kernel Driver Frequestly Asked Questions (FAQ) http://www.osronline.com/custom.cfm?name=articlePrint.cfm&id=256 [16] INFO: Network Binding Analysis http://support.microsoft.com/default.aspx?scid=kb;en-us;192483