本论文不是帮助程序猿开发网络驱动而是帮助他使用这种驱动。
此外。特定的应用与特定种类的驱动相相应。随着Internet的到来,编写网络驱动成为驱动开发的核心。为帮助开发网络设备驱动。微软为Windows NT操作系统开发了网络设备接口规范(NDIS)库。
比如。以太网中称为以太网接口卡,令牌环网中称为令牌环网接口卡,等等。
对全部外部功能来说。NIC驱动都依赖于NDIS。这些功能包含与协议驱动的通信。注冊,截获NIC硬件中断。与下层的NIC的通信。
全然NIC驱动必须保持接收数据的绑定信息。
对于上层传输驱动程序来书,中间驱动看起来像是微port驱动。对微port驱动来说,看起来像是协议驱动。使用中间协议驱动的主要是为了传输媒质,存在于对于传输驱动未知和微port管理之间的新的媒质类型。
它也在它的底层提供协议接口,来接收下层驱动发送来的包
。驱动中其他的函数是通过DriverEntry函数声明的。应用程序调用函数如CreateFile。ReadFile等。会由NT I/O管理器生成对应IRP(输入/输出请求包)。
每一个I/O操作由工作顺序来描写叙述,工作顺序告诉驱动做什么和通过I/O子系统追踪请求的过程。
这些工作顺序通过一个称为I/O请求包(IRP)的数据结构的形式给出。
这个IRP为完毕特定操作按顺序调用驱动中的进入点。
应用能够利用PACKET.SYS将网卡设置为混杂模式,以便于捕获网络中传输的全部数据包。
这个驱动能够将网卡设置为不论什么期望的模式,而且同意应用程序通过网络发送和接收数据包。除驱动程序的sys文件之外。还提供了一个DLL(PACKET32.DLL),通过此DLL应用程序能够和驱动程序通信。
- typedef struct _ADAPTER
- {
- HANDLE hFile; // 保存由CreateFile方法返回的句柄
- TCHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; // 保存驱动的符号链接名
- } ADAPTER, *LPADAPTER;
- typedef struct _PACKET
- {
- HANDLE hEvent; // 保存和适配器对象对应的事件句柄
- OVERLAPPED OverLapped;// 包括异步输入输出信息的OVERLAPPED结构
- PVOID Buffer; // 包括发送和接收数据的缓冲区
- UINT Length; // 缓冲区长度
- } PACKET, *LPPACKET;
- typedef struct _CONTROL_BLOCK
- {
- LPADAPTER hFile; // 指向适配器对象的指针
- HANDLE hEvent; // 保存事件句柄
- // Name of the driver as registered in the registry.
- TCHAR AdapterName[64]; // 注冊表中注冊的驱动名
- HANDLE hMem; // 保存接收数据包的缓冲区
- LPBYTE lpMem;
- HGLOBAL hMem2; // 保存发送数据包的缓冲区
- LPBYTE lpMem2;
- ULONG PacketLength; // 包长度
- ULONG LastReadSize; // 最后读取的包大小
- UINT BufferSize; // 缓冲区长度
- } CONTROL_BLOCK, *PCONTROL_BLOCK;
应用程序開始
- CONTROL_BLOCK cbAdapter;
- ULONG NameLength=64;
- // 得到驱动在注冊表中注冊的名字
- PacketGetAdapterNames(CbAdapter.AdapterName,&NameLength);
- CbAdapter.BufferSize=1514; // 保留1514字节,最大帧长度
- // 分配并锁定内存缓冲区用于发送和接收数据包
- CbAdapter.hMem=GlobalAlloc(GPTR, 1514);
- CbAdapter.lpMem=(LPBYTE)GlobalLock(CbAdapter.hMem);
- CbAdapter.hMem2=GlobalAlloc(GPTR,1514);
- CbAdapter.lpMem2=(LPBYTE)GlobalLock(CbAdapter.hMem2);
- // 打开优先的适配器用于接收数据,
- // 函数依次调用CreateFile方法。调用驱动程序中对应的进入点。
为随后的读写操作打开适配器
- CbAdapter.hFile=(ADAPTER*)PacketOpenAdapter(CbAdapter.AdapterName);
- // 打开适配器域
- if (CbAdapter.hFile = = NULL)
- {
- AfxMessageBox("Open Adapter failed");
- }
- // 此Packet对象用于从网络上接收全部数据的包
- PVOID Packet;
- // 设置过滤条件为混杂(非选择)模式
- // 此函数依次呼叫DeviceIoControl方法。用来设置网卡工作于期望的模式。
- Filter = NDIS_PACKET_TYPE_PROMISCUOUS;
- // 设置网卡为混杂模式
- PacketSetFilter(CbAdapter.hFile, Filter);
- // 分配缓冲区用于接收数据包
- Packet=PacketAllocatePacket(CbAdapter.hFile);
- // 初始化接收数据包缓冲区
- if(Packet != NULL)
- {
- PacketInitPacket((PACKET *)Packet,(char *)pdData[nCurrentWriteLocation].pData,1514);
- // 从驱动中读取数据包
- // 此函数依次调用ReadFile方法来读取通过EIC从网络上收到的数据
- PacketReceivePacket(CbAdapter.hFile,(PACKET *)Packet,TRUE,&pdData[nCurrentWriteLocation].nPacketLength );
- ULONG
- PacketGetAdapterNames(
- PTSTR pStr,
- PULONG BufferSize
- )
- {
- HKEY SystemKey;
- HKEY ControlSetKey;
- HKEY ServicesKey;
- HKEY NdisPerfKey;
- HKEY LinkageKey;
- LONG Status;
- DWORD RegType;
- // Open the Key HKEY_LOCAL_MACHINE,打开HKEY_LOCAL_MACHINE键值
- Status=RegOpenKeyEx(
- HKEY_LOCAL_MACHINE,
- TEXT("SYSTEM"),
- 0,
- KEY_READ,
- &SystemKey
- );
- if (Status == ERROR_SUCCESS) {
- // Open the key currentcontrolset 打开currentcontrolset键值
- Status=RegOpenKeyEx(
- SystemKey,
- TEXT("CurrentControlSet"),
- 0,
- KEY_READ,
- &ControlSetKey
- );
- if (Status == ERROR_SUCCESS) {
- // Open the key Services打开Services键值
- Status=RegOpenKeyEx(
- ControlSetKey,
- TEXT("Services"),
- 0,
- KEY_READ,
- &ServicesKey
- );
- if (Status == ERROR_SUCCESS) {
- // Open the key Packet. 打开Packet键值
- Status=RegOpenKeyEx(
- ServicesKey,
- TEXT("Packet"),
- 0,
- KEY_READ,
- &NdisPerfKey
- );
- if (Status == ERROR_SUCCESS) {
- // Open the key Linkage.打开Linkage键值
- Status=RegOpenKeyEx(
- NdisPerfKey,
- TEXT("Linkage"),
- 0,
- KEY_READ,
- &LinkageKey
- );
- if (Status == ERROR_SUCCESS) {
- // Open the key Export.
- Status=RegQueryValueEx(
- LinkageKey,
- TEXT("Export"),
- NULL,
- &RegType,
- (LPBYTE)pStr,
- BufferSize
- );
- // Close all the keys that have been opened so far.关闭已打开的全部键值
- RegCloseKey(LinkageKey);
- }
- RegCloseKey(NdisPerfKey);
- }
- RegCloseKey(ServicesKey);
- }
- RegCloseKey(ControlSetKey);
- }
- RegCloseKey(SystemKey);
- }
- return Status;
- }
- PVOID PacketOpenAdapter(LPTSTR AdapterName)
- {
- LPADAPTER lpAdapter;
- BOOLEAN Result;
- ODS("Packet32: PacketOpenAdapter/n");
- // 为适配器对象分配全局内存
- lpAdapter=(LPADAPTER)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(ADAPTER));
- if (lpAdapter==NULL)
- {
- ODS("Packet32: PacketOpenAdapter GlobalAlloc Failed/n");
- return NULL;
- }
- // 将名字复制到符号链接名
- wsprintf(lpAdapter->SymbolicLink, TEXT("////.//%s%s"), DOSNAMEPREFIX, &AdapterName[8] );
- // Defines an MS-DOS name for the device.
- Result=DefineDosDevice(DDD_RAW_TARGET_PATH,&lpAdapter->SymbolicLink[4], AdapterName);
- if (Result)
- {
- // Creates and returns a file handle for the specified device. 为特定设备创建并返回文件句柄
- lpAdapter->hFile=CreateFile(lpAdapter->SymbolicLink,GENERIC_WRITE | GENERIC_READ,0,NULL,CREATE_ALWAYS,FILE_FLAG_OVERLAPPED,0);
- if (lpAdapter->hFile != INVALID_HANDLE_VALUE)
- {
- return lpAdapter;
- }
- }
- ODS("Packet32: PacketOpenAdapter Could not open adapter /n");
- GlobalFreePtr(lpAdapter );
- return NULL;
- }
- PVOID PacketAllocatePacket(LPADAPTER AdapterObject)
- {
- LPPACKET lpPacket;
- // 为Packet对象分配内存
- lpPacket=(LPPACKET)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(PACKET));
- if (lpPacket==NULL)
- {
- ODS("Packet32: PacketAllocateSendPacket: GlobalAlloc Failed/n");
- return NULL;
- }
- // 操作结束时建立事件对象
- lpPacket->OverLapped.hEvent=CreateEvent( NULL,FALSE,FALSE, NULL);
- if (lpPacket->OverLapped.hEvent==NULL)
- {
- ODS("Packet32: PacketAllocateSendPacket: CreateEvent Failed/n");
- GlobalFreePtr(lpPacket);
- return NULL;
- }
- return lpPacket;
- }
PacketInitPacket函数设置packet对象缓冲区
- VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length)
- {
- // 设置packet对象缓冲区到缓冲区
- lpPacket->Buffer=Buffer;
- // 设置packet对象缓冲区长度到缓冲区长度
- lpPacket->Length=Length;
- }
- BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync,PULONG BytesReceived)
- {
- BOOLEAN Result;
- // 设置偏移量为0
- lpPacket->OverLapped.Offset=0;
- lpPacket->OverLapped.OffsetHigh=0;
- if (!ResetEvent(lpPacket->OverLapped.hEvent))
- {
- return FALSE;
- }
- // 调用ReadFile来读取数据包
- Result=ReadFile(AdapterObject->hFile,lpPacket->Buffer, lpPacket->Length, BytesReceived, &lpPacket->OverLapped);
- if (Sync)
- {
- // They want to wait
- Result=GetOverlappedResult(AdapterObject->hFile,&lpPacket->OverLapped,BytesReceived, TRUE );
- }
- else
- {
- // They don't want to wait, they will call PacketWaitPacket to get
- // The real result
- //不等待,调用PacketWaitPacket得到真实值
- Result = TRUE;
- }
- return Result;
- }
在数据穿越每一层协议的同一时候,协议栈上对应协议为了栈中下一层协议,将数据封装起来。
因此。封装就是一个将数据存储成协议栈中更低层协议要求的格式的过程。
Protocol
|
Value(Decimal)
|
TCP
|
6
|
UDP
|
17
|
ICMP
|
1
|
IGMP
|
2
|
因此,依靠分析数据包就能够得到URL。URL出项在数据包中的通用格式为:
这必须考虑在内。驱动中使用的是NDIS版本号是3.0。
驱动在Windows NT下工作良好,但不能在Windows95下工作。由于Windows95只支持的是NDIS是2.1版本号和NDIS 3.1版本号。
并且,CE不支持内建的DMA和分配连续的内存块。
更进一步,为CE编写NDIS驱动。程序猿必须考虑到电源管理的问题。
这就是说。必须提供附加的电源管理代码。