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.

614 lines
17 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. nbfpnp.c
  5. Abstract:
  6. This module contains code which allocates and initializes all data
  7. structures needed to activate a plug and play binding. It also informs
  8. tdi (and thus nbf clients) of new devices and protocol addresses.
  9. Author:
  10. Jim McNelis (jimmcn) 1-Jan-1996
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #ifdef RASAUTODIAL
  18. LONG NumberOfBinds = 0;
  19. VOID
  20. NbfAcdBind();
  21. VOID
  22. NbfAcdUnbind();
  23. #endif // RASAUTODIAL
  24. // PnP-Power Declarations
  25. VOID
  26. NbfPnPEventDispatch(
  27. IN PVOID NetPnPEvent
  28. );
  29. VOID
  30. NbfPnPEventComplete(
  31. IN PNET_PNP_EVENT NetPnPEvent,
  32. IN NTSTATUS retVal
  33. );
  34. NTSTATUS
  35. NbfPnPBindsComplete(
  36. IN PDEVICE_CONTEXT DeviceContext,
  37. IN PNET_PNP_EVENT NetPnPEvent
  38. );
  39. // PnP Handler Routines
  40. VOID
  41. NbfProtocolBindAdapter(
  42. OUT PNDIS_STATUS NdisStatus,
  43. IN NDIS_HANDLE BindContext,
  44. IN PNDIS_STRING DeviceName,
  45. IN PVOID SystemSpecific1,
  46. IN PVOID SystemSpecific2
  47. )
  48. /*++
  49. Routine Description:
  50. This routine activates a transport binding and exposes the new device
  51. and associated addresses to transport clients. This is done by reading
  52. the registry, and performing any one time initialization of the transport
  53. and then natching the device to bind to with the linkage information from
  54. the registry. If we have a match for that device the bind will be
  55. performed.
  56. Arguments:
  57. NdisStatus - The status of the bind.
  58. BindContext - A context used for NdisCompleteBindAdapter() if
  59. STATUS_PENDING is returned.
  60. DeviceName - The name of the device that we are binding with.
  61. SystemSpecific1 - Unused (a pointer to an NDIS_STRING to use with
  62. NdisOpenProtocolConfiguration. This is not used by nbf
  63. since there is no adapter specific information when
  64. configuring the protocol via the registry. Passed to
  65. NbfInitializeOneDeviceContext for possible future use)
  66. SystemSpecific2 - Passed to NbfInitializeOneDeviceContext to be used
  67. in a call to TdiRegisterNetAddress
  68. Return Value:
  69. None.
  70. --*/
  71. {
  72. PUNICODE_STRING ExportName;
  73. UNICODE_STRING ExportString;
  74. ULONG i, j, k;
  75. NTSTATUS status;
  76. #if DBG
  77. // We can never be called at DISPATCH or above
  78. if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
  79. {
  80. DbgBreakPoint();
  81. }
  82. #endif
  83. IF_NBFDBG (NBF_DEBUG_PNP) {
  84. NbfPrint1 ("ENTER NbfProtocolBindAdapter for %S\n", DeviceName->Buffer);
  85. }
  86. if (NbfConfig == NULL) {
  87. //
  88. // This allocates the CONFIG_DATA structure and returns
  89. // it in NbfConfig.
  90. //
  91. status = NbfConfigureTransport(&NbfRegistryPath, &NbfConfig);
  92. if (!NT_SUCCESS (status)) {
  93. PANIC (" Failed to initialize transport, Nbf binding failed.\n");
  94. *NdisStatus = NDIS_STATUS_RESOURCES;
  95. return;
  96. }
  97. #if DBG
  98. //
  99. // Allocate the debugging tables.
  100. //
  101. NbfConnectionTable = (PVOID *)ExAllocatePoolWithTag(NonPagedPool,
  102. sizeof(PVOID) *
  103. (NbfConfig->InitConnections + 2 +
  104. NbfConfig->InitRequests + 2 +
  105. NbfConfig->InitUIFrames + 2 +
  106. NbfConfig->InitPackets + 2 +
  107. NbfConfig->InitLinks + 2 +
  108. NbfConfig->InitAddressFiles + 2 +
  109. NbfConfig->InitAddresses + 2),
  110. NBF_MEM_TAG_CONNECTION_TABLE);
  111. ASSERT (NbfConnectionTable);
  112. NbfRequestTable = NbfConnectionTable + (NbfConfig->InitConnections + 2);
  113. NbfUiFrameTable = NbfRequestTable + (NbfConfig->InitRequests + 2);
  114. NbfSendPacketTable = NbfUiFrameTable + (NbfConfig->InitUIFrames + 2);
  115. NbfLinkTable = NbfSendPacketTable + (NbfConfig->InitPackets + 2);
  116. NbfAddressFileTable = NbfLinkTable + (NbfConfig->InitLinks + 2);
  117. NbfAddressTable = NbfAddressFileTable +
  118. (NbfConfig->InitAddressFiles + 2);
  119. #endif
  120. }
  121. //
  122. // Loop through all the adapters that are in the configuration
  123. // information structure (this is the initial cache) until we
  124. // find the one that NDIS is calling Protocol bind adapter for.
  125. //
  126. for (j = 0; j < NbfConfig->NumAdapters; j++ ) {
  127. if (NdisEqualString(DeviceName, &NbfConfig->Names[j], TRUE)) {
  128. break;
  129. }
  130. }
  131. if (j < NbfConfig->NumAdapters) {
  132. // We found the bind to export mapping in initial cache
  133. ExportName = &NbfConfig->Names[NbfConfig->DevicesOffset + j];
  134. }
  135. else {
  136. IF_NBFDBG (NBF_DEBUG_PNP) {
  137. NbfPrint1("\nNot In Initial Cache = %08x\n\n", DeviceName->Buffer);
  138. NbfPrint0("Bind Names in Initial Cache: \n");
  139. for (k = 0; k < NbfConfig->NumAdapters; k++)
  140. {
  141. NbfPrint3("Config[%2d]: @ %08x, %75S\n",
  142. k, &NbfConfig->Names[k],
  143. NbfConfig->Names[k].Buffer);
  144. }
  145. NbfPrint0("Export Names in Initial Cache: \n");
  146. for (k = 0; k < NbfConfig->NumAdapters; k++)
  147. {
  148. NbfPrint3("Config[%2d]: @ %08x, %75S\n",
  149. k, &NbfConfig->Names[NbfConfig->DevicesOffset + k],
  150. NbfConfig->Names[NbfConfig->DevicesOffset + k].Buffer);
  151. }
  152. NbfPrint0("\n\n");
  153. }
  154. ExportName = &ExportString;
  155. //
  156. // We have not found the name in the initial registry info;
  157. // Read the registry and check if a new binding appeared...
  158. //
  159. *NdisStatus = NbfGetExportNameFromRegistry(&NbfRegistryPath,
  160. DeviceName,
  161. ExportName
  162. );
  163. if (!NT_SUCCESS (*NdisStatus))
  164. {
  165. return;
  166. }
  167. }
  168. NbfInitializeOneDeviceContext(NdisStatus,
  169. NbfDriverObject,
  170. NbfConfig,
  171. DeviceName,
  172. ExportName,
  173. SystemSpecific1,
  174. SystemSpecific2
  175. );
  176. // Check if we need to de-allocate the ExportName buffer
  177. if (ExportName == &ExportString)
  178. {
  179. ExFreePool(ExportName->Buffer);
  180. }
  181. if (*NdisStatus == NDIS_STATUS_SUCCESS) {
  182. if (InterlockedIncrement(&NumberOfBinds) == 1) {
  183. #ifdef RASAUTODIAL
  184. //
  185. // This is the first successful open.
  186. //
  187. #if DBG
  188. DbgPrint("Calling NbfAcdBind()\n");
  189. #endif
  190. //
  191. // Get the automatic connection driver entry points.
  192. //
  193. NbfAcdBind();
  194. #endif // RASAUTODIAL
  195. }
  196. }
  197. IF_NBFDBG (NBF_DEBUG_PNP) {
  198. NbfPrint2 ("LEAVE NbfProtocolBindAdapter for %S with Status %08x\n",
  199. DeviceName->Buffer, *NdisStatus);
  200. }
  201. return;
  202. }
  203. VOID
  204. NbfProtocolUnbindAdapter(
  205. OUT PNDIS_STATUS NdisStatus,
  206. IN NDIS_HANDLE ProtocolBindContext,
  207. IN PNDIS_HANDLE UnbindContext
  208. )
  209. /*++
  210. Routine Description:
  211. This routine deactivates a transport binding. Before it does this, it
  212. indicates to all clients above, that the device is going away. Clients
  213. are expected to close all open handles to the device.
  214. Then the device is pulled out of the list of NBF devices, and all
  215. resources reclaimed. Any connections, address files etc, that the
  216. client has cleaned up are forcibly cleaned out at this point. Any
  217. outstanding requests are completed (with a status). Any future
  218. requests are automatically invalid as they use obsolete handles.
  219. Arguments:
  220. NdisStatus - The status of the bind.
  221. ProtocolBindContext - the context from the openadapter call
  222. UnbindContext - A context for async unbinds.
  223. Return Value:
  224. None.
  225. --*/
  226. {
  227. PDEVICE_CONTEXT DeviceContext;
  228. PTP_ADDRESS Address;
  229. NTSTATUS status;
  230. KIRQL oldirql;
  231. PLIST_ENTRY p;
  232. #if DBG
  233. // We can never be called at DISPATCH or above
  234. if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
  235. {
  236. DbgBreakPoint();
  237. }
  238. #endif
  239. // Get the device context for the adapter being unbound
  240. DeviceContext = (PDEVICE_CONTEXT) ProtocolBindContext;
  241. IF_NBFDBG (NBF_DEBUG_PNP) {
  242. NbfPrint1 ("ENTER NbfProtocolUnbindAdapter for %S\n", DeviceContext->DeviceName);
  243. }
  244. // Remove creation ref if it has not already been removed,
  245. // after telling TDI and its clients that we'r going away.
  246. // This flag also helps prevent any more TDI indications
  247. // of deregister addr/devobj - after the 1st one succeeds.
  248. if (InterlockedExchange(&DeviceContext->CreateRefRemoved, TRUE) == FALSE) {
  249. // Assume upper layers clean up by closing connections
  250. // when we deregister all addresses and device object,
  251. // but this can happen asynchronously, after we return
  252. // from the (asynchronous) TdiDeregister.. calls below
  253. // Inform TDI by deregistering the reserved netbios address
  254. *NdisStatus = TdiDeregisterNetAddress(DeviceContext->ReservedAddressHandle);
  255. if (!NT_SUCCESS (*NdisStatus)) {
  256. IF_NBFDBG (NBF_DEBUG_PNP) {
  257. NbfPrint1("No success deregistering this address,STATUS = %08X\n",*NdisStatus);
  258. }
  259. // this can never happen
  260. ASSERT(FALSE);
  261. // In case it happens, this allows a redo of the unbind
  262. DeviceContext->CreateRefRemoved = FALSE;
  263. return;
  264. }
  265. // Inform TDI (and its clients) that device is going away
  266. *NdisStatus = TdiDeregisterDeviceObject(DeviceContext->TdiDeviceHandle);
  267. if (!NT_SUCCESS (*NdisStatus)) {
  268. IF_NBFDBG (NBF_DEBUG_PNP) {
  269. NbfPrint1("No success deregistering device object,STATUS = %08X\n",*NdisStatus);
  270. }
  271. // This can never happen
  272. ASSERT(FALSE);
  273. // In case it happens, this allows a redo of the unbind
  274. DeviceContext->CreateRefRemoved = FALSE;
  275. return;
  276. }
  277. // Clear away the association with the underlying PDO object
  278. DeviceContext->PnPContext = NULL;
  279. // Stop all the internal timers - this'll clear timer refs
  280. NbfStopTimerSystem(DeviceContext);
  281. // Cleanup the Ndis Binding as it is not useful on return
  282. // from this function - do not try to use it after this
  283. NbfCloseNdis(DeviceContext);
  284. // BUG BUG -- probable race condition with timer callbacks
  285. // Do we wait for some time in case a timer func gets in ?
  286. // Removing creation reference means that once all handles
  287. // r closed,device will automatically be garbage-collected
  288. NbfDereferenceDeviceContext ("Unload", DeviceContext, DCREF_CREATION);
  289. if (InterlockedDecrement(&NumberOfBinds) == 0) {
  290. #ifdef RASAUTODIAL
  291. //
  292. // This is a successful close of last adapter
  293. //
  294. #if DBG
  295. DbgPrint("Calling NbfAcdUnbind()\n");
  296. #endif
  297. //
  298. // Unbind from the automatic connection driver.
  299. //
  300. NbfAcdUnbind();
  301. #endif // RASAUTODIAL
  302. }
  303. }
  304. else {
  305. // Ignore any duplicate Unbind Indications from NDIS layer
  306. *NdisStatus = NDIS_STATUS_SUCCESS;
  307. }
  308. IF_NBFDBG (NBF_DEBUG_PNP) {
  309. NbfPrint2 ("LEAVE NbfProtocolUnbindAdapter for %S with Status %08x\n",
  310. DeviceContext->DeviceName, *NdisStatus);
  311. }
  312. return;
  313. }
  314. NDIS_STATUS
  315. NbfProtocolPnPEventHandler(
  316. IN NDIS_HANDLE ProtocolBindContext,
  317. IN PNET_PNP_EVENT NetPnPEvent
  318. )
  319. /*++
  320. Routine Description:
  321. This routine queues a work item to invoke the actual PnP
  322. event dispatcher. This asyncronous mechanism is to allow
  323. NDIS to signal PnP events to other bindings in parallel.
  324. Arguments:
  325. ProtocolBindContext - the context from the openadapter call
  326. NetPnPEvent - kind of PnP event and its parameters
  327. Return Value:
  328. STATUS_PENDING (or) an error code
  329. --*/
  330. {
  331. PNET_PNP_EVENT_RESERVED NetPnPReserved;
  332. PWORK_QUEUE_ITEM PnPWorkItem;
  333. PnPWorkItem = (PWORK_QUEUE_ITEM)ExAllocatePoolWithTag(
  334. NonPagedPool,
  335. sizeof (WORK_QUEUE_ITEM),
  336. NBF_MEM_TAG_WORK_ITEM);
  337. if (PnPWorkItem == NULL)
  338. {
  339. return NDIS_STATUS_RESOURCES;
  340. }
  341. NetPnPReserved = (PNET_PNP_EVENT_RESERVED)NetPnPEvent->TransportReserved;
  342. NetPnPReserved->PnPWorkItem = PnPWorkItem;
  343. NetPnPReserved->DeviceContext = (PDEVICE_CONTEXT) ProtocolBindContext;
  344. ExInitializeWorkItem(
  345. PnPWorkItem,
  346. NbfPnPEventDispatch,
  347. NetPnPEvent);
  348. ExQueueWorkItem(PnPWorkItem, CriticalWorkQueue);
  349. return NDIS_STATUS_PENDING;
  350. }
  351. VOID
  352. NbfPnPEventDispatch(
  353. IN PVOID NetPnPEvent
  354. )
  355. /*++
  356. Routine Description:
  357. This routine dispatches all PnP events for the NBF transport.
  358. The event is dispatched to the proper PnP event handler, and
  359. the events are indicated to the transport clients using TDI.
  360. These PnP events can trigger state changes that affect the
  361. device behavior ( like transitioning to low power state ).
  362. Arguments:
  363. NetPnPEvent - kind of PnP event and its parameters
  364. Return Value:
  365. None
  366. --*/
  367. {
  368. PNET_PNP_EVENT_RESERVED NetPnPReserved;
  369. PDEVICE_CONTEXT DeviceContext;
  370. UNICODE_STRING DeviceString;
  371. PTDI_PNP_CONTEXT tdiPnPContext1;
  372. PTDI_PNP_CONTEXT tdiPnPContext2;
  373. NDIS_STATUS retVal;
  374. // Retrieve the transport information block in event
  375. NetPnPReserved = (PNET_PNP_EVENT_RESERVED)((PNET_PNP_EVENT)NetPnPEvent)->TransportReserved;
  376. // Free the memory allocated for this work item itself
  377. ExFreePool(NetPnPReserved->PnPWorkItem);
  378. // Get the device context for the adapter being unbound
  379. DeviceContext = NetPnPReserved->DeviceContext;
  380. // In case everything goes ok, we return an NDIS_SUCCESS
  381. retVal = STATUS_SUCCESS;
  382. // Dispatch the PnP Event to the appropriate PnP handler
  383. switch (((PNET_PNP_EVENT)NetPnPEvent)->NetEvent)
  384. {
  385. case NetEventReconfigure:
  386. case NetEventCancelRemoveDevice:
  387. case NetEventQueryRemoveDevice:
  388. case NetEventQueryPower:
  389. case NetEventSetPower:
  390. case NetEventPnPCapabilities:
  391. break;
  392. case NetEventBindsComplete:
  393. retVal = NbfPnPBindsComplete(DeviceContext, NetPnPEvent);
  394. break;
  395. default:
  396. ASSERT( FALSE );
  397. }
  398. if ( retVal == STATUS_SUCCESS )
  399. {
  400. if (DeviceContext != NULL)
  401. {
  402. RtlInitUnicodeString(&DeviceString, DeviceContext->DeviceName);
  403. tdiPnPContext1 = tdiPnPContext2 = NULL;
  404. // Notify our TDI clients about this PNP event
  405. retVal = TdiPnPPowerRequest(&DeviceString,
  406. NetPnPEvent,
  407. tdiPnPContext1,
  408. tdiPnPContext2,
  409. NbfPnPEventComplete);
  410. }
  411. }
  412. if (retVal != STATUS_PENDING)
  413. {
  414. NdisCompletePnPEvent(retVal, (NDIS_HANDLE)DeviceContext, NetPnPEvent);
  415. }
  416. }
  417. //
  418. // PnP Complete Handler
  419. //
  420. VOID
  421. NbfPnPEventComplete(
  422. IN PNET_PNP_EVENT NetPnPEvent,
  423. IN NTSTATUS retVal
  424. )
  425. {
  426. PNET_PNP_EVENT_RESERVED NetPnPReserved;
  427. PDEVICE_CONTEXT DeviceContext;
  428. // Retrieve the transport information block in event
  429. NetPnPReserved = (PNET_PNP_EVENT_RESERVED)NetPnPEvent->TransportReserved;
  430. // Get the device context for the adapter being unbound
  431. DeviceContext = NetPnPReserved->DeviceContext;
  432. NdisCompletePnPEvent(retVal, (NDIS_HANDLE)DeviceContext, NetPnPEvent);
  433. }
  434. //
  435. // PnP Handler Dispatches
  436. //
  437. NTSTATUS
  438. NbfPnPBindsComplete(
  439. IN PDEVICE_CONTEXT DeviceContext,
  440. IN PNET_PNP_EVENT NetPnPEvent
  441. )
  442. {
  443. NDIS_STATUS retVal;
  444. ASSERT(DeviceContext == NULL);
  445. retVal = TdiProviderReady(NbfProviderHandle);
  446. ASSERT(retVal == STATUS_SUCCESS);
  447. return retVal;
  448. }