This repo is obsolete, please see git://git.code.sf.net/p/dummynet/code@master
[ipfw.git] / dummynet2 / passthru.c
1 /*++
2
3 Copyright (c) 1992-2000  Microsoft Corporation
4  
5 Module Name:
6  
7     passthru.c
8
9 Abstract:
10
11     Ndis Intermediate Miniport driver sample. This is a passthru driver.
12
13 Author:
14
15 Environment:
16
17
18 Revision History:
19
20
21 --*/
22
23
24 #include "precomp.h"
25 #pragma hdrstop
26
27 #pragma NDIS_INIT_FUNCTION(DriverEntry)
28
29 NDIS_HANDLE         ProtHandle = NULL;
30 NDIS_HANDLE         DriverHandle = NULL;
31 NDIS_MEDIUM         MediumArray[4] =
32                     {
33                         NdisMedium802_3,    // Ethernet
34                         NdisMedium802_5,    // Token-ring
35                         NdisMediumFddi,     // Fddi
36                         NdisMediumWan       // NDISWAN
37                     };
38
39 NDIS_SPIN_LOCK     GlobalLock;
40
41 PADAPT             pAdaptList = NULL;
42 LONG               MiniportCount = 0;
43
44 NDIS_HANDLE        NdisWrapperHandle;
45
46 //
47 // To support ioctls from user-mode:
48 //
49
50 #define STR2(x) #x
51 #define STR(x) STR2(x)
52 #define DOSPREFIX "\\DosDevices\\"
53 #define NTPREFIX "\\Device\\"
54 #define WIDEN2(x) L ## x
55 #define WIDEN(x) WIDEN2(x)
56 #define LINKNAME_STRING                 WIDEN(DOSPREFIX) WIDEN(STR(MODULENAME))
57 #define NTDEVICE_STRING                 WIDEN(NTPREFIX) WIDEN(STR(MODULENAME))
58 #define PROTOCOLNAME_STRING             WIDEN(STR(MODULENAME))
59
60 NDIS_HANDLE     NdisDeviceHandle = NULL;
61 PDEVICE_OBJECT  ControlDeviceObject = NULL;
62
63 enum _DEVICE_STATE
64 {
65     PS_DEVICE_STATE_READY = 0,    // ready for create/delete
66     PS_DEVICE_STATE_CREATING,    // create operation in progress
67     PS_DEVICE_STATE_DELETING    // delete operation in progress
68 } ControlDeviceState = PS_DEVICE_STATE_READY;
69
70
71
72 NTSTATUS
73 DriverEntry(
74     IN PDRIVER_OBJECT        DriverObject,
75     IN PUNICODE_STRING       RegistryPath
76     )
77 /*++
78
79 Routine Description:
80
81     First entry point to be called, when this driver is loaded.
82     Register with NDIS as an intermediate driver.
83
84 Arguments:
85
86     DriverObject - pointer to the system's driver object structure
87         for this driver
88     
89     RegistryPath - system's registry path for this driver
90     
91 Return Value:
92
93     STATUS_SUCCESS if all initialization is successful, STATUS_XXX
94     error code if not.
95
96 --*/
97 {
98     NDIS_STATUS                        Status;
99     NDIS_PROTOCOL_CHARACTERISTICS      PChars;
100     NDIS_MINIPORT_CHARACTERISTICS      MChars;
101     NDIS_STRING                        Name;
102
103     Status = NDIS_STATUS_SUCCESS;
104     NdisAllocateSpinLock(&GlobalLock);
105
106     NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);
107
108     do
109     {
110         //
111         // Register the miniport with NDIS. Note that it is the miniport
112         // which was started as a driver and not the protocol. Also the miniport
113         // must be registered prior to the protocol since the protocol's BindAdapter
114         // handler can be initiated anytime and when it is, it must be ready to
115         // start driver instances.
116         //
117
118         NdisZeroMemory(&MChars, sizeof(NDIS_MINIPORT_CHARACTERISTICS));
119
120         MChars.MajorNdisVersion = PASSTHRU_MAJOR_NDIS_VERSION;
121         MChars.MinorNdisVersion = PASSTHRU_MINOR_NDIS_VERSION;
122
123         MChars.InitializeHandler = MPInitialize;
124         MChars.QueryInformationHandler = MPQueryInformation;
125         MChars.SetInformationHandler = MPSetInformation;
126         MChars.ResetHandler = NULL;
127         MChars.TransferDataHandler = MPTransferData;
128         MChars.HaltHandler = MPHalt;
129 #ifdef NDIS51_MINIPORT
130         MChars.CancelSendPacketsHandler = MPCancelSendPackets;
131         MChars.PnPEventNotifyHandler = MPDevicePnPEvent;
132         MChars.AdapterShutdownHandler = MPAdapterShutdown;
133 #endif // NDIS51_MINIPORT
134
135         //
136         // We will disable the check for hang timeout so we do not
137         // need a check for hang handler!
138         //
139         MChars.CheckForHangHandler = NULL;
140         MChars.ReturnPacketHandler = MPReturnPacket;
141
142         //
143         // Either the Send or the SendPackets handler should be specified.
144         // If SendPackets handler is specified, SendHandler is ignored
145         //
146         MChars.SendHandler = MPSend;    // IPFW: use MPSend, not SendPackets
147         MChars.SendPacketsHandler = NULL;
148
149         Status = NdisIMRegisterLayeredMiniport(NdisWrapperHandle,
150                                                   &MChars,
151                                                   sizeof(MChars),
152                                                   &DriverHandle);
153         if (Status != NDIS_STATUS_SUCCESS)
154         {
155             break;
156         }
157
158 #ifndef WIN9X
159         NdisMRegisterUnloadHandler(NdisWrapperHandle, PtUnload);
160 #endif
161
162         //
163         // Now register the protocol.
164         //
165         NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
166         PChars.MajorNdisVersion = PASSTHRU_PROT_MAJOR_NDIS_VERSION;
167         PChars.MinorNdisVersion = PASSTHRU_PROT_MINOR_NDIS_VERSION;
168
169         //
170         // Make sure the protocol-name matches the service-name
171         // (from the INF) under which this protocol is installed.
172         // This is needed to ensure that NDIS can correctly determine
173         // the binding and call us to bind to miniports below.
174         //
175         NdisInitUnicodeString(&Name, PROTOCOLNAME_STRING);    // Protocol name
176         PChars.Name = Name;
177         PChars.OpenAdapterCompleteHandler = PtOpenAdapterComplete;
178         PChars.CloseAdapterCompleteHandler = PtCloseAdapterComplete;
179         PChars.SendCompleteHandler = PtSendComplete;
180         PChars.TransferDataCompleteHandler = PtTransferDataComplete;
181     
182         PChars.ResetCompleteHandler = PtResetComplete;
183         PChars.RequestCompleteHandler = PtRequestComplete;
184         PChars.ReceiveHandler = PtReceive;
185         PChars.ReceiveCompleteHandler = PtReceiveComplete;
186         PChars.StatusHandler = PtStatus;
187         PChars.StatusCompleteHandler = PtStatusComplete;
188         PChars.BindAdapterHandler = PtBindAdapter;
189         PChars.UnbindAdapterHandler = PtUnbindAdapter;
190         PChars.UnloadHandler = PtUnloadProtocol;
191
192         PChars.ReceivePacketHandler = PtReceivePacket;
193         PChars.PnPEventHandler= PtPNPHandler;
194
195         NdisRegisterProtocol(&Status,
196                              &ProtHandle,
197                              &PChars,
198                              sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
199
200         if (Status != NDIS_STATUS_SUCCESS)
201         {
202             NdisIMDeregisterLayeredMiniport(DriverHandle);
203             break;
204         }
205
206         NdisIMAssociateMiniport(DriverHandle, ProtHandle);
207     }
208     while (FALSE);
209
210     if (Status != NDIS_STATUS_SUCCESS)
211     {
212         NdisTerminateWrapper(NdisWrapperHandle, NULL);
213     }
214         
215     ipfw_module_init(); // IPFW - start the system
216
217     return(Status);
218 }
219
220
221 NDIS_STATUS
222 PtRegisterDevice(
223     VOID
224     )
225 /*++
226
227 Routine Description:
228
229     Register an ioctl interface - a device object to be used for this
230     purpose is created by NDIS when we call NdisMRegisterDevice.
231
232     This routine is called whenever a new miniport instance is
233     initialized. However, we only create one global device object,
234     when the first miniport instance is initialized. This routine
235     handles potential race conditions with PtDeregisterDevice via
236     the ControlDeviceState and MiniportCount variables.
237
238     NOTE: do not call this from DriverEntry; it will prevent the driver
239     from being unloaded (e.g. on uninstall).
240
241 Arguments:
242
243     None
244
245 Return Value:
246
247     NDIS_STATUS_SUCCESS if we successfully register a device object.
248
249 --*/
250 {
251     NDIS_STATUS            Status = NDIS_STATUS_SUCCESS;
252     UNICODE_STRING         DeviceName;
253     UNICODE_STRING         DeviceLinkUnicodeString;
254     PDRIVER_DISPATCH       DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
255
256     DBGPRINT(("==>PtRegisterDevice\n"));
257
258     NdisAcquireSpinLock(&GlobalLock);
259
260     ++MiniportCount;
261     
262     if (1 == MiniportCount)
263     {
264         ASSERT(ControlDeviceState != PS_DEVICE_STATE_CREATING);
265
266         //
267         // Another thread could be running PtDeregisterDevice on
268         // behalf of another miniport instance. If so, wait for
269         // it to exit.
270         //
271         while (ControlDeviceState != PS_DEVICE_STATE_READY)
272         {
273             NdisReleaseSpinLock(&GlobalLock);
274             NdisMSleep(1);
275             NdisAcquireSpinLock(&GlobalLock);
276         }
277
278         ControlDeviceState = PS_DEVICE_STATE_CREATING;
279
280         NdisReleaseSpinLock(&GlobalLock);
281
282     
283         NdisZeroMemory(DispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH));
284
285         DispatchTable[IRP_MJ_CREATE] = PtDispatch;
286         DispatchTable[IRP_MJ_CLEANUP] = PtDispatch;
287         DispatchTable[IRP_MJ_CLOSE] = PtDispatch;
288         // IPFW we use DevIoControl ?
289         DispatchTable[IRP_MJ_DEVICE_CONTROL] = DevIoControl;
290         
291
292         NdisInitUnicodeString(&DeviceName, NTDEVICE_STRING);
293         NdisInitUnicodeString(&DeviceLinkUnicodeString, LINKNAME_STRING);
294
295         //
296         // Create a device object and register our dispatch handlers
297         //
298         
299         Status = NdisMRegisterDevice(
300                     NdisWrapperHandle, 
301                     &DeviceName,
302                     &DeviceLinkUnicodeString,
303                     &DispatchTable[0],
304                     &ControlDeviceObject,
305                     &NdisDeviceHandle
306                     );
307
308         NdisAcquireSpinLock(&GlobalLock);
309
310         ControlDeviceState = PS_DEVICE_STATE_READY;
311     }
312
313     NdisReleaseSpinLock(&GlobalLock);
314
315     DBGPRINT(("<==PtRegisterDevice: %x\n", Status));
316
317     return (Status);
318 }
319
320
321 NTSTATUS
322 PtDispatch(
323     IN PDEVICE_OBJECT    DeviceObject,
324     IN PIRP              Irp
325     )
326 /*++
327 Routine Description:
328
329     Process IRPs sent to this device.
330
331 Arguments:
332
333     DeviceObject - pointer to a device object
334     Irp      - pointer to an I/O Request Packet
335
336 Return Value:
337
338     NTSTATUS - STATUS_SUCCESS always - change this when adding
339     real code to handle ioctls.
340
341 --*/
342 {
343     PIO_STACK_LOCATION  irpStack;
344     NTSTATUS            status = STATUS_SUCCESS;
345
346     UNREFERENCED_PARAMETER(DeviceObject);
347     
348     DBGPRINT(("==>Pt Dispatch\n"));
349     irpStack = IoGetCurrentIrpStackLocation(Irp);
350       
351
352     switch (irpStack->MajorFunction)
353     {
354         case IRP_MJ_CREATE:
355             break;
356             
357         case IRP_MJ_CLEANUP:
358             break;
359             
360         case IRP_MJ_CLOSE:
361             break;        
362                     
363                 case IRP_MJ_DEVICE_CONTROL:
364             //
365             // Add code here to handle ioctl commands sent to passthru.
366             //
367                         break;
368         default:
369             break;
370     }
371
372     Irp->IoStatus.Status = status;
373     IoCompleteRequest(Irp, IO_NO_INCREMENT);
374
375     DBGPRINT(("<== Pt Dispatch\n"));
376
377     return status;
378
379
380
381
382 NDIS_STATUS
383 PtDeregisterDevice(
384     VOID
385     )
386 /*++
387
388 Routine Description:
389
390     Deregister the ioctl interface. This is called whenever a miniport
391     instance is halted. When the last miniport instance is halted, we
392     request NDIS to delete the device object
393
394 Arguments:
395
396     NdisDeviceHandle - Handle returned by NdisMRegisterDevice
397
398 Return Value:
399
400     NDIS_STATUS_SUCCESS if everything worked ok
401
402 --*/
403 {
404     NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
405
406     DBGPRINT(("==>PassthruDeregisterDevice\n"));
407
408     NdisAcquireSpinLock(&GlobalLock);
409
410     ASSERT(MiniportCount > 0);
411
412     --MiniportCount;
413     
414     if (0 == MiniportCount)
415     {
416         //
417         // All miniport instances have been halted. Deregister
418         // the control device.
419         //
420
421         ASSERT(ControlDeviceState == PS_DEVICE_STATE_READY);
422
423         //
424         // Block PtRegisterDevice() while we release the control
425         // device lock and deregister the device.
426         // 
427         ControlDeviceState = PS_DEVICE_STATE_DELETING;
428
429         NdisReleaseSpinLock(&GlobalLock);
430
431         if (NdisDeviceHandle != NULL)
432         {
433             Status = NdisMDeregisterDevice(NdisDeviceHandle);
434             NdisDeviceHandle = NULL;
435         }
436
437         NdisAcquireSpinLock(&GlobalLock);
438         ControlDeviceState = PS_DEVICE_STATE_READY;
439     }
440
441     NdisReleaseSpinLock(&GlobalLock);
442
443     DBGPRINT(("<== PassthruDeregisterDevice: %x\n", Status));
444     return Status;
445     
446 }
447
448 VOID
449 PtUnload(
450     IN PDRIVER_OBJECT        DriverObject
451     )
452 //
453 // PassThru driver unload function
454 //
455 {
456     UNREFERENCED_PARAMETER(DriverObject);
457     
458     DBGPRINT(("PtUnload: entered\n"));   
459     
460     PtUnloadProtocol();
461     
462     NdisIMDeregisterLayeredMiniport(DriverHandle);
463     
464     NdisFreeSpinLock(&GlobalLock);
465         
466     ipfw_module_exit(); // IPFW unloading dummynet
467
468     DBGPRINT(("PtUnload: done!\n"));
469 }