这是一本学习 window编程的很好的参考教材

源代码在线查看: filter.c

软件大小: 5535 K
上传用户: ok34090512
关键词: window 编程 教材
下载地址: 免注册下载 普通下载 VIP

相关代码

				// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
				//
				// $Id: filter.c,v 1.2 2003/05/19 14:20:43 dev Exp $
				
				/** @addtogroup hook_driver
				 *@{
				 */
				
				/**
				 * @file ndis_hk\\filter.c
				 * Implementation of functions to work with stack of packet filter drivers
				 *
				 * Stack of packet filter drivers:\n
				 \verbatim
				  +--------------------+  
				  |  adapter (top)     |  
				  +-----------------^--+  
				    +-in            | out 
				  +-V---------------|--+  
				  | |  filter.1     ^  |  
				  +-|---------------|--+  
				  | V  filter.2     ^  |  
				  +-|---------------|--+  
				  | V  filter.3     |  |  
				  +-|---------------^--+  
				    | in            +-out 
				  +-V------------------+  
				  |   tcpip (bottom)   |  
				  +--------------------+  
				 \endverbatim
				 */
				
				#include 
				#include 			// for TdiCopyMdlToBuffer
				
				#include "except.h"
				#include "memtrack.h"
				#include "ndis_hk.h"
				#include "filter.h"
				#include "ndis_hk_ioctl.h"
				
				/** top in filter stack is adapter */
				static struct filter_nfo top;
				/** bottom in filter stack is tcpip */
				static struct filter_nfo bottom;
				/** guard spinlock for top & bottom double linked list */
				static KSPIN_LOCK guard;
				
				static BOOLEAN	queue_for_net(
					int direction, int iface, PNDIS_PACKET packet, struct filter_nfo *self, BOOLEAN packet_unchanged);
				static BOOLEAN	queue_for_tcp(
					int direction, int iface, PNDIS_PACKET packet, struct filter_nfo *self, BOOLEAN packet_unchanged);
				
				/** param for delayed send input packet */
				struct send_in_packet_param {
					ULONG			size;		/**< size of data */
					int				iface;		/**< index of interface */
					WORK_QUEUE_ITEM	item;		/**< we use work items to queue it */
					char			data[0];	/**< packet data */
				};
				
				VOID	send_in_packet_delayed(PVOID p);
				
				void
				init_filter(void)
				{
					KeInitializeSpinLock(&guard);
					
					top.process_packet = queue_for_net;
					top.lower = ⊥
				
					bottom.process_packet = queue_for_tcp;
					bottom.upper = ⊤
				}
				
				void
				attach_filter(struct filter_nfo *flt, BOOLEAN add, BOOLEAN to_top)
				{
					KIRQL irql;
				
					KeAcquireSpinLock(&guard, &irql);
				
					__try {
						if (add) {
							if (to_top) {
								top.lower->upper = flt;
								flt->lower = top.lower;
								
								top.lower = flt;
								flt->upper = ⊤
							
							} else {
								bottom.upper->lower = flt;
								flt->upper = bottom.upper;
				
								bottom.upper = flt;
								flt->lower = ⊥
							}
						} else {
							struct filter_nfo *f;
							for (f = top.lower; f != ⊥ f = f->lower)		// from top to bottom
								if (f == flt) {
									f->upper->lower = f->lower;
									f->lower->upper = f->upper;
									break;
								}
						}
				
					} __finally {
						KeReleaseSpinLock(&guard, irql);
					}
				}
				
				BOOLEAN
				filter_packet(int direction, int iface, PNDIS_PACKET packet)
				{
					BOOLEAN result;
					KIRQL irql;
					
					KeAcquireSpinLock(&guard, &irql);		// using r/w locks give better performance?
					
					__try {
				
						if (direction == DIRECTION_IN)		// from top (adapter) to bottom (tcpip)
							result = top.lower->process_packet(direction, iface, packet, top.lower, TRUE);
						else								// from bottom (tcpip) to top (adapter)
							result = bottom.upper->process_packet(direction, iface, packet, bottom.upper, TRUE);
				
					} __finally {
						KeReleaseSpinLock(&guard, irql);
					}
					
					return result;
				}
				
				/**
				 * On top of filter stack we can queue packet for sending to net if packet was changed.
				 * Can be called at IRQL 				 * @param	direction	DIRECTION_OUT only!
				 * @param	iface		index of interface
				 * @param	packet		NDIS packet to send (can be freed after function call)
				 * @param	self		structure with packet filter information
				 * @param	packet_unchanged	if TRUE function doensn't queue packet
				 * @return				function returns packet_unchanged in any case (doesn't change packet)
				 */
				BOOLEAN
				queue_for_net(int direction, int iface, PNDIS_PACKET packet, struct filter_nfo *self,
							  BOOLEAN packet_unchanged)
				{
					char *packet_data;
					ULONG hdr_size, data_size, packet_size;
					PNDIS_BUFFER buffer;
				
					// sanity check (self == &top)
					if (self != &top) {
						KdPrint(("[ndis_hk] queue_for_net: self != &top!\n"));
						return packet_unchanged;
					}
				
					// sanity check (queue_for_net for DIRECTION_OUT only!)
					if (direction != DIRECTION_OUT)
						return packet_unchanged;
				
					if (packet_unchanged)
						return TRUE;			// no need to queue packet. it's unchanged!
				
				    /*
					 * do async send
					 * to simplify process function they do sync only processing
					 * copy packet
					 * send it and free resources in completion
					 */
				
					send_out_packet(iface, packet);
				
					return FALSE;		// packet_unchanged == FALSE
				}
				
				/**
				 * On bottom of filter stack we can queue packet for sending to TCP/IP protocol if packet was changed.
				 * Can be called at IRQL 				 * @param	direction	DIRECTION_IN only!
				 * @param	iface		index of interface
				 * @param	packet		NDIS packet to send (can be freed after function call)
				 * @param	self		structure with packet filter information
				 * @param	packet_unchanged	if TRUE function doensn't queue packet
				 * @return				function returns packet_unchanged in any case (doesn't change packet)
				 */
				BOOLEAN
				queue_for_tcp(int direction, int iface, PNDIS_PACKET packet, struct filter_nfo *self,
							  BOOLEAN packet_unchanged)
				{
					PNDIS_BUFFER buffer;
					ULONG size, hdr_size;
					struct send_in_packet_param *param;
				
					// sanity check (self == &bottom)
					if (self != &bottom) {
						KdPrint(("[ndis_hk] queue_for_net: self != &bottom!\n"));
						return packet_unchanged;
					}
					
					// sanity check (queue_for_net for DIRECTION_IN only!)
					if (direction != DIRECTION_IN)
						return packet_unchanged;
				
					if (packet_unchanged)
						return TRUE;			// no need to queue packet. it's unchanged!
				
					/*
					 * copy packet and queue it to call simulated receive in another thread
					 */
				
					NdisQueryPacket(packet, NULL, NULL, &buffer, &size);
				
					param = (struct send_in_packet_param *)malloc_np(sizeof(*param) + size);
					if (param == NULL) {
						KdPrint(("[ndis_hk] queue_for_tcp: malloc_np!\n"));
						return packet_unchanged;
					}
				
					memset(param, 0, sizeof(*param));
					
					// A HACK! actually NDIS_BUFFER is MDL so use TdiCopyBufferToMdl (i don't know NDIS equialent)
					TdiCopyMdlToBuffer((PMDL)buffer, 0, param->data, 0, size, &size);
				
					param->size = size;
					param->iface = iface;
				
					/** @todo is it a good idea to use system worker thread here? */
					ExInitializeWorkItem(¶m->item, send_in_packet_delayed, param);
					ExQueueWorkItem(¶m->item, DelayedWorkQueue);	// DelayedWorkQueue a good value?
				
					return FALSE;		// packet_unchanged == FALSE
				}
				
				/**
				 * We use work items to delay sending of packets for input.
				 * This function is called using work items at PASSIVE_LEVEL
				 * @param	p	actually points to struct send_in_packet_param
				 */
				VOID
				send_in_packet_delayed(PVOID p)
				{
					struct send_in_packet_param *param = (struct send_in_packet_param *)p;
					ULONG hdr_size = 14;		// ??? ethernet only ???
				
					send_in_packet(param->iface, hdr_size, param->size - hdr_size, param->data);
				
				    free(param);
				}
				
				/*@}*/			

相关资源