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>
37 #include "time_calls.h"
39 extern struct time_conv G_Start_Time; // from openclos.c
41 //-------------------------------------------------------------------
43 UINT GetBuffOccupation(POPEN_INSTANCE Open)
47 NdisAcquireSpinLock( &Open->BufLock );
49 if(Open->Btail >= Open->Bhead) Occupation = Open->Btail-Open->Bhead;
50 else Occupation = Open->BLastByte-Open->Bhead+Open->Btail;
52 NdisReleaseSpinLock( &Open->BufLock );
57 //-------------------------------------------------------------------
59 void PacketMoveMem(PVOID Destination, PVOID Source, ULONG Length, UINT *Bhead)
65 NBlocks=WordLength>>8;
67 for(n=0;n<NBlocks;n++){
69 *((PULONG)Destination)++=*((PULONG)Source)++;
74 n=WordLength-(NBlocks<<8);
76 *((PULONG)Destination)++=*((PULONG)Source)++;
80 n=Length-(WordLength<<2);
82 *((PUCHAR)Destination)++=*((PUCHAR)Source)++;
87 //-------------------------------------------------------------------
90 NPF_Read(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
93 PIO_STACK_LOCATION IrpSp;
96 ULONG Input_Buffer_Length;
103 LARGE_INTEGER CapTime;
104 LARGE_INTEGER TimeFreq;
105 struct bpf_hdr *header;
110 IF_LOUD(DbgPrint("NPF: Read\n");)
112 IrpSp = IoGetCurrentIrpStackLocation(Irp);
113 Open=IrpSp->FileObject->FsContext;
115 if( Open->Bound == FALSE ){
116 // The Network adapter was removed.
120 if( Open->mode & MODE_DUMP && Open->DumpFileHandle == NULL ){
121 // this instance is in dump mode, but the dump file has still not been opened
125 //See if the buffer is full enough to be copied
126 if( GetBuffOccupation(Open) <= Open->MinToCopy || Open->mode & MODE_DUMP )
128 //wait until some packets arrive or the timeout expires
129 if(Open->TimeOut.QuadPart != (LONGLONG)IMMEDIATE)
130 KeWaitForSingleObject(Open->ReadEvent,
134 (Open->TimeOut.QuadPart == (LONGLONG)0)? NULL: &(Open->TimeOut));
136 KeClearEvent(Open->ReadEvent);
138 if(Open->mode & MODE_STAT){ //this capture instance is in statistics mode
139 CurrBuff=(PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress);
141 //fill the bpf header for this packet
142 header=(struct bpf_hdr*)CurrBuff;
143 GET_TIME(&header->bh_tstamp,&G_Start_Time);
145 if(Open->mode & MODE_DUMP){
146 *(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr)+16)=Open->DumpOffset.QuadPart;
147 header->bh_caplen=24;
148 header->bh_datalen=24;
149 Irp->IoStatus.Information = 24 + sizeof(struct bpf_hdr);
152 header->bh_caplen=16;
153 header->bh_datalen=16;
154 header->bh_hdrlen=sizeof(struct bpf_hdr);
155 Irp->IoStatus.Information = 16 + sizeof(struct bpf_hdr);
158 *(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr))=Open->Npackets.QuadPart;
159 *(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr)+8)=Open->Nbytes.QuadPart;
161 //reset the countetrs
162 NdisAcquireSpinLock( &Open->CountersLock );
163 Open->Npackets.QuadPart=0;
164 Open->Nbytes.QuadPart=0;
165 NdisReleaseSpinLock( &Open->CountersLock );
167 Irp->IoStatus.Status = STATUS_SUCCESS;
168 IoCompleteRequest(Irp, IO_NO_INCREMENT);
170 return STATUS_SUCCESS;
173 if(Open->mode==MODE_MON) //this capture instance is in monitor mode
180 UserPointer=MmGetSystemAddressForMdl(Irp->MdlAddress);
182 if ((!IS_VALIDATED(Open->tme.validated_blocks,Open->tme.active_read))||(IrpSp->Parameters.Read.Length<sizeof(struct bpf_hdr)))
187 header=(struct bpf_hdr*)UserPointer;
189 GET_TIME(&header->bh_tstamp,&G_Start_Time);
192 header->bh_hdrlen=sizeof(struct bpf_hdr);
195 //moves user memory pointer
196 UserPointer+=sizeof(struct bpf_hdr);
198 //calculus of data to be copied
199 //if the user buffer is smaller than data to be copied,
200 //only some data will be copied
201 data=&Open->tme.block_data[Open->tme.active_read];
203 if (data->last_read.tv_sec!=0)
204 data->last_read=header->bh_tstamp;
207 bytecopy=data->block_size*data->filled_blocks;
209 if ((IrpSp->Parameters.Read.Length-sizeof(struct bpf_hdr))<bytecopy)
210 bytecopy=(IrpSp->Parameters.Read.Length-sizeof(struct bpf_hdr))/ data->block_size;
212 bytecopy=data->filled_blocks;
214 tmp=data->shared_memory_base_address;
215 block_size=data->block_size;
217 for (cnt=0;cnt<bytecopy;cnt++)
219 NdisAcquireSpinLock(&Open->machine_lock);
220 RtlCopyMemory(UserPointer,tmp,block_size);
221 NdisReleaseSpinLock(&Open->machine_lock);
223 UserPointer+=block_size;
226 bytecopy*=block_size;
228 header->bh_caplen=bytecopy;
229 header->bh_datalen=header->bh_caplen;
231 EXIT_SUCCESS(bytecopy+sizeof(struct bpf_hdr));
234 if (Open->Bhead == Open->Btail || Open->mode & MODE_DUMP)
235 // The timeout has expired, but the buffer is still empty (or the packets must be written to file).
236 // We must awake the application, returning an empty buffer.
244 // The buffer if full enough to be copied,
246 NdisAcquireSpinLock( &Open->BufLock );
250 TLastByte = Open->BLastByte;
252 //get the address of the buffer
253 CurrBuff=Open->Buffer;
255 NdisReleaseSpinLock( &Open->BufLock );
257 Input_Buffer_Length=IrpSp->Parameters.Read.Length;
258 packp=(PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress);
262 //fill the application buffer
264 if(Ttail > Thead){ //first of all see if it we can copy all the buffer in one time
265 if((Ttail-Thead)<Input_Buffer_Length){
266 KeResetEvent(Open->ReadEvent);
268 PacketMoveMem(packp,CurrBuff+Thead,Ttail-Thead,&(Open->Bhead));
269 EXIT_SUCCESS(Ttail-Thead);
272 else if((TLastByte - Thead) < Input_Buffer_Length){
273 PacketMoveMem(packp, CurrBuff+Thead, TLastByte - Thead, &(Open->Bhead));
275 NdisAcquireSpinLock( &Open->BufLock );
277 Open->BLastByte = Open->Btail;
280 NdisReleaseSpinLock( &Open->BufLock );
282 EXIT_SUCCESS(TLastByte-Thead);
285 //the buffer must be scannned to determine the number of bytes to copy
289 if(Thead == Ttail)break;
291 if(Thead == TLastByte){
292 // Copy the portion between thead and TLastByte
293 PacketMoveMem(packp,CurrBuff+CpStart,Thead-CpStart,&(Open->Bhead));
294 packp+=(Thead-CpStart);
296 NdisAcquireSpinLock( &Open->BufLock );
298 Open->BLastByte = Open->Btail;
301 NdisReleaseSpinLock( &Open->BufLock );
306 cplen=((struct bpf_hdr*)(CurrBuff+Thead))->bh_caplen+sizeof(struct bpf_hdr);
308 if((i+cplen > Input_Buffer_Length)){//no more space in the application's buffer
309 PacketMoveMem(packp,CurrBuff+CpStart,Thead-CpStart,&(Open->Bhead));
313 cplen=Packet_WORDALIGN(cplen);
319 KeResetEvent(Open->ReadEvent);
321 PacketMoveMem(packp,CurrBuff+CpStart,Thead-CpStart,&(Open->Bhead));
329 //-------------------------------------------------------------------
331 NDIS_STATUS NPF_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE MacReceiveContext,
332 IN PVOID HeaderBuffer,IN UINT HeaderBufferSize,IN PVOID LookAheadBuffer,
333 IN UINT LookaheadBufferSize,IN UINT PacketSize)
336 PNDIS_PACKET pPacketb;
337 ULONG SizeToTransfer;
339 UINT BytesTransfered;
342 LARGE_INTEGER CapTime;
343 LARGE_INTEGER TimeFreq;
344 struct bpf_hdr *header;
354 IF_VERY_LOUD(DbgPrint("NPF: tap\n");)
356 Open= (POPEN_INSTANCE)ProtocolBindingContext;
358 Open->Received++; // Number of packets received by filter ++
360 BufOccupation = GetBuffOccupation(Open); // Get the full buffer space
362 if(((Open->mode&MODE_CAPT)||(Open->mode&MODE_DUMP)) && Open->BufSize - BufOccupation < PacketSize+HeaderBufferSize+sizeof(struct bpf_hdr)){
363 // Heuristic that drops the packet also if it possibly fits in the buffer.
364 // It allows to avoid filtering in critical situations when CPU is very important.
366 return NDIS_STATUS_NOT_ACCEPTED;
369 NdisAcquireSpinLock(&Open->machine_lock);
372 //Check if the lookahead buffer follows the mac header.
373 //If the data follow the header (i.e. there is only a buffer) a normal bpf_filter() is
374 //executed on the packet.
375 //Otherwise if there are 2 separate buffers (this could be the case of LAN emulation or
376 //things like this) bpf_filter_with_2_buffers() is executed.
378 if((UINT)LookAheadBuffer-(UINT)HeaderBuffer != HeaderBufferSize)
379 fres=bpf_filter_with_2_buffers((struct bpf_insn*)(Open->bpfprogram),
383 PacketSize+HeaderBufferSize,
384 LookaheadBufferSize+HeaderBufferSize,
391 if(Open->Filter != NULL)
393 if (Open->bpfprogram != NULL)
395 fres=Open->Filter->Function(HeaderBuffer,
396 PacketSize+HeaderBufferSize,
397 LookaheadBufferSize+HeaderBufferSize);
399 // Restore the stack.
400 // I ignore the reason, but this instruction is needed only at kernel level
410 fres=bpf_filter((struct bpf_insn*)(Open->bpfprogram),
412 PacketSize+HeaderBufferSize,
413 LookaheadBufferSize+HeaderBufferSize,
418 NdisReleaseSpinLock(&Open->machine_lock);
420 if(Open->mode==MODE_MON)
421 // we are in monitor mode
424 KeSetEvent(Open->ReadEvent,0,FALSE);
425 return NDIS_STATUS_NOT_ACCEPTED;
430 // Packet not accepted by the filter, ignore it.
431 return NDIS_STATUS_NOT_ACCEPTED;
433 //if the filter returns -1 the whole packet must be accepted
434 if(fres==-1 || fres > PacketSize+HeaderBufferSize)fres=PacketSize+HeaderBufferSize;
436 if(Open->mode & MODE_STAT){
437 // we are in statistics mode
438 NdisAcquireSpinLock( &Open->CountersLock );
440 Open->Npackets.QuadPart++;
442 if(PacketSize+HeaderBufferSize<60)
443 Open->Nbytes.QuadPart+=60;
445 Open->Nbytes.QuadPart+=PacketSize+HeaderBufferSize;
446 // add preamble+SFD+FCS to the packet
447 // these values must be considered because are not part of the packet received from NDIS
448 Open->Nbytes.QuadPart+=12;
450 NdisReleaseSpinLock( &Open->CountersLock );
452 if(!(Open->mode & MODE_DUMP)){
453 return NDIS_STATUS_NOT_ACCEPTED;
457 if(Open->BufSize==0)return NDIS_STATUS_NOT_ACCEPTED;
459 if(Open->mode & MODE_DUMP && Open->MaxDumpPacks && (UINT)Open->Accepted > Open->MaxDumpPacks){
460 // Reached the max number of packets to save in the dump file. Discard the packet and stop the dump thread.
461 Open->DumpLimitReached = TRUE; // This stops the thread
462 // Awake the dump thread
463 NdisSetEvent(&Open->DumpEvent);
465 // Awake the application
466 KeSetEvent(Open->ReadEvent,0,FALSE);
468 return NDIS_STATUS_NOT_ACCEPTED;
471 // Calculate the correct size for the header associated with the packet
472 NPFHdrSize=(Open->mode==MODE_CAPT)? sizeof(struct bpf_hdr): sizeof(struct sf_pkthdr);
474 NdisAcquireSpinLock( &Open->BufLock );
478 TLastByte = Open->BLastByte;
480 NdisReleaseSpinLock( &Open->BufLock );
482 maxbufspace=Packet_WORDALIGN(fres+NPFHdrSize);
484 if(Ttail+maxbufspace >= Open->BufSize){
485 if(Thead <= maxbufspace)
488 return NDIS_STATUS_NOT_ACCEPTED;
495 CurrBuff=Open->Buffer+Ttail;
497 if(LookaheadBufferSize != PacketSize || (UINT)LookAheadBuffer-(UINT)HeaderBuffer != HeaderBufferSize)
499 // Allocate an MDL to map the portion of the buffer following the header
500 pMdl=IoAllocateMdl(CurrBuff+HeaderBufferSize+LookaheadBufferSize+NPFHdrSize,
508 // Unable to map the memory: packet lost
509 IF_LOUD(DbgPrint("NPF: Read-Failed to allocate Mdl\n");)
511 return NDIS_STATUS_NOT_ACCEPTED;
513 MmBuildMdlForNonPagedPool(pMdl);
515 //allocate the packet from NDIS
516 NdisAllocatePacket(&Status, &pPacketb, Open->PacketPool);
517 if (Status != NDIS_STATUS_SUCCESS)
519 IF_LOUD(DbgPrint("NPF: Tap - No free packets\n");)
522 return NDIS_STATUS_NOT_ACCEPTED;
524 //link the buffer to the packet
525 NdisChainBufferAtFront(pPacketb,pMdl);
527 BufferLength=fres-HeaderBufferSize;
528 //Find out how much to transfer
529 SizeToTransfer = (PacketSize < BufferLength) ? PacketSize : BufferLength;
531 //copy the ethernet header into buffer
532 NdisMoveMappedMemory((CurrBuff)+NPFHdrSize,HeaderBuffer,HeaderBufferSize);
534 //Copy the look ahead buffer
535 if(LookaheadBufferSize)
537 NdisMoveMappedMemory((CurrBuff) + NPFHdrSize + HeaderBufferSize,
539 (SizeToTransfer < LookaheadBufferSize)? SizeToTransfer : LookaheadBufferSize );
541 SizeToTransfer = (SizeToTransfer > LookaheadBufferSize)?
542 SizeToTransfer - LookaheadBufferSize : 0;
545 Open->TransferMdl=pMdl;
549 //Call the Mac to transfer the packet
550 NdisTransferData(&Status,
565 // The whole packet is in the lookahead buffer, we can avoid the call to NdisTransferData.
566 // This allows us to avoid the allocation of the MDL and the NDIS packet as well
567 RtlCopyMemory((CurrBuff) + NPFHdrSize,
569 HeaderBufferSize + LookaheadBufferSize);
571 Open->TransferMdl = NULL;
572 Status = NDIS_STATUS_SUCCESS;
575 Open->Accepted++; // Increase the accepted packets counter
577 if (Status != NDIS_STATUS_FAILURE)
580 if( fres > (BytesTransfered+HeaderBufferSize+LookaheadBufferSize) )
581 fres = BytesTransfered+HeaderBufferSize+LookaheadBufferSize;
586 header=(struct bpf_hdr*)CurrBuff;
587 GET_TIME(&header->bh_tstamp,&G_Start_Time);
588 header->bh_caplen=fres;
589 header->bh_datalen=PacketSize+HeaderBufferSize;
590 if(Open->mode==MODE_CAPT){
591 header->bh_hdrlen=NPFHdrSize;
592 // Don't align if the packet goes to disk
593 Ttail+=Packet_WORDALIGN(fres + NPFHdrSize);
596 Ttail+=fres+NPFHdrSize;
599 if(Ttail > Thead)TLastByte = Ttail;
601 NdisAcquireSpinLock( &Open->BufLock );
604 Open->BLastByte=TLastByte;
606 NdisReleaseSpinLock( &Open->BufLock );
609 if (Status != NDIS_STATUS_PENDING){
611 if( Open->TransferMdl != NULL)
612 // Complete the request and free the buffers
613 NPF_TransferDataComplete(Open,pPacketb,Status,fres);
615 // Unfreeze the consumer
616 if(GetBuffOccupation(Open)>Open->MinToCopy){
617 if(Open->mode & MODE_DUMP){
618 NdisSetEvent(&Open->DumpEvent);
621 KeSetEvent(Open->ReadEvent,0,FALSE);
627 return NDIS_STATUS_SUCCESS;
631 //-------------------------------------------------------------------
633 VOID NPF_TransferDataComplete (IN NDIS_HANDLE ProtocolBindingContext,IN PNDIS_PACKET pPacket,
634 IN NDIS_STATUS Status,IN UINT BytesTransfered)
638 IF_LOUD(DbgPrint("NPF: TransferDataComplete\n");)
640 Open= (POPEN_INSTANCE)ProtocolBindingContext;
642 IoFreeMdl(Open->TransferMdl);
643 //recylcle the packet
644 NdisReinitializePacket(pPacket);
645 //Put the packet on the free queue
646 NdisFreePacket(pPacket);
647 // Unfreeze the consumer
648 if(GetBuffOccupation(Open)>Open->MinToCopy){
649 if(Open->mode & MODE_DUMP){
650 NdisSetEvent(&Open->DumpEvent);
653 KeSetEvent(Open->ReadEvent,0,FALSE);
658 //-------------------------------------------------------------------
660 VOID NPF_ReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext)
662 IF_VERY_LOUD(DbgPrint("NPF: NPF_ReceiveComplete\n");)