2 * Copyright (c) 1999, 2000
3 * Politecnico di Torino. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the Politecnico
13 * di Torino, and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28 #include <ddk/ntddk.h>
31 #define NdisReinitializePacket(Packet) \
33 (Packet)->Private.Head = (PNDIS_BUFFER)NULL; \
34 (Packet)->Private.ValidCounts = FALSE; \
45 #include "time_calls.h"
47 extern struct time_conv G_Start_Time
; // from openclos.c
49 //-------------------------------------------------------------------
51 UINT
GetBuffOccupation(POPEN_INSTANCE Open
)
55 NdisAcquireSpinLock( &Open
->BufLock
);
57 if(Open
->Btail
>= Open
->Bhead
) Occupation
= Open
->Btail
-Open
->Bhead
;
58 else Occupation
= Open
->BLastByte
-Open
->Bhead
+Open
->Btail
;
60 NdisReleaseSpinLock( &Open
->BufLock
);
65 //-------------------------------------------------------------------
67 void PacketMoveMem(PVOID Destination
, PVOID Source
, ULONG Length
, UINT
*Bhead
)
75 NBlocks
=WordLength
>>8;
77 ULSrc
= (PULONG
) Source
;
78 ULDest
= (PULONG
) Destination
;
79 for(n
=0;n
<NBlocks
;n
++){
86 n
=WordLength
-(NBlocks
<<8);
92 UCDest
= (PUCHAR
) ULDest
;
93 UCSrc
= (PUCHAR
) ULSrc
;
94 n
=Length
-(WordLength
<<2);
101 //-------------------------------------------------------------------
104 NPF_Read(IN PDEVICE_OBJECT DeviceObject
,IN PIRP Irp
)
107 PIO_STACK_LOCATION IrpSp
;
109 ULONG Input_Buffer_Length
;
114 struct bpf_hdr
*header
;
120 IF_LOUD(DbgPrint("NPF: Read\n");)
122 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
123 Open
=IrpSp
->FileObject
->FsContext
;
125 if( Open
->Bound
== FALSE
){
126 // The Network adapter was removed.
130 if( Open
->mode
& MODE_DUMP
&& Open
->DumpFileHandle
== NULL
){
131 // this instance is in dump mode, but the dump file has still not been opened
135 //See if the buffer is full enough to be copied
136 if( GetBuffOccupation(Open
) <= Open
->MinToCopy
|| Open
->mode
& MODE_DUMP
)
138 //wait until some packets arrive or the timeout expires
139 if(Open
->TimeOut
.QuadPart
!= (LONGLONG
)IMMEDIATE
)
140 KeWaitForSingleObject(Open
->ReadEvent
,
144 (Open
->TimeOut
.QuadPart
== (LONGLONG
)0)? NULL
: &(Open
->TimeOut
));
146 KeClearEvent(Open
->ReadEvent
);
148 if(Open
->mode
& MODE_STAT
){ //this capture instance is in statistics mode
149 CurrBuff
=(PUCHAR
)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
151 //fill the bpf header for this packet
152 header
=(struct bpf_hdr
*)CurrBuff
;
153 GET_TIME(&header
->bh_tstamp
,&G_Start_Time
);
155 if(Open
->mode
& MODE_DUMP
){
156 *(LONGLONG
*)(CurrBuff
+sizeof(struct bpf_hdr
)+16)=Open
->DumpOffset
.QuadPart
;
157 header
->bh_caplen
=24;
158 header
->bh_datalen
=24;
159 Irp
->IoStatus
.Information
= 24 + sizeof(struct bpf_hdr
);
162 header
->bh_caplen
=16;
163 header
->bh_datalen
=16;
164 header
->bh_hdrlen
=sizeof(struct bpf_hdr
);
165 Irp
->IoStatus
.Information
= 16 + sizeof(struct bpf_hdr
);
168 *(LONGLONG
*)(CurrBuff
+sizeof(struct bpf_hdr
))=Open
->Npackets
.QuadPart
;
169 *(LONGLONG
*)(CurrBuff
+sizeof(struct bpf_hdr
)+8)=Open
->Nbytes
.QuadPart
;
171 //reset the countetrs
172 NdisAcquireSpinLock( &Open
->CountersLock
);
173 Open
->Npackets
.QuadPart
=0;
174 Open
->Nbytes
.QuadPart
=0;
175 NdisReleaseSpinLock( &Open
->CountersLock
);
177 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
178 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
180 return STATUS_SUCCESS
;
183 if(Open
->mode
==MODE_MON
) //this capture instance is in monitor mode
190 UserPointer
=MmGetSystemAddressForMdl(Irp
->MdlAddress
);
192 if ((!IS_VALIDATED(Open
->tme
.validated_blocks
,Open
->tme
.active_read
))||(IrpSp
->Parameters
.Read
.Length
<sizeof(struct bpf_hdr
)))
197 header
=(struct bpf_hdr
*)UserPointer
;
199 GET_TIME(&header
->bh_tstamp
,&G_Start_Time
);
202 header
->bh_hdrlen
=sizeof(struct bpf_hdr
);
205 //moves user memory pointer
206 UserPointer
+=sizeof(struct bpf_hdr
);
208 //calculus of data to be copied
209 //if the user buffer is smaller than data to be copied,
210 //only some data will be copied
211 data
=&Open
->tme
.block_data
[Open
->tme
.active_read
];
213 if (data
->last_read
.tv_sec
!=0)
214 data
->last_read
=header
->bh_tstamp
;
217 bytecopy
=data
->block_size
*data
->filled_blocks
;
219 if ((IrpSp
->Parameters
.Read
.Length
-sizeof(struct bpf_hdr
))<bytecopy
)
220 bytecopy
=(IrpSp
->Parameters
.Read
.Length
-sizeof(struct bpf_hdr
))/ data
->block_size
;
222 bytecopy
=data
->filled_blocks
;
224 tmp
=data
->shared_memory_base_address
;
225 block_size
=data
->block_size
;
227 for (cnt
=0;cnt
<bytecopy
;cnt
++)
229 NdisAcquireSpinLock(&Open
->machine_lock
);
230 RtlCopyMemory(UserPointer
,tmp
,block_size
);
231 NdisReleaseSpinLock(&Open
->machine_lock
);
233 UserPointer
+=block_size
;
236 bytecopy
*=block_size
;
238 header
->bh_caplen
=bytecopy
;
239 header
->bh_datalen
=header
->bh_caplen
;
241 EXIT_SUCCESS(bytecopy
+sizeof(struct bpf_hdr
));
244 if (Open
->Bhead
== Open
->Btail
|| Open
->mode
& MODE_DUMP
)
245 // The timeout has expired, but the buffer is still empty (or the packets must be written to file).
246 // We must awake the application, returning an empty buffer.
254 // The buffer if full enough to be copied,
256 NdisAcquireSpinLock( &Open
->BufLock
);
260 TLastByte
= Open
->BLastByte
;
262 //get the address of the buffer
263 CurrBuff
=Open
->Buffer
;
265 NdisReleaseSpinLock( &Open
->BufLock
);
267 Input_Buffer_Length
=IrpSp
->Parameters
.Read
.Length
;
268 packp
=(PUCHAR
)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
272 //fill the application buffer
274 if(Ttail
> Thead
){ //first of all see if it we can copy all the buffer in one time
275 if((Ttail
-Thead
)<Input_Buffer_Length
){
276 KeResetEvent(Open
->ReadEvent
);
278 PacketMoveMem(packp
,CurrBuff
+Thead
,Ttail
-Thead
,&(Open
->Bhead
));
279 EXIT_SUCCESS(Ttail
-Thead
);
282 else if((TLastByte
- Thead
) < Input_Buffer_Length
){
283 PacketMoveMem(packp
, CurrBuff
+Thead
, TLastByte
- Thead
, &(Open
->Bhead
));
285 NdisAcquireSpinLock( &Open
->BufLock
);
287 Open
->BLastByte
= Open
->Btail
;
290 NdisReleaseSpinLock( &Open
->BufLock
);
292 EXIT_SUCCESS(TLastByte
-Thead
);
295 //the buffer must be scannned to determine the number of bytes to copy
298 if(Thead
+ SizeToCopy
== Ttail
)
301 if(Thead
+ SizeToCopy
== TLastByte
&& TLastByte
!= Ttail
){
303 PacketMoveMem(packp
, CurrBuff
+Thead
, SizeToCopy
, &(Open
->Bhead
));
305 NdisAcquireSpinLock( &Open
->BufLock
);
306 Open
->BLastByte
= (UINT
) -1;
308 NdisReleaseSpinLock( &Open
->BufLock
);
310 EXIT_SUCCESS(SizeToCopy
);
313 // Get the size of the next packet in the buffer
314 PktLen
= ((struct bpf_hdr
*)(CurrBuff
+ Thead
+ SizeToCopy
))->bh_caplen
+ sizeof(struct bpf_hdr
);
316 // The length is aligned to 32-bit boundary
317 PktLen
= Packet_WORDALIGN(PktLen
);
319 if(SizeToCopy
+ PktLen
> Input_Buffer_Length
)
322 SizeToCopy
+= PktLen
;
325 PacketMoveMem(packp
, CurrBuff
+Thead
, SizeToCopy
, &(Open
->Bhead
));
326 EXIT_SUCCESS(SizeToCopy
);
330 //-------------------------------------------------------------------
332 NDIS_STATUS STDCALL
NPF_tap (IN NDIS_HANDLE ProtocolBindingContext
,IN NDIS_HANDLE MacReceiveContext
,
333 IN PVOID HeaderBuffer
,IN UINT HeaderBufferSize
,IN PVOID LookAheadBuffer
,
334 IN UINT LookaheadBufferSize
,IN UINT PacketSize
)
337 PNDIS_PACKET pPacketb
;
338 ULONG SizeToTransfer
;
340 UINT BytesTransfered
;
343 struct bpf_hdr
*header
;
352 BOOLEAN ResetBuff
= FALSE
;
354 IF_VERY_LOUD(DbgPrint("NPF: tap\n");)
355 IF_VERY_LOUD(DbgPrint("HeaderBufferSize=%d, LookAheadBuffer=%d, LookaheadBufferSize=%d, PacketSize=%d\n",
361 Open
= (POPEN_INSTANCE
)ProtocolBindingContext
;
363 Open
->Received
++; // Number of packets received by filter ++
365 BufOccupation
= GetBuffOccupation(Open
); // Get the full buffer space
367 if(((Open
->mode
&MODE_CAPT
)||(Open
->mode
&MODE_DUMP
)) && Open
->BufSize
- BufOccupation
< PacketSize
+HeaderBufferSize
+sizeof(struct bpf_hdr
)){
368 // Heuristic that drops the packet also if it possibly fits in the buffer.
369 // It allows to avoid filtering in critical situations when CPU is very important.
371 return NDIS_STATUS_NOT_ACCEPTED
;
374 NdisAcquireSpinLock(&Open
->machine_lock
);
377 //Check if the lookahead buffer follows the mac header.
378 //If the data follow the header (i.e. there is only a buffer) a normal bpf_filter() is
379 //executed on the packet.
380 //Otherwise if there are 2 separate buffers (this could be the case of LAN emulation or
381 //things like this) bpf_filter_with_2_buffers() is executed.
383 if((UINT
)LookAheadBuffer
-(UINT
)HeaderBuffer
!= HeaderBufferSize
)
384 fres
=bpf_filter_with_2_buffers((struct bpf_insn
*)(Open
->bpfprogram
),
388 PacketSize
+HeaderBufferSize
,
389 LookaheadBufferSize
+HeaderBufferSize
,
396 if(Open
->Filter
!= NULL
)
398 if (Open
->bpfprogram
!= NULL
)
400 fres
=Open
->Filter
->Function(HeaderBuffer
,
401 PacketSize
+HeaderBufferSize
,
402 LookaheadBufferSize
+HeaderBufferSize
);
404 // Restore the stack.
405 // I ignore the reason, but this instruction is needed only at kernel level
409 asm("add $0x12,%esp;");
416 fres
=bpf_filter((struct bpf_insn
*)(Open
->bpfprogram
),
418 PacketSize
+HeaderBufferSize
,
419 LookaheadBufferSize
+HeaderBufferSize
,
424 NdisReleaseSpinLock(&Open
->machine_lock
);
426 if(Open
->mode
==MODE_MON
)
427 // we are in monitor mode
430 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
431 return NDIS_STATUS_NOT_ACCEPTED
;
436 // Packet not accepted by the filter, ignore it.
437 return NDIS_STATUS_NOT_ACCEPTED
;
439 //if the filter returns -1 the whole packet must be accepted
440 if(fres
==(UINT
)-1 || fres
> PacketSize
+HeaderBufferSize
)fres
=PacketSize
+HeaderBufferSize
;
442 if(Open
->mode
& MODE_STAT
){
443 // we are in statistics mode
444 NdisAcquireSpinLock( &Open
->CountersLock
);
446 Open
->Npackets
.QuadPart
++;
448 if(PacketSize
+HeaderBufferSize
<60)
449 Open
->Nbytes
.QuadPart
+=60;
451 Open
->Nbytes
.QuadPart
+=PacketSize
+HeaderBufferSize
;
452 // add preamble+SFD+FCS to the packet
453 // these values must be considered because are not part of the packet received from NDIS
454 Open
->Nbytes
.QuadPart
+=12;
456 NdisReleaseSpinLock( &Open
->CountersLock
);
458 if(!(Open
->mode
& MODE_DUMP
)){
459 return NDIS_STATUS_NOT_ACCEPTED
;
463 if(Open
->BufSize
==0)return NDIS_STATUS_NOT_ACCEPTED
;
465 if(Open
->mode
& MODE_DUMP
&& Open
->MaxDumpPacks
&& (UINT
)Open
->Accepted
> Open
->MaxDumpPacks
){
466 // Reached the max number of packets to save in the dump file. Discard the packet and stop the dump thread.
467 Open
->DumpLimitReached
= TRUE
; // This stops the thread
468 // Awake the dump thread
469 NdisSetEvent(&Open
->DumpEvent
);
471 // Awake the application
472 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
474 return NDIS_STATUS_NOT_ACCEPTED
;
477 // Calculate the correct size for the header associated with the packet
478 NPFHdrSize
=(Open
->mode
==MODE_CAPT
)? sizeof(struct bpf_hdr
): sizeof(struct sf_pkthdr
);
480 NdisAcquireSpinLock( &Open
->BufLock
);
484 TLastByte
= Open
->BLastByte
;
486 NdisReleaseSpinLock( &Open
->BufLock
);
488 maxbufspace
=Packet_WORDALIGN(fres
+NPFHdrSize
);
490 if(Ttail
+maxbufspace
>= Open
->BufSize
){
491 if(Thead
<= maxbufspace
)
494 return NDIS_STATUS_NOT_ACCEPTED
;
502 if (Thead
> Ttail
&& (Thead
-Ttail
) <= maxbufspace
)
505 return NDIS_STATUS_NOT_ACCEPTED
;
508 CurrBuff
=Open
->Buffer
+Ttail
;
510 if(LookaheadBufferSize
!= PacketSize
|| (UINT
)LookAheadBuffer
-(UINT
)HeaderBuffer
!= HeaderBufferSize
)
512 // Allocate an MDL to map the portion of the buffer following the header
513 pMdl
=IoAllocateMdl(CurrBuff
+HeaderBufferSize
+LookaheadBufferSize
+NPFHdrSize
,
521 // Unable to map the memory: packet lost
522 IF_LOUD(DbgPrint("NPF: Read-Failed to allocate Mdl\n");)
524 return NDIS_STATUS_NOT_ACCEPTED
;
526 MmBuildMdlForNonPagedPool(pMdl
);
528 //allocate the packet from NDIS
529 NdisAllocatePacket(&Status
, &pPacketb
, Open
->PacketPool
);
530 if (Status
!= NDIS_STATUS_SUCCESS
)
532 IF_LOUD(DbgPrint("NPF: Tap - No free packets\n");)
535 return NDIS_STATUS_NOT_ACCEPTED
;
537 //link the buffer to the packet
538 NdisChainBufferAtFront(pPacketb
,pMdl
);
540 BufferLength
=fres
-HeaderBufferSize
;
541 //Find out how much to transfer
542 SizeToTransfer
= (PacketSize
< BufferLength
) ? PacketSize
: BufferLength
;
544 //copy the ethernet header into buffer
545 NdisMoveMappedMemory((CurrBuff
)+NPFHdrSize
,HeaderBuffer
,HeaderBufferSize
);
547 //Copy the look ahead buffer
548 if(LookaheadBufferSize
)
550 NdisMoveMappedMemory((CurrBuff
) + NPFHdrSize
+ HeaderBufferSize
,
552 (SizeToTransfer
< LookaheadBufferSize
)? SizeToTransfer
: LookaheadBufferSize
);
554 SizeToTransfer
= (SizeToTransfer
> LookaheadBufferSize
)?
555 SizeToTransfer
- LookaheadBufferSize
: 0;
558 Open
->TransferMdl
=pMdl
;
562 //Call the Mac to transfer the packet
563 NdisTransferData(&Status
,
578 // The whole packet is in the lookahead buffer, we can avoid the call to NdisTransferData.
579 // This allows us to avoid the allocation of the MDL and the NDIS packet as well
580 RtlCopyMemory((CurrBuff
) + NPFHdrSize
,
582 HeaderBufferSize
+ LookaheadBufferSize
);
586 Open
->TransferMdl
= NULL
;
587 Status
= NDIS_STATUS_SUCCESS
;
590 if (Status
!= NDIS_STATUS_FAILURE
)
593 Open
->Accepted
++; // Increase the accepted packets counter
595 if( fres
> (BytesTransfered
+HeaderBufferSize
+LookaheadBufferSize
) )
596 fres
= BytesTransfered
+HeaderBufferSize
+LookaheadBufferSize
;
601 header
=(struct bpf_hdr
*)CurrBuff
;
602 GET_TIME(&header
->bh_tstamp
,&G_Start_Time
);
603 header
->bh_caplen
=fres
;
604 header
->bh_datalen
=PacketSize
+HeaderBufferSize
;
605 if(Open
->mode
==MODE_CAPT
){
606 header
->bh_hdrlen
=NPFHdrSize
;
607 // Don't align if the packet goes to disk
608 Ttail
+=Packet_WORDALIGN(fres
+ NPFHdrSize
);
611 Ttail
+=fres
+NPFHdrSize
;
614 NdisAcquireSpinLock( &Open
->BufLock
);
617 Open
->BLastByte
= Open
->Btail
;
621 NdisReleaseSpinLock( &Open
->BufLock
);
624 if (Status
!= NDIS_STATUS_PENDING
){
626 if( Open
->TransferMdl
!= NULL
)
627 // Complete the request and free the buffers
628 NPF_TransferDataComplete(Open
,pPacketb
,Status
,fres
);
630 // Unfreeze the consumer
631 if(GetBuffOccupation(Open
)>Open
->MinToCopy
){
632 if(Open
->mode
& MODE_DUMP
){
633 NdisSetEvent(&Open
->DumpEvent
);
636 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
642 return NDIS_STATUS_SUCCESS
;
646 //-------------------------------------------------------------------
648 VOID STDCALL
NPF_TransferDataComplete (IN NDIS_HANDLE ProtocolBindingContext
,IN PNDIS_PACKET pPacket
,
649 IN NDIS_STATUS Status
,IN UINT BytesTransfered
)
653 IF_LOUD(DbgPrint("NPF: TransferDataComplete\n");)
655 Open
= (POPEN_INSTANCE
)ProtocolBindingContext
;
657 IoFreeMdl(Open
->TransferMdl
);
658 //recylcle the packet
659 NdisReinitializePacket(pPacket
);
660 //Put the packet on the free queue
661 NdisFreePacket(pPacket
);
662 // Unfreeze the consumer
663 if(GetBuffOccupation(Open
)>Open
->MinToCopy
){
664 if(Open
->mode
& MODE_DUMP
){
665 NdisSetEvent(&Open
->DumpEvent
);
668 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
673 //-------------------------------------------------------------------
675 VOID STDCALL
NPF_ReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext
)
677 IF_VERY_LOUD(DbgPrint("NPF: NPF_ReceiveComplete\n");)