Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

443 lines
9.8 KiB

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