1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
|
/*
* Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
* Copyright (c) 2005 CACE Technologies, Davis (California)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Politecnico di Torino, CACE Technologies
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @ingroup NPF
* @{
*/
/** @defgroup NPF_include NPF structures and definitions
* @{
*/
#ifndef __PACKET_INCLUDE______
#define __PACKET_INCLUDE______
#ifdef __NPF_x86__
#define NTKERNEL ///< Forces the compilation of the jitter with kernel calls
#include "jitter.h"
#endif
#include "win_bpf.h"
#define MAX_REQUESTS 256 ///< Maximum number of simultaneous IOCTL requests.
#define Packet_ALIGNMENT sizeof(int) ///< Alignment macro. Defines the alignment size.
#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) ///< Alignment macro. Rounds up to the next
///< even multiple of Packet_ALIGNMENT.
/***************************/
/* IOCTLs */
/***************************/
/*!
\brief IOCTL code: set kernel buffer size.
This IOCTL is used to set a new size of the circular buffer associated with an instance of NPF.
When a BIOCSETBUFFERSIZE command is received, the driver frees the old buffer, allocates the new one
and resets all the parameters associated with the buffer in the OPEN_INSTANCE structure. The currently
buffered packets are lost.
*/
#define BIOCSETBUFFERSIZE 9592
/*!
\brief IOCTL code: set packet filtering program.
This IOCTL sets a new packet filter in the driver. Before allocating any memory for the new filter, the
bpf_validate() function is called to check the correctness of the filter. If this function returns TRUE,
the filter is copied to the driver's memory, its address is stored in the bpfprogram field of the
OPEN_INSTANCE structure associated with current instance of the driver, and the filter will be applied to
every incoming packet. This command also empties the circular buffer used by current instance
to store packets. This is done to avoid the presence in the buffer of packets that do not match the filter.
*/
#define BIOCSETF 9030
/*!
\brief IOCTL code: get the capture stats
This command returns to the application the number of packets received and the number of packets dropped by
an instance of the driver.
*/
#define BIOCGSTATS 9031
/*!
\brief IOCTL code: set the read timeout
This command sets the maximum timeout after which a read is released, also if no data packets were received.
*/
#define BIOCSRTIMEOUT 7416
/*!
\brief IOCTL code: set working mode
This IOCTL can be used to set the working mode of a NPF instance. The new mode, received by the driver in the
buffer associated with the IOCTL command, can be #MODE_CAPT for capture mode (the default), #MODE_STAT for
statistical mode or #MODE_DUMP for dump mode.
*/
#define BIOCSMODE 7412
/*!
\brief IOCTL code: set number of physical repetions of every packet written by the app
Sets the number of times a single write call must be repeated. This command sets the OPEN_INSTANCE::Nwrites
member, and is used to implement the 'multiple write' feature of the driver.
*/
#define BIOCSWRITEREP 7413
/*!
\brief IOCTL code: set minimum amount of data in the kernel buffer that unlocks a read call
This command sets the OPEN_INSTANCE::MinToCopy member.
*/
#define BIOCSMINTOCOPY 7414
/*!
\brief IOCTL code: set an OID value
This IOCTL is used to perform an OID set operation on the NIC driver.
*/
#define BIOCSETOID 2147483648
/*!
\brief IOCTL code: get an OID value
This IOCTL is used to perform an OID get operation on the NIC driver.
*/
#define BIOCQUERYOID 2147483652
#define BIOCISETLOBBEH 7410
/*!
\brief IOCTL code: set the name of a the file used by kernel dump mode
This command opens a file whose name is contained in the IOCTL buffer and associates it with current NPf instance.
The dump thread uses it to copy the content of the circular buffer to file.
If a file was already opened, the driver closes it before opening the new one.
*/
#define BIOCSETDUMPFILENAME 9029
/*!
\brief IOCTL code: get the name of the event that the driver signals when some data is present in the buffer
Command used by the application to retrieve the name of the global event associated with a NPF instance.
The event is signaled by the driver when the kernel buffer contains enough data for a transfer.
*/
#define BIOCGEVNAME 7415
/*!
\brief IOCTL code: Send a buffer containing multiple packets to the network, ignoring the timestamps.
Command used to send a buffer of packets in a single system call. Every packet in the buffer is preceded by
a sf_pkthdr structure. The timestamps of the packets are ignored, i.e. the packets are sent as fast as
possible. The NPF_BufferedWrite() function is invoked to send the packets.
*/
#define BIOCSENDPACKETSNOSYNC 9032
/*!
\brief IOCTL code: Send a buffer containing multiple packets to the network, considering the timestamps.
Command used to send a buffer of packets in a single system call. Every packet in the buffer is preceded by
a sf_pkthdr structure. The timestamps of the packets are used to synchronize the write, i.e. the packets
are sent to the network respecting the intervals specified in the sf_pkthdr structure assiciated with each
packet. NPF_BufferedWrite() function is invoked to send the packets.
*/
#define BIOCSENDPACKETSSYNC 9033
/*!
\brief IOCTL code: Set the dump file limits.
This IOCTL sets the limits (maximum size and maximum number of packets) of the dump file created when the
driver works in dump mode.
*/
#define BIOCSETDUMPLIMITS 9034
/*!
\brief IOCTL code: Get the status of the kernel dump process.
This command returns TRUE if the kernel dump is ended, i.e if one of the limits set with BIOCSETDUMPLIMITS
(amount of bytes or number of packets) has been reached.
*/
#define BIOCISDUMPENDED 7411
// Working modes
#define MODE_CAPT 0x0 ///< Capture working mode
#define MODE_STAT 0x1 ///< Statistical working mode
#define MODE_MON 0x2 ///< Kernel monitoring mode
#define MODE_DUMP 0x10 ///< Kernel dump working mode
#define IMMEDIATE 1 ///< Immediate timeout. Forces a read call to return immediately.
// The following definitions are used to provide compatibility
// of the dump files with the ones of libpcap
#define TCPDUMP_MAGIC 0xa1b2c3d4 ///< Libpcap magic number. Used by programs like tcpdump to recognize a driver's generated dump file.
#define PCAP_VERSION_MAJOR 2 ///< Major libpcap version of the dump file. Used by programs like tcpdump to recognize a driver's generated dump file.
#define PCAP_VERSION_MINOR 4 ///< Minor libpcap version of the dump file. Used by programs like tcpdump to recognize a driver's generated dump file.
/*!
\brief Header of a libpcap dump file.
Used when a driver instance is set in dump mode to create a libpcap-compatible file.
*/
struct packet_file_header
{
UINT magic; ///< Libpcap magic number
USHORT version_major; ///< Libpcap major version
USHORT version_minor; ///< Libpcap minor version
UINT thiszone; ///< Gmt to local correction
UINT sigfigs; ///< Accuracy of timestamps
UINT snaplen; ///< Length of the max saved portion of each packet
UINT linktype; ///< Data link type (DLT_*). See win_bpf.h for details.
};
/*!
\brief Header associated to a packet in the driver's buffer when the driver is in dump mode.
Similar to the bpf_hdr structure, but simpler.
*/
struct sf_pkthdr {
struct timeval ts; ///< time stamp
UINT caplen; ///< Length of captured portion. The captured portion can be different from
///< the original packet, because it is possible (with a proper filter) to
///< instruct the driver to capture only a portion of the packets.
UINT len; ///< Length of the original packet (off wire).
};
/*!
\brief Stores an OID request.
This structure is used by the driver to perform OID query or set operations on the underlying NIC driver.
The OID operations be performed usually only by network drivers, but NPF exports this mechanism to user-level
applications through an IOCTL interface. The driver uses this structure to wrap a NDIS_REQUEST structure.
This allows to handle correctly the callback structure of NdisRequest(), handling multiple requests and
maintaining information about the IRPs to complete.
*/
typedef struct _INTERNAL_REQUEST {
LIST_ENTRY ListElement; ///< Used to handle lists of requests.
PIRP Irp; ///< Irp that performed the request
BOOLEAN Internal; ///< True if the request is for internal use of npf.sys. False if the request is performed by the user through an IOCTL.
NDIS_REQUEST Request; ///< The structure with the actual request, that will be passed to NdisRequest().
} INTERNAL_REQUEST, *PINTERNAL_REQUEST;
/*!
\brief Contains a NDIS packet.
The driver uses this structure to wrap a NDIS_PACKET structure.
This allows to handle correctly the callback structure of NdisTransferData(), handling multiple requests and
maintaining information about the IRPs to complete.
*/
typedef struct _PACKET_RESERVED {
LIST_ENTRY ListElement; ///< Used to handle lists of packets.
PIRP Irp; ///< Irp that performed the request
PMDL pMdl; ///< MDL mapping the buffer of the packet.
BOOLEAN FreeBufAfterWrite; ///< True if the memory buffer associated with the packet must be freed
///< after a call to NdisSend().
ULONG Cpu; ///< The CPU on which the packet was pulled out of the linked list of free packets
} PACKET_RESERVED, *PPACKET_RESERVED;
#define RESERVED(_p) ((PPACKET_RESERVED)((_p)->ProtocolReserved)) ///< Macro to obtain a NDIS_PACKET from a PACKET_RESERVED
/*!
\brief Port device extension.
Structure containing some data relative to every adapter on which NPF is bound.
*/
typedef struct _DEVICE_EXTENSION {
NDIS_HANDLE NdisProtocolHandle; ///< NDIS handle of NPF.
NDIS_STRING AdapterName; ///< Name of the adapter.
PWSTR ExportString; ///< Name of the exported device, i.e. name that the applications will use
///< to open this adapter through WinPcap.
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
/*!
\brief Kernel buffer of each CPU.
Structure containing the kernel buffer (and other CPU related fields) used to capture packets.
*/
typedef struct __CPU_Private_Data
{
ULONG P; ///< Zero-based index of the producer in the buffer. It indicates the first free byte to be written.
ULONG C; ///< Zero-based index of the consumer in the buffer. It indicates the first free byte to be read.
ULONG Free; ///< Number of the free bytes in the buffer
PUCHAR Buffer; ///< Pointer to the kernel buffer used to capture packets.
ULONG Accepted; ///< Number of packet that current capture instance acepted, from its opening. A packet
///< is accepted if it passes the filter and fits in the buffer. Accepted packets are the
///< ones that reach the application.
///< This number is related to the particular CPU this structure is referring to.
ULONG Received; ///< Number of packets received by current instance from its opening, i.e. number of
///< packet received by the network adapter since the beginning of the
///< capture/monitoring/dump session.
///< This number is related to the particular CPU this structure is referring to.
ULONG Dropped; ///< Number of packet that current instance had to drop, from its opening. A packet
///< is dropped if there is no more space to store it in the circular buffer that the
///< driver associates to current instance.
///< This number is related to the particular CPU this structure is referring to.
ULONG Processing; ///< Flag. If set to 1, it indicates that the tap is processing a packet on the CPU this structure is referring to.
PMDL TransferMdl1; ///< MDL used to map the portion of the buffer that will contain an incoming packet.
PMDL TransferMdl2; ///< Second MDL used to map the portion of the buffer that will contain an incoming packet.
ULONG NewP; ///< Used by NdisTransferData() (when we call NdisTransferData, p index must be updated only in the TransferDataComplete.
}
CpuPrivateData;
/*!
\brief Contains the state of a running instance of the NPF driver.
This is the most important structure of NPF: it is used by almost all the functions of the driver. An
_OPEN_INSTANCE structure is associated with every user-level session, allowing concurrent access
to the driver.
*/
typedef struct _OPEN_INSTANCE
{
PDEVICE_EXTENSION DeviceExtension; ///< Pointer to the _DEVICE_EXTENSION structure of the device on which
///< the instance is bound.
NDIS_HANDLE AdapterHandle; ///< NDIS idetifier of the adapter used by this instance.
UINT Medium; ///< Type of physical medium the underlying NDIS driver uses. See the
///< documentation of NdisOpenAdapter in the MS DDK for details.
NDIS_HANDLE PacketPool; ///< Pool of NDIS_PACKET structures used to transfer the packets from and to the NIC driver.
PIRP OpenCloseIrp; ///< Pointer used to store the open/close IRP requests and provide them to the
///< callbacks of NDIS.
KSPIN_LOCK RequestSpinLock; ///< SpinLock used to synchronize the OID requests.
LIST_ENTRY RequestList; ///< List of pending OID requests.
LIST_ENTRY ResetIrpList; ///< List of pending adapter reset requests.
INTERNAL_REQUEST Requests[MAX_REQUESTS]; ///< Array of structures that wrap every single OID request.
PMDL BufferMdl; ///< Pointer to a Memory descriptor list (MDL) that maps the circular buffer's memory.
PKEVENT ReadEvent; ///< Pointer to the event on which the read calls on this instance must wait.
HANDLE ReadEventHandle; ///< Handle of the event on which the read calls on this instance must wait.
UNICODE_STRING ReadEventName; ///< Name of the event on which the read calls on this instance must wait.
///< The event is created with a name, so it can be used at user level to know when it
///< is possible to access the driver without being blocked. This fiels stores the name
///< that and is used by the BIOCGEVNAME IOCTL call.
PUCHAR bpfprogram; ///< Pointer to the filtering pseudo-code associated with current instance of the driver.
///< This code is used only in particular situations (for example when the packet received
///< from the NIC driver is stored in two non-consecutive buffers. In normal situations
///< the filtering routine created by the JIT compiler and pointed by the next field
///< is used. See \ref NPF for details on the filtering process.
#ifdef __NPF_x86__
JIT_BPF_Filter *Filter; ///< Pointer to the native filtering function created by the jitter.
///< See BPF_jitter() for details.
#endif
UINT MinToCopy; ///< Minimum amount of data in the circular buffer that unlocks a read. Set with the
///< BIOCSMINTOCOPY IOCTL.
LARGE_INTEGER TimeOut; ///< Timeout after which a read is released, also if the amount of data in the buffer is
///< less than MinToCopy. Set with the BIOCSRTIMEOUT IOCTL.
int mode; ///< Working mode of the driver. See PacketSetMode() for details.
LARGE_INTEGER Nbytes; ///< Amount of bytes accepted by the filter when this instance is in statistical mode.
LARGE_INTEGER Npackets; ///< Number of packets accepted by the filter when this instance is in statistical mode.
NDIS_SPIN_LOCK CountersLock; ///< SpinLock that protects the statistical mode counters.
UINT Nwrites; ///< Number of times a single write must be physically repeated. See \ref NPF for an
///< explanation
ULONG Multiple_Write_Counter; ///< Counts the number of times a single write has already physically repeated.
NDIS_EVENT WriteEvent; ///< Event used to synchronize the multiple write process.
BOOLEAN WriteInProgress; ///< True if a write is currently in progress. NPF currently allows a single wite on
///< the same open instance.
NDIS_SPIN_LOCK WriteLock; ///< SpinLock that protects the WriteInProgress variable.
NDIS_EVENT IOEvent; ///< Event used to synchronize I/O requests with the callback structure of NDIS.
NDIS_STATUS IOStatus; ///< Maintains the status of and OID request call, that will be passed to the application.
BOOLEAN Bound; ///< Specifies if NPF is still bound to the adapter used by this instance. Bound can be
///< FALSE if a Plug and Play adapter has been removed or disabled by the user.
HANDLE DumpFileHandle; ///< Handle of the file used in dump mode.
PFILE_OBJECT DumpFileObject; ///< Pointer to the object of the file used in dump mode.
PKTHREAD DumpThreadObject; ///< Pointer to the object of the thread used in dump mode.
HANDLE DumpThreadHandle; ///< Handle of the thread created by dump mode to asynchronously move the buffer to disk.
NDIS_EVENT DumpEvent; ///< Event used to synchronize the dump thread with the tap when the instance is in dump mode.
LARGE_INTEGER DumpOffset; ///< Current offset in the dump file.
UNICODE_STRING DumpFileName; ///< String containing the name of the dump file.
UINT MaxDumpBytes; ///< Maximum dimension in bytes of the dump file. If the dump file reaches this size it
///< will be closed. A value of 0 means unlimited size.
UINT MaxDumpPacks; ///< Maximum number of packets that will be saved in the dump file. If this number of
///< packets is reached the dump will be closed. A value of 0 means unlimited number of
///< packets.
BOOLEAN DumpLimitReached; ///< TRUE if the maximum dimension of the dump file (MaxDumpBytes or MaxDumpPacks) is
///< reached.
MEM_TYPE mem_ex; ///< Memory used by the TME virtual co-processor
TME_CORE tme; ///< Data structure containing the virtualization of the TME co-processor
NDIS_SPIN_LOCK MachineLock; ///< SpinLock that protects the mem_ex buffer
UINT MaxFrameSize; ///< Maximum frame size that the underlying MAC acceptes. Used to perform a check on the
///< size of the frames sent with NPF_Write() or NPF_BufferedWrite().
CpuPrivateData CpuData[1024]; ///< Pool of kernel buffer structures, one for each CPU.
ULONG ReaderSN; ///< Sequence number of the next packet to be read from the pool of kernel buffers.
ULONG WriterSN; ///< Sequence number of the next packet to be written in the pool of kernel buffers.
///< These two sequence numbers are unique for each capture instance.
ULONG Size; ///< Size of each kernel buffer contained in the CpuData field.
ULONG SkipProcessing; ///< Flag. When set to 1, the tap discards each packet. It is set to 1 by the IOCTLs that modify
///< some "sensible" fields of the Open structure (e.g. they reallocate the pool of kernel buffers,
///< or change the filter program
BOOLEAN SkipSentPackets;
}
OPEN_INSTANCE, *POPEN_INSTANCE;
/*!
\brief Structure prepended to each packet in the kernel buffer pool.
Each packet in one of the kernel buffers is prepended by this header. It encapsulates the bpf_header,
which will be passed to user level programs, as well as the sequence number of the packet, set by the producer (the tap function),
and used by the consumer (the read function) to "reorder" the packets contained in the various kernel buffers.
*/
struct PacketHeader
{
ULONG SN; ///< Sequence number of the packet.
struct bpf_hdr header; ///< bpf header, created by the tap, and copied unmodified to user level programs.
};
extern UINT g_SendPacketFlags;
#define NDIS_FLAGS_SKIP_LOOPBACK_W2K 0x400 ///< This is an undocumented flag for NdisSetPacketFlags() that allows to disable loopback reception.
#define TRANSMIT_PACKETS 2048 ///< Maximum number of packets in the transmit packet pool. This value is an upper bound to the number
///< of packets that can be transmitted at the same time or with a single call to NdisSendPackets.
/// Macro used in the I/O routines to return the control to user-mode with a success status.
#define EXIT_SUCCESS(quantity) Irp->IoStatus.Information=quantity;\
Irp->IoStatus.Status = STATUS_SUCCESS;\
IoCompleteRequest(Irp, IO_NO_INCREMENT);\
return STATUS_SUCCESS;\
/// Macro used in the I/O routines to return the control to user-mode with a failure status.
#define EXIT_FAILURE(quantity) Irp->IoStatus.Information=quantity;\
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;\
IoCompleteRequest(Irp, IO_NO_INCREMENT);\
return STATUS_UNSUCCESSFUL;\
/**
* @}
*/
/***************************/
/* Prototypes */
/***************************/
/** @defgroup NPF_code NPF functions
* @{
*/
/*!
\brief The initialization routine of the driver.
\param DriverObject The driver object of NPF created by the system.
\param RegistryPath The registry path containing the keys related to the driver.
\return A string containing a list of network adapters.
DriverEntry is a mandatory function in a device driver. Like the main() of a user level program, it is called
by the system when the driver is loaded in memory and started. Its purpose is to initialize the driver,
performing all the allocations and the setup. In particular, DriverEntry registers all the driver's I/O
callbacks, creates the devices, defines NPF as a protocol inside NDIS.
*/
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
/*!
\brief Returns the list of the MACs available on the system.
\return A string containing a list of network adapters.
The list of adapters is retrieved from the
SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318} registry key.
NPF tries to create its bindings from this list. In this way it is possible to be loaded
and unloaded dynamically without passing from the control panel.
*/
PWCHAR getAdaptersList(VOID);
/*!
\brief Returns the MACs that bind to TCP/IP.
\return Pointer to the registry key containing the list of adapters on which TCP/IP is bound.
If getAdaptersList() fails, NPF tries to obtain the TCP/IP bindings through this function.
*/
PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings(VOID);
/*!
\brief Creates a device for a given MAC.
\param adriverObjectP The driver object that will be associated with the device, i.e. the one of NPF.
\param amacNameP The name of the network interface that the device will point.
\param aProtoHandle NDIS protocol handle of NPF.
\return If the function succeeds, the return value is nonzero.
NPF creates a device for every valid network adapter. The new device points to the NPF driver, but contains
information about the original device. In this way, when the user opens the new device, NPF will be able to
determine the correct adapter to use.
*/
BOOLEAN createDevice(
IN OUT PDRIVER_OBJECT adriverObjectP,
IN PUNICODE_STRING amacNameP,
NDIS_HANDLE aProtoHandle);
/*!
\brief Opens a new instance of the driver.
\param DeviceObject Pointer to the device object utilized by the user.
\param Irp Pointer to the IRP containing the user request.
\return The status of the operation. See ntstatus.h in the DDK.
This function is called by the OS when a new instance of the driver is opened, i.e. when a user application
performs a CreateFile on a device created by NPF. NPF_Open allocates and initializes variables, objects
and buffers needed by the new instance, fills the OPEN_INSTANCE structure associated with it and opens the
adapter with a call to NdisOpenAdapter.
*/
NTSTATUS
NPF_Open(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
/*!
\brief Ends the opening of an adapter.
\param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
\param Status Status of the opening operation performed by NDIS.
\param OpenErrorStatus not used by NPF.
Callback function associated with the NdisOpenAdapter() NDIS function. It is invoked by NDIS when the NIC
driver has finished an open operation that was previously started by NPF_Open().
*/
VOID
NPF_OpenAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus
);
/*!
\brief Closes an instance of the driver.
\param DeviceObject Pointer to the device object utilized by the user.
\param Irp Pointer to the IRP containing the user request.
\return The status of the operation. See ntstatus.h in the DDK.
This function is called when a running instance of the driver is closed by the user with a CloseHandle().
It stops the capture/monitoring/dump process, deallocates the memory and the objects associated with the
instance and closing the files. The network adapter is then closed with a call to NdisCloseAdapter.
*/
NTSTATUS
NPF_Close(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
/*!
\brief Ends the closing of an adapter.
\param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
\param Status Status of the close operation performed by NDIS.
Callback function associated with the NdisCloseAdapter() NDIS function. It is invoked by NDIS when the NIC
driver has finished a close operation that was previously started by NPF_Close().
*/
VOID
NPF_CloseAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
);
/*!
\brief Callback invoked by NDIS when a packet arrives from the network.
\param ProtocolBindingContext Context of the function. Points to a OPEN_INSTANCE structure that identifies
the NPF instance to which the packets are destined.
\param MacReceiveContext Handle that identifies the underlying NIC driver that generated the request.
This value must be used when the packet is transferred from the NIC driver with NdisTransferData().
\param HeaderBuffer Pointer to the buffer in the NIC driver memory that contains the header of the packet.
\param HeaderBufferSize Size in bytes of the header.
\param LookAheadBuffer Pointer to the buffer in the NIC driver's memory that contains the incoming packet's
data <b>available to NPF</b>. This value does not necessarily coincide with the actual size of the packet,
since only a portion can be available at this time. The remaining portion can be obtained with the
NdisTransferData() NDIS function.
\param LookaheadBufferSize Size in bytes of the lookahead buffer.
\param PacketSize Total size of the incoming packet, excluded the header.
\return The status of the operation. See ntstatus.h in the DDK.
NPF_tap() is called by the underlying NIC for every incoming packet. It is the most important and one of
the most complex functions of NPF: it executes the filter, runs the statistical engine (if the instance is in
statistical mode), gathers the timestamp, moves the packet in the buffer. NPF_tap() is the only function,
along with the filtering ones, that is executed for every incoming packet, therefore it is carefully
optimized.
*/
NDIS_STATUS
NPF_tap(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookaheadBufferSize,
IN UINT PacketSize
);
/*!
\brief Ends the transfer of a packet.
\param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
\param Packet Pointer to the NDIS_PACKET structure that received the packet data.
\param Status Status of the transfer operation.
\param BytesTransferred Amount of bytes transferred.
Callback function associated with the NdisTransferData() NDIS function. It is invoked by NDIS when the NIC
driver has finished the transfer of a packet from the NIC driver memory to the NPF circular buffer.
*/
VOID
NPF_TransferDataComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet,
IN NDIS_STATUS Status,
IN UINT BytesTransferred
);
/*!
\brief Callback function that signals the end of a packet reception.
\param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
does nothing in NPF
*/
VOID
NPF_ReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext);
/*!
\brief Handles the IOCTL calls.
\param DeviceObject Pointer to the device object utilized by the user.
\param Irp Pointer to the IRP containing the user request.
\return The status of the operation. See ntstatus.h in the DDK.
Once the packet capture driver is opened it can be configured from user-level applications with IOCTL commands
using the DeviceIoControl() system call. NPF_IoControl receives and serves all the IOCTL calls directed to NPF.
The following commands are recognized:
- #BIOCSETBUFFERSIZE
- #BIOCSETF
- #BIOCGSTATS
- #BIOCSRTIMEOUT
- #BIOCSMODE
- #BIOCSWRITEREP
- #BIOCSMINTOCOPY
- #BIOCSETOID
- #BIOCQUERYOID
- #BIOCSETDUMPFILENAME
- #BIOCGEVNAME
- #BIOCSENDPACKETSSYNC
- #BIOCSENDPACKETSNOSYNC
*/
NTSTATUS
NPF_IoControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
VOID
/*!
\brief Ends an OID request.
\param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
\param pRequest Pointer to the completed OID request.
\param Status Status of the operation.
Callback function associated with the NdisRequest() NDIS function. It is invoked by NDIS when the NIC
driver has finished an OID request operation that was previously started by NPF_IoControl().
*/
NPF_RequestComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_REQUEST pRequest,
IN NDIS_STATUS Status
);
/*!
\brief Writes a raw packet to the network.
\param DeviceObject Pointer to the device object on which the user wrote the packet.
\param Irp Pointer to the IRP containing the user request.
\return The status of the operation. See ntstatus.h in the DDK.
This function is called by the OS in consequence of user WriteFile() call, with the data of the packet that must
be sent on the net. The data is contained in the buffer associated with Irp, NPF_Write takes it and
delivers it to the NIC driver via the NdisSend() function. The Nwrites field of the OPEN_INSTANCE structure
associated with Irp indicates the number of copies of the packet that will be sent: more than one copy of the
packet can be sent for performance reasons.
*/
NTSTATUS
NPF_Write(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
/*!
\brief Writes a buffer of raw packets to the network.
\param Irp Pointer to the IRP containing the user request.
\param UserBuff Pointer to the buffer containing the packets to send.
\param UserBuffSize Size of the buffer with the packets.
\return The amount of bytes actually sent. If the return value is smaller than the Size parameter, an
error occurred during the send. The error can be caused by an adapter problem or by an
inconsistent/bogus user buffer.
This function is called by the OS in consequence of a BIOCSENDPACKETSNOSYNC or a BIOCSENDPACKETSSYNC IOCTL.
The buffer received as input parameter contains an arbitrary number of packets, each of which preceded by a
sf_pkthdr structure. NPF_BufferedWrite() scans the buffer and sends every packet via the NdisSend() function.
When Sync is set to TRUE, the packets are synchronized with the KeQueryPerformanceCounter() function.
This requires a remarkable amount of CPU, but allows to respect the timestamps associated with packets with a precision
of some microseconds (depending on the precision of the performance counter of the machine).
If Sync is false, the timestamps are ignored and the packets are sent as fat as possible.
*/
INT NPF_BufferedWrite(IN PIRP Irp,
IN PCHAR UserBuff,
IN ULONG UserBuffSize,
BOOLEAN sync);
/*!
\brief Waits the completion of all the sends performed by NPF_BufferedWrite.
\param Open Pointer to open context structure
Used by NPF_BufferedWrite to wait the completion of all the sends before returning the control to the user.
*/
VOID NPF_WaitEndOfBufferedWrite(POPEN_INSTANCE Open);
/*!
\brief Ends a send operation.
\param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
\param pRequest Pointer to the NDIS PACKET structure used by NPF_Write() to send the packet.
\param Status Status of the operation.
Callback function associated with the NdisSend() NDIS function. It is invoked by NDIS when the NIC
driver has finished an OID request operation that was previously started by NPF_Write().
*/
VOID
NPF_SendComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pPacket,
IN NDIS_STATUS Status
);
/*!
\brief Ends a reset of the adapter.
\param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
\param Status Status of the operation.
Callback function associated with the NdisReset() NDIS function. It is invoked by NDIS when the NIC
driver has finished an OID request operation that was previously started by NPF_IoControl(), in an IOCTL_PROTOCOL_RESET
command.
*/
VOID
NPF_ResetComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
);
/*!
\brief Callback for NDIS StatusHandler. Not used by NPF
*/
VOID
NPF_Status(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN PVOID StatusBuffer,
IN UINT StatusBufferSize
);
/*!
\brief Callback for NDIS StatusCompleteHandler. Not used by NPF
*/
VOID
NPF_StatusComplete(IN NDIS_HANDLE ProtocolBindingContext);
/*!
\brief Function called by the OS when NPF is unloaded.
\param DriverObject The driver object of NPF created by the system.
This is the last function executed when the driver is unloaded from the system. It frees global resources,
delete the devices and deregisters the protocol. The driver can be unloaded by the user stopping the NPF
service (from control panel or with a console 'net stop npf').
*/
VOID
NPF_Unload(IN PDRIVER_OBJECT DriverObject);
/*!
\brief Function that serves the user's reads.
\param DeviceObject Pointer to the device used by the user.
\param Irp Pointer to the IRP containing the user request.
\return The status of the operation. See ntstatus.h in the DDK.
This function is called by the OS in consequence of user ReadFile() call. It moves the data present in the
kernel buffer to the user buffer associated with Irp.
First of all, NPF_Read checks the amount of data in kernel buffer associated with current NPF instance.
- If the instance is in capture mode and the buffer contains more than OPEN_INSTANCE::MinToCopy bytes,
NPF_Read moves the data in the user buffer and returns immediatly. In this way, the read performed by the
user is not blocking.
- If the buffer contains less than MinToCopy bytes, the application's request isn't
satisfied immediately, but it's blocked until at least MinToCopy bytes arrive from the net
or the timeout on this read expires. The timeout is kept in the OPEN_INSTANCE::TimeOut field.
- If the instance is in statistical mode or in dump mode, the application's request is blocked until the
timeout kept in OPEN_INSTANCE::TimeOut expires.
*/
NTSTATUS
NPF_Read(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
/*!
\brief Reads the registry keys associated woth NPF if the driver is manually installed via the control panel.
Normally not used in recent versions of NPF.
*/
NTSTATUS
NPF_ReadRegistry(
IN PWSTR *MacDriverName,
IN PWSTR *PacketDriverName,
IN PUNICODE_STRING RegistryPath
);
/*!
\brief Function used by NPF_ReadRegistry() to quesry the registry keys associated woth NPF if the driver
is manually installed via the control panel.
Normally not used in recent versions of NPF.
*/
NTSTATUS
NPF_QueryRegistryRoutine(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
);
/*!
\brief Callback for NDIS BindAdapterHandler. Not used by NPF.
Function called by NDIS when a new adapter is installed on the machine With Plug and Play.
*/
VOID NPF_BindAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING DeviceName,
IN PVOID SystemSpecific1,
IN PVOID SystemSpecific2
);
/*!
\brief Callback for NDIS UnbindAdapterHandler.
\param Status out variable filled by NPF_UnbindAdapter with the status of the unbind operation.
\param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with current instance.
\param UnbindContext Specifies a handle, supplied by NDIS, that NPF can use to complete the opration.
Function called by NDIS when a new adapter is removed from the machine without shutting it down.
NPF_UnbindAdapter closes the adapter calling NdisCloseAdapter() and frees the memory and the structures
associated with it. It also releases the waiting user-level app and closes the dump thread if the instance
is in dump mode.
*/
VOID
NPF_UnbindAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE UnbindContext
);
/*!
\brief Creates the file that will receive the packets when the driver is in dump mode.
\param Open The NPF instance that opens the file.
\param fileName Pointer to a UNICODE string containing the name of the file.
\param append Boolean value that specifies if the data must be appended to the file.
\return The status of the operation. See ntstatus.h in the DDK.
*/
NTSTATUS NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN append);
/*!
\brief Starts dump to file.
\param Open The NPF instance that opens the file.
\return The status of the operation. See ntstatus.h in the DDK.
This function performs two operations. First, it writes the libpcap header at the beginning of the file.
Second, it starts the thread that asynchronously dumps the network data to the file.
*/
NTSTATUS NPF_StartDump(POPEN_INSTANCE Open);
/*!
\brief The dump thread.
\param Open The NPF instance that creates the thread.
This function moves the content of the NPF kernel buffer to file. It runs in the user context, so at lower
priority than the TAP.
*/
VOID NPF_DumpThread(PVOID Open);
/*!
\brief Saves the content of the packet buffer to the file associated with current instance.
\param Open The NPF instance that creates the thread.
Used by NPF_DumpThread() and NPF_CloseDumpFile().
*/
NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open);
/*!
\brief Writes a block of packets on the dump file.
\param FileObject The file object that will receive the packets.
\param Offset The offset in the file where the packets will be put.
\param Length The amount of bytes to write.
\param Mdl MDL mapping the memory buffer that will be written to disk.
\param IoStatusBlock Used by the function to return the status of the operation.
\return The status of the operation. See ntstatus.h in the DDK.
NPF_WriteDumpFile addresses directly the file system, creating a custom IRP and using it to send a portion
of the NPF circular buffer to disk. This function is used by NPF_DumpThread().
*/
VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject,
PLARGE_INTEGER Offset,
ULONG Length,
PMDL Mdl,
PIO_STATUS_BLOCK IoStatusBlock);
/*!
\brief Closes the dump file associated with an instance of the driver.
\param Open The NPF instance that closes the file.
\return The status of the operation. See ntstatus.h in the DDK.
*/
NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open);
/*!
\brief Returns the amount of bytes present in the packet buffer.
\param Open The NPF instance that closes the file.
*/
UINT GetBuffOccupation(POPEN_INSTANCE Open);
/*!
\brief Called by NDIS to notify us of a PNP event. The most significant one for us is power state change.
\param ProtocolBindingContext Pointer to open context structure. This is NULL for global reconfig
events.
\param pNetPnPEvent Pointer to the PnP event
If there is a power state change, the driver is forced to resynchronize the global timer.
This hopefully avoids the synchronization issues caused by hibernation or standby.
This function is excluded from the NT4 driver, where PnP is not supported
*/
#ifdef NDIS50
NDIS_STATUS NPF_PowerChange(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent);
#endif
/**
* @}
*/
/**
* @}
*/
#endif /*main ifndef/define*/
|