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