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.

4375 lines
126 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. tdipnp.c
  5. Abstract:
  6. TDI routines for supporting PnP in transports and transport clients.
  7. Author:
  8. Henry Sanders (henrysa) Oct. 10, 1995
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. henrysa 10-10-95 created
  13. shreem 01-23-97 bug #33975
  14. adube 01-01-01 maintenance mode - windows xp
  15. Notes:
  16. Change from the previous approach:
  17. 1. Processing the TDI_REQUEST is done in a different function.
  18. 2. Requests can be queued while another thread is notifying its clients/providers
  19. 3. These are then dequeued by the and run on a different thread using CTE functions.
  20. --*/
  21. #include <ntddk.h>
  22. #include <ndis.h>
  23. #include <tdi.h>
  24. #include <tdikrnl.h>
  25. #include <cxport.h>
  26. #include <ndispnp.h>
  27. #include "tdipnp.h"
  28. #include "tdidebug.h"
  29. #ifdef DBG
  30. CHAR DbgMsgs[LOG_MSG_CNT][MAX_MSG_LEN];
  31. UINT First, Last;
  32. CTELock DbgLock;
  33. ULONG TdiDebugEx = TDI_DEBUG_ERROR;
  34. ULONG TdiMemLog =
  35. //LOG_NOTIFY |
  36. //LOG_REGISTER |
  37. //LOG_POWER |
  38. 0;
  39. ULONG TdiLogOutput = LOG_OUTPUT_BUFFER /*| LOG_OUTPUT_DEBUGGER*/;
  40. #endif
  41. KSPIN_LOCK TDIListLock;
  42. LIST_ENTRY PnpHandlerRequestList;
  43. LIST_ENTRY PnpHandlerProviderList;
  44. LIST_ENTRY PnpHandlerClientList;
  45. PTDI_OPEN_BLOCK OpenList = NULL;
  46. BOOLEAN PnpHandlerRequestInProgress;
  47. PETHREAD PnpHandlerRequestThread;
  48. UINT PrevRequestType = 0;
  49. ULONG ProvidersRegistered = 0;
  50. ULONG ProvidersReady = 0;
  51. ULONG EventScheduled = 0;
  52. // structure private to tdipnp.c. used to marshall parms to a CTE event
  53. typedef struct _TDI_EXEC_PARAMS {
  54. LIST_ENTRY Linkage;
  55. UINT Signature;
  56. PLIST_ENTRY ClientList;
  57. PLIST_ENTRY ProviderList;
  58. PLIST_ENTRY RequestList;
  59. TDI_SERIALIZED_REQUEST Request;
  60. PETHREAD *CurrentThread;
  61. CTEEvent *RequestCTEEvent;
  62. PBOOLEAN SerializeFlag;
  63. BOOLEAN ResetSerializeFlag;
  64. PVOID pCallersAddress;
  65. PVOID pCallersCaller;
  66. PETHREAD pCallerThread;
  67. } TDI_EXEC_PARAMS, *PTDI_EXEC_PARAMS;
  68. typedef struct {
  69. PVOID ExecParm;
  70. UINT Type;
  71. PVOID Element;
  72. PVOID Thread;
  73. } EXEC_PARM;
  74. // Keep a short list of current and last few requests that TDI has processed.
  75. // (Debug purposes only. Current request isn't store anyware during processing)
  76. #define EXEC_CNT 8
  77. EXEC_PARM TrackExecs[EXEC_CNT];
  78. int NextExec;
  79. EXEC_PARM TrackExecCompletes[EXEC_CNT];
  80. int NextExecComplete;
  81. CTEEvent BindEvent;
  82. CTEEvent AddressEvent;
  83. CTEEvent PnpHandlerEvent;
  84. PWSTR StrRegTdiBindList = L"Bind";
  85. PWSTR StrRegTdiLinkage = L"\\Linkage";
  86. PWSTR StrRegTdiBindingsBasicPath = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
  87. #define MAX_UNICODE_BUFLEN 256
  88. // private function prototypes
  89. NTSYSAPI NTSTATUS NTAPI
  90. NtClose(
  91. IN HANDLE Handle
  92. );
  93. NTSTATUS
  94. TdiExecuteRequest(
  95. CTEEvent *Event,
  96. PVOID pTdiExecParams
  97. );
  98. BOOLEAN
  99. TdipIsSzInMultiSzSafe (
  100. IN PCWSTR pszSearchString,
  101. IN PCWSTR pmsz);
  102. VOID
  103. TdipRemoveMultiSzFromSzArray (
  104. IN PWSTR pmszToRemove,
  105. IN OUT PWSTR* pszArray,
  106. IN ULONG ItemsInArray,
  107. OUT ULONG* pRemainingItems);
  108. VOID
  109. TdipRemoveMultiSzFromMultiSz (
  110. IN PCWSTR pmszToRemove,
  111. IN OUT PWSTR pmszToModify);
  112. NTSTATUS
  113. TdipAddMultiSzToMultiSz(
  114. IN PUNICODE_STRING pmszAdd,
  115. IN PCWSTR pmszModify,
  116. OUT PWSTR* ppmszOut);
  117. VOID
  118. TdipGetMultiSZList(
  119. PWSTR **ListPointer,
  120. PWSTR BaseKeyName,
  121. PUNICODE_STRING DeviceName,
  122. PWSTR Linkage,
  123. PWSTR ParameterKeyName,
  124. PUINT NumEntries
  125. );
  126. BOOLEAN
  127. TdipMultiSzStrStr(
  128. PWSTR *TdiClientBindingList,
  129. PUNICODE_STRING DeviceName
  130. );
  131. BOOLEAN
  132. TdipBuildProviderList(
  133. PTDI_NOTIFY_PNP_ELEMENT NotifyElement
  134. );
  135. PTDI_PROVIDER_RESOURCE
  136. LocateProviderContext(
  137. PUNICODE_STRING ProviderName
  138. );
  139. // end private protos
  140. #if DBG
  141. VOID
  142. TdipPrintMultiSz (
  143. IN PCWSTR pmsz);
  144. VOID
  145. TdiDumpAddress(
  146. IN PTA_ADDRESS Addr
  147. )
  148. {
  149. int j;
  150. TDI_DEBUG(ADDRESS, ("len %d ", Addr->AddressLength));
  151. if (Addr->AddressType == TDI_ADDRESS_TYPE_IP) {
  152. TDI_DEBUG(ADDRESS, ("IP %d.%d.%d.%d\n",
  153. Addr->Address[2],
  154. Addr->Address[3],
  155. Addr->Address[4],
  156. Addr->Address[5]));
  157. } else if (Addr->AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
  158. if (Addr->Address[2] == '\0') {
  159. TDI_DEBUG(ADDRESS, ("NETBIOS reserved %2x %2x %2x %2x %2x %2x\n",
  160. (ULONG)(Addr->Address[12]),
  161. (ULONG)(Addr->Address[13]),
  162. (ULONG)(Addr->Address[14]),
  163. (ULONG)(Addr->Address[15]),
  164. (ULONG)(Addr->Address[16]),
  165. (ULONG)(Addr->Address[17])));
  166. } else {
  167. TDI_DEBUG(ADDRESS, ("NETBIOS %.16s\n", Addr->Address+2));
  168. }
  169. } else {
  170. TDI_DEBUG(ADDRESS, ("type %d ", Addr->AddressType));
  171. for (j = 0; j < Addr->AddressLength; j++) {
  172. TDI_DEBUG(ADDRESS, ("%2x ", (ULONG)(Addr->Address[j])));
  173. }
  174. TDI_DEBUG(ADDRESS, ("\n"));
  175. }
  176. }
  177. #else
  178. #define TdiDumpAddress(d) (0)
  179. #define TdipPrintMultiSz(p)
  180. #endif
  181. NTSTATUS
  182. TdiNotifyPnpClientList (
  183. PLIST_ENTRY ListHead,
  184. PVOID Info,
  185. BOOLEAN Added
  186. )
  187. /*++
  188. Routine Description:
  189. Arguments:
  190. ListHead - Head of list to walk.
  191. Info - Information describing the provider that changed.
  192. Added - True if a provider was added, false otherwise
  193. Return Value:
  194. --*/
  195. {
  196. PLIST_ENTRY Current;
  197. PTDI_PROVIDER_COMMON ProviderCommon;
  198. PTDI_NOTIFY_PNP_ELEMENT NotifyPnpElement;
  199. PTDI_PROVIDER_RESOURCE Provider;
  200. NTSTATUS Status, ReturnStatus = STATUS_SUCCESS;
  201. BOOLEAN bStatus = FALSE;
  202. TDI_DEBUG(FUNCTION, ("++ TdiNotifyPnpClientList\n"));
  203. Current = ListHead->Flink;
  204. // The Info parameter is actually a pointer to a PROVIDER_COMMON
  205. // structure, so get back to that so that we can find out what kind of
  206. // provider this is.
  207. ProviderCommon = (PTDI_PROVIDER_COMMON)Info;
  208. Provider = CONTAINING_RECORD(
  209. ProviderCommon,
  210. TDI_PROVIDER_RESOURCE,
  211. Common
  212. );
  213. if (Provider->Common.Type == TDI_RESOURCE_DEVICE) {
  214. TDI_DEBUG(PROVIDERS, ("Got new (de)registration for device %wZ\n", &Provider->Specific.Device.DeviceName));
  215. } else if (Provider->Common.Type == TDI_RESOURCE_NET_ADDRESS) {
  216. TDI_DEBUG(PROVIDERS, ("Got new (de)registration for address "));
  217. TdiDumpAddress(&Provider->Specific.NetAddress.Address);
  218. }
  219. // Walk the input client list, and for every element in it
  220. // notify the client.
  221. while (Current != ListHead) {
  222. NotifyPnpElement = CONTAINING_RECORD(
  223. Current,
  224. TDI_NOTIFY_PNP_ELEMENT,
  225. Common.Linkage
  226. );
  227. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  228. Provider->Common.pNotifyElement = NotifyPnpElement; //Debugging info
  229. if (Provider->Common.Type == TDI_RESOURCE_DEVICE) {
  230. if (TDI_VERSION_ONE == NotifyPnpElement->TdiVersion) {
  231. if (Added) {
  232. if (NotifyPnpElement->Bind.BindHandler) {
  233. TDI_LOG(LOG_NOTIFY, ("V1 bind %wZ to %wZ\n",
  234. &Provider->Specific.Device.DeviceName,
  235. &NotifyPnpElement->ElementName));
  236. (*(NotifyPnpElement->Bind.BindHandler))(
  237. &Provider->Specific.Device.DeviceName
  238. );
  239. }
  240. } else {
  241. if (NotifyPnpElement->Bind.UnbindHandler) {
  242. TDI_LOG(LOG_NOTIFY, ("V1 unbind %wZ from %wZ\n",
  243. &Provider->Specific.Device.DeviceName,
  244. &NotifyPnpElement->ElementName));
  245. (*(NotifyPnpElement->Bind.UnbindHandler))(
  246. &Provider->Specific.Device.DeviceName
  247. );
  248. }
  249. }
  250. } else {
  251. if (NULL != NotifyPnpElement->BindingHandler) {
  252. // Remove any providers from the list that we are supposed
  253. // to ignore.
  254. //
  255. TdipRemoveMultiSzFromSzArray (
  256. NotifyPnpElement->ListofBindingsToIgnore,
  257. NotifyPnpElement->ListofProviders,
  258. NotifyPnpElement->NumberofEntries,
  259. &NotifyPnpElement->NumberofEntries);
  260. // This is a device object provider.
  261. // This must be a notify bind element.
  262. if (TdipMultiSzStrStr (
  263. NotifyPnpElement->ListofProviders,
  264. &Provider->Specific.Device.DeviceName
  265. )) {
  266. if (Added) {
  267. TDI_LOG(LOG_NOTIFY, ("Bind %wZ to %wZ\n",
  268. &Provider->Specific.Device.DeviceName,
  269. &NotifyPnpElement->ElementName));
  270. (*(NotifyPnpElement->BindingHandler))(
  271. TDI_PNP_OP_ADD,
  272. &Provider->Specific.Device.DeviceName,
  273. (PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
  274. );
  275. } else {
  276. TDI_LOG(LOG_NOTIFY, ("Unbind %wZ from %wZ\n",
  277. &Provider->Specific.Device.DeviceName,
  278. &NotifyPnpElement->ElementName));
  279. (*(NotifyPnpElement->BindingHandler))(
  280. TDI_PNP_OP_DEL,
  281. &Provider->Specific.Device.DeviceName,
  282. (PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
  283. );
  284. }
  285. } else {
  286. TDI_DEBUG(BIND, ("The Client %wZ wasnt interested in this Provider %wZ!\r\n",
  287. &NotifyPnpElement->ElementName, &Provider->Specific.Device.DeviceName));
  288. }
  289. }
  290. }
  291. } else if (Provider->Common.Type == TDI_RESOURCE_NET_ADDRESS) {
  292. // This is a notify net address element. If this is
  293. // an address coming in, call the add address handler,
  294. // otherwise call delete address handler.
  295. if (TDI_VERSION_ONE == NotifyPnpElement->TdiVersion) {
  296. if (Added && (NULL != NotifyPnpElement->AddressElement.AddHandler)) {
  297. TDI_LOG(LOG_NOTIFY, ("Add address v1 %wZ to %wZ\n",
  298. &Provider->DeviceName,
  299. &NotifyPnpElement->ElementName));
  300. (*(NotifyPnpElement->AddressElement.AddHandler))(
  301. &Provider->Specific.NetAddress.Address
  302. );
  303. } else if (NULL != NotifyPnpElement->AddressElement.DeleteHandler) {
  304. TDI_LOG(LOG_NOTIFY, ("Del address v1 %wZ from %wZ\n",
  305. &Provider->DeviceName,
  306. &NotifyPnpElement->ElementName));
  307. (*(NotifyPnpElement->AddressElement.DeleteHandler))(
  308. &Provider->Specific.NetAddress.Address
  309. );
  310. }
  311. } else {
  312. if (Added && (NULL != NotifyPnpElement->AddressElement.AddHandlerV2)) {
  313. TDI_LOG(LOG_NOTIFY, ("Add address %wZ to %wZ\n",
  314. &Provider->DeviceName,
  315. &NotifyPnpElement->ElementName));
  316. (*(NotifyPnpElement->AddressElement.AddHandlerV2))(
  317. &Provider->Specific.NetAddress.Address,
  318. &Provider->DeviceName,
  319. Provider->Context2
  320. );
  321. TDI_DEBUG(ADDRESS, ("Address Handler Called: ADD!\n"));
  322. } else if (NULL != NotifyPnpElement->AddressElement.DeleteHandlerV2) {
  323. TDI_LOG(LOG_NOTIFY, ("Del address %wZ from %wZ\n",
  324. &Provider->DeviceName,
  325. &NotifyPnpElement->ElementName));
  326. (*(NotifyPnpElement->AddressElement.DeleteHandlerV2))(
  327. &Provider->Specific.NetAddress.Address,
  328. &Provider->DeviceName,
  329. Provider->Context2 );
  330. }
  331. }
  332. } else if (Provider->Common.Type == TDI_RESOURCE_POWER) {
  333. // RESOURCE_POWER
  334. if (NotifyPnpElement->PnpPowerHandler) {
  335. TDI_DEBUG(POWER, ("PnPPower Handler Called!\n"));
  336. TDI_LOG(LOG_NOTIFY | LOG_POWER,
  337. ("Power event %d to %wZ\n",
  338. Provider->PnpPowerEvent->NetEvent,
  339. &NotifyPnpElement->ElementName));
  340. Status = (*(NotifyPnpElement->PnpPowerHandler)) (
  341. &Provider->Specific.Device.DeviceName,
  342. Provider->PnpPowerEvent,
  343. Provider->Context1,
  344. Provider->Context2
  345. );
  346. if (STATUS_PENDING == Status) {
  347. TDI_DEBUG(POWER, ("Client returned PENDING (%d) ++\n", Provider->PowerHandlers));
  348. ReturnStatus = STATUS_PENDING;
  349. } else {
  350. //
  351. // Record the return value only if it is not SUCCESS or PENDING.
  352. //
  353. if (STATUS_SUCCESS != Status) {
  354. Provider->Status = Status;
  355. TDI_DEBUG(POWER, ("Client: %wZ returned %x\n", &NotifyPnpElement->ElementName, Provider->Status));
  356. //
  357. // For easier routing of failures.
  358. //
  359. DbgPrint("Client: %wZ returned %x\n", &NotifyPnpElement->ElementName, Provider->Status);
  360. }
  361. InterlockedDecrement(&Provider->PowerHandlers);
  362. TDI_DEBUG(POWER, ("Client returned Immediately (%d) : ++\n", Provider->PowerHandlers));
  363. }
  364. }
  365. } else if (Provider->Common.Type == TDI_RESOURCE_PROVIDER && Provider->ProviderReady) {
  366. //
  367. // First inform the clients about this provider and then if
  368. // ProvidersRegistered == ProvidersReady call again with NULL.
  369. //
  370. if ((TDI_VERSION_ONE != NotifyPnpElement->TdiVersion) &&
  371. (NULL != NotifyPnpElement->BindingHandler)) {
  372. TDI_LOG(LOG_NOTIFY, ("%wZ ready, notify %wZ\n",
  373. &Provider->Specific.Device.DeviceName,
  374. &NotifyPnpElement->ElementName));
  375. (*(NotifyPnpElement->BindingHandler))(
  376. TDI_PNP_OP_PROVIDERREADY,
  377. &Provider->Specific.Device.DeviceName,
  378. NULL
  379. );
  380. if (ProvidersReady == ProvidersRegistered) {
  381. TDI_LOG(LOG_NOTIFY, ("NETREADY to %wZ\n", &NotifyPnpElement->ElementName));
  382. (*(NotifyPnpElement->BindingHandler))(
  383. TDI_PNP_OP_NETREADY,
  384. NULL,
  385. NULL
  386. );
  387. } else {
  388. TDI_DEBUG(BIND, ("************** Registered:%d + Ready %d\n", ProvidersRegistered, ProvidersReady));
  389. }
  390. } else {
  391. TDI_DEBUG(PROVIDERS, ("%wZ has a NULL BindHandler\n", &NotifyPnpElement->ElementName));
  392. }
  393. }
  394. // Get the next one.
  395. Current = Current->Flink;
  396. Provider->Common.pNotifyElement = NULL; //Debugging info
  397. Provider->Common.ReturnStatus = ReturnStatus; // Debugging info
  398. }
  399. TDI_DEBUG(FUNCTION, ("-- TdiNotifyPnpClientList : %lx\n", ReturnStatus));
  400. return ReturnStatus;
  401. }
  402. VOID
  403. TdiNotifyNewPnpClient(
  404. PLIST_ENTRY ListHead,
  405. PVOID Info
  406. )
  407. /*++
  408. Routine Description:
  409. Called when a new client is added and we want to notify it of existing
  410. providers. The client can be for either binds or net addresses. We
  411. walk the specified input list, and notify the client about each entry in
  412. it.
  413. Arguments:
  414. ListHead - Head of list to walk.
  415. Info - Information describing the new client to be notified.
  416. Return Value:
  417. --*/
  418. {
  419. PLIST_ENTRY CurrentEntry;
  420. PTDI_NOTIFY_COMMON NotifyCommon;
  421. PTDI_PROVIDER_RESOURCE Provider;
  422. PTDI_NOTIFY_PNP_ELEMENT NotifyPnpElement;
  423. PWSTR MultiSZBindList = NULL;
  424. TDI_DEBUG(FUNCTION, ("++ TdiNotifyNewPnpClient\n"));
  425. CurrentEntry = ListHead->Flink;
  426. // The info is actually a pointer to a client notify element. Cast
  427. // it to the common type.
  428. NotifyCommon = (PTDI_NOTIFY_COMMON)Info;
  429. NotifyPnpElement = CONTAINING_RECORD(
  430. NotifyCommon,
  431. TDI_NOTIFY_PNP_ELEMENT,
  432. Common
  433. );
  434. TDI_DEBUG(CLIENTS, ("New handler set registered by %wZ\n", &NotifyPnpElement->ElementName));
  435. // Walk the input provider list, and for every element in it notify
  436. // the new client.
  437. while (CurrentEntry != ListHead) {
  438. // If the new client is for bind notifys, set up to call it's bind
  439. // handler.
  440. // Put the current provider element into the proper form.
  441. Provider = CONTAINING_RECORD(
  442. CurrentEntry,
  443. TDI_PROVIDER_RESOURCE,
  444. Common.Linkage
  445. );
  446. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  447. if (Provider->Common.Type == TDI_RESOURCE_DEVICE) {
  448. if (TDI_VERSION_ONE == NotifyPnpElement->TdiVersion ) {
  449. if (NotifyPnpElement->Bind.BindHandler) {
  450. TDI_LOG(LOG_NOTIFY, ("V1 bind %wZ to %wZ\n",
  451. &Provider->Specific.Device.DeviceName,
  452. &NotifyPnpElement->ElementName));
  453. (*(NotifyPnpElement->Bind.BindHandler))(
  454. &Provider->Specific.Device.DeviceName
  455. );
  456. }
  457. } else {
  458. if (NULL != NotifyPnpElement->BindingHandler) {
  459. // This is a bind notify client.
  460. if (TdipMultiSzStrStr(
  461. NotifyPnpElement->ListofProviders,
  462. &Provider->Specific.Device.DeviceName
  463. )) {
  464. TDI_DEBUG(BIND, ("Telling new handlers to bind to %wZ\n", &Provider->Specific.Device.DeviceName));
  465. TDI_LOG(LOG_NOTIFY, ("bind(new) %wZ to %wZ\n",
  466. &Provider->Specific.Device.DeviceName,
  467. &NotifyPnpElement->ElementName));
  468. (*(NotifyPnpElement->BindingHandler))(
  469. TDI_PNP_OP_ADD,
  470. &Provider->Specific.Device.DeviceName,
  471. (PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
  472. );
  473. } else {
  474. TDI_DEBUG(BIND, ("The Client %wZ wasnt interested in this Provider %wZ!\r\n",
  475. &NotifyPnpElement->ElementName, &Provider->Specific.Device.DeviceName));
  476. }
  477. } else {
  478. TDI_DEBUG(BIND, ("The client %wZ has a NULL Binding Handler\n", &NotifyPnpElement->ElementName));
  479. }
  480. }
  481. } else if (Provider->Common.Type == TDI_RESOURCE_NET_ADDRESS) {
  482. // This is an address notify client.
  483. // cant be TDI_RESOURCE_POWER coz we never put it on the list! - ShreeM
  484. if (TDI_VERSION_ONE == NotifyPnpElement->TdiVersion) {
  485. if (NULL != NotifyPnpElement->AddressElement.AddHandler) {
  486. TDI_LOG(LOG_NOTIFY, ("Add address v1 %wZ to %wZ\n",
  487. &Provider->DeviceName,
  488. &NotifyPnpElement->ElementName));
  489. (*(NotifyPnpElement->AddressElement.AddHandler))(
  490. &Provider->Specific.NetAddress.Address
  491. );
  492. }
  493. } else {
  494. if (NotifyPnpElement->AddressElement.AddHandlerV2) {
  495. TdiDumpAddress(&Provider->Specific.NetAddress.Address);
  496. TDI_LOG(LOG_NOTIFY, ("Add address(2) %wZ to %wZ\n",
  497. &Provider->DeviceName,
  498. &NotifyPnpElement->ElementName));
  499. (*(NotifyPnpElement->AddressElement.AddHandlerV2))(
  500. &Provider->Specific.NetAddress.Address,
  501. &Provider->DeviceName,
  502. Provider->Context2
  503. );
  504. }
  505. }
  506. }
  507. // And do the next one.
  508. CurrentEntry = CurrentEntry->Flink;
  509. }
  510. //
  511. // Now the providers who are ready.
  512. //
  513. if (NULL == NotifyPnpElement->BindingHandler) {
  514. //
  515. // If the Bindhandler is NULL, further action is pointless.
  516. //
  517. TDI_DEBUG(PROVIDERS, ("%wZ has a NULL BindHandler!!\n", &NotifyPnpElement->ElementName));
  518. TDI_DEBUG(FUNCTION, ("-- TdiNotifyNewPnpClient\n"));
  519. return;
  520. }
  521. if (TDI_VERSION_ONE == NotifyPnpElement->TdiVersion) {
  522. //
  523. // If the Bindhandler is NULL, further action is pointless.
  524. //
  525. TDI_DEBUG(PROVIDERS, ("This is a TDI v.1 client!\n"));
  526. TDI_DEBUG(FUNCTION, ("-- TdiNotifyNewPnpClient\n"));
  527. return;
  528. }
  529. // Otherwise, we can start the loop again.
  530. // Yes, maintaining different lists for addresses, providers, and devices
  531. // might be more efficient and I will do this later.
  532. CurrentEntry = ListHead->Flink;
  533. while (CurrentEntry != ListHead) {
  534. Provider = CONTAINING_RECORD(
  535. CurrentEntry,
  536. TDI_PROVIDER_RESOURCE,
  537. Common.Linkage
  538. );
  539. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  540. if (Provider->Common.Type == TDI_RESOURCE_PROVIDER && Provider->ProviderReady) {
  541. //
  542. // First inform the clients about this provider and then if
  543. // ProvidersRegistered == ProvidersReady call again with NULL.
  544. //
  545. TDI_LOG(LOG_NOTIFY, ("%wZ ready2, notify %wZ\n",
  546. &Provider->Specific.Device.DeviceName,
  547. &NotifyPnpElement->ElementName));
  548. (*(NotifyPnpElement->BindingHandler))(
  549. TDI_PNP_OP_PROVIDERREADY,
  550. &Provider->Specific.Device.DeviceName,
  551. NULL
  552. );
  553. }
  554. // And do the next one.
  555. CurrentEntry = CurrentEntry->Flink;
  556. }
  557. if (ProvidersReady == ProvidersRegistered) {
  558. TDI_LOG(LOG_NOTIFY, ("NETREADY2 to %wZ\n", &NotifyPnpElement->ElementName));
  559. (*(NotifyPnpElement->BindingHandler))(
  560. TDI_PNP_OP_NETREADY,
  561. NULL,
  562. NULL
  563. );
  564. } else {
  565. TDI_DEBUG(PROVIDERS, ("Provider Ready Status: Registered:%d + Ready:%d\n", ProvidersRegistered, ProvidersReady));
  566. }
  567. TDI_DEBUG(FUNCTION, ("-- TdiNotifyNewPnpClient\n"));
  568. }
  569. VOID
  570. TdiNotifyAddresses(
  571. PLIST_ENTRY ListHead,
  572. PVOID Info
  573. )
  574. /*++
  575. Routine Description:
  576. Called when a client wants to know about all the TDI Addresses
  577. Arguments:
  578. ListHead - Head of list to walk.
  579. Info - Information describing the new client to be notified.
  580. Return Value:
  581. --*/
  582. {
  583. PLIST_ENTRY CurrentEntry;
  584. PTDI_NOTIFY_COMMON NotifyCommon;
  585. PTDI_PROVIDER_RESOURCE Provider;
  586. PTDI_NOTIFY_PNP_ELEMENT NotifyPnpElement;
  587. TDI_DEBUG(FUNCTION, ("++ TdiNotifyAddresses\n"));
  588. CurrentEntry = ListHead->Flink;
  589. // The info is actually a pointer to a client notify element. Cast
  590. // it to the common type.
  591. NotifyCommon = (PTDI_NOTIFY_COMMON)Info;
  592. NotifyPnpElement = CONTAINING_RECORD(
  593. NotifyCommon,
  594. TDI_NOTIFY_PNP_ELEMENT,
  595. Common
  596. );
  597. TDI_DEBUG(CLIENTS, ("%wZ wants to know about all the addresses\n", &NotifyPnpElement->ElementName));
  598. // Walk the input provider list, and for every element in it notify
  599. // the new client.
  600. while (CurrentEntry != ListHead) {
  601. // If the new client is for bind notifys, set up to call it's bind
  602. // handler.
  603. // Put the current provider element into the proper form.
  604. Provider = CONTAINING_RECORD(
  605. CurrentEntry,
  606. TDI_PROVIDER_RESOURCE,
  607. Common.Linkage
  608. );
  609. if (Provider->Common.Type == TDI_RESOURCE_NET_ADDRESS) {
  610. if (NotifyPnpElement->AddressElement.AddHandlerV2) {
  611. TDI_DEBUG(ADDRESS, ("Add Address Handler\n"));
  612. TDI_DEBUG(CLIENTS, ("Telling new handlers about address: "));
  613. TdiDumpAddress(&Provider->Specific.NetAddress.Address);
  614. (*(NotifyPnpElement->AddressElement.AddHandlerV2))(
  615. &Provider->Specific.NetAddress.Address,
  616. &Provider->DeviceName,
  617. Provider->Context2
  618. );
  619. }
  620. }
  621. // And do the next one.
  622. CurrentEntry = CurrentEntry->Flink;
  623. }
  624. TDI_DEBUG(FUNCTION, ("-- TdiNotifyAddresses\n"));
  625. }
  626. VOID
  627. TdiHandlePnpOperation(
  628. PLIST_ENTRY ListHead,
  629. PVOID Info
  630. )
  631. {
  632. PLIST_ENTRY Current;
  633. PTDI_NOTIFY_PNP_ELEMENT NotifyPnpElement;
  634. PTDI_PROVIDER_RESOURCE ProviderElement;
  635. PTDI_NCPA_BINDING_INFO NCPABindingInfo;
  636. NTSTATUS Status = STATUS_SUCCESS;
  637. NET_PNP_EVENT NetEvent;
  638. ULONG Operation;
  639. BOOLEAN DeviceRegistered = FALSE;
  640. BOOLEAN ClientFound = FALSE;
  641. UINT NumberofEntries = 0;
  642. TDI_DEBUG(FUNCTION, ("---------------------------> ++ TdiHandlePnpOperation!!\n"));
  643. ASSERT(NULL != Info);
  644. ASSERT(NULL != ListHead);
  645. Current = ListHead->Flink;
  646. // The Info parameter is actually a pointer to TDI_NCPA_BINDING_INFO
  647. // structure.
  648. NCPABindingInfo = (PTDI_NCPA_BINDING_INFO) Info;
  649. Operation = (ULONG) NCPABindingInfo->PnpOpcode;
  650. // Walk the input client list, and see if that is the client we are looking for.
  651. while (Current != ListHead) {
  652. NotifyPnpElement = CONTAINING_RECORD(
  653. Current,
  654. TDI_NOTIFY_PNP_ELEMENT,
  655. Common.Linkage
  656. );
  657. if (!RtlCompareUnicodeString(
  658. NCPABindingInfo->TdiClientName,
  659. &NotifyPnpElement->ElementName,
  660. TRUE)
  661. ) {
  662. TDI_DEBUG(NCPA, ("Found the TDI client for the message from NCPA\n"));
  663. ClientFound = TRUE;
  664. break;
  665. }
  666. Current = Current->Flink;
  667. }
  668. if (!ClientFound) {
  669. //
  670. // Cant do much if the client's handlers are not registered.
  671. //
  672. return;
  673. } else {
  674. //
  675. // Let's update the ListofProviders for this client.
  676. // Add a new provider to the Client's list of Providers...
  677. //
  678. if (NotifyPnpElement->ListofProviders) {
  679. TDI_DEBUG(NCPA, ("Before this BIND - Client %wZ was interested in %lx Providers\n", &NotifyPnpElement->ElementName,
  680. NotifyPnpElement->NumberofEntries));
  681. ExFreePool(NotifyPnpElement->ListofProviders);
  682. TDI_DEBUG(NCPA, ("Freed the previous List of Providers\n"));
  683. } else {
  684. TDI_DEBUG(NCPA, ("List of providers was NULL for %wZ\n", &NotifyPnpElement->ElementName));
  685. }
  686. TdipBuildProviderList(
  687. (PTDI_NOTIFY_PNP_ELEMENT) NotifyPnpElement
  688. );
  689. TDI_DEBUG(NCPA, ("Built New BindList - %wZ is interested in %lx Providers after BIND\n", &NotifyPnpElement->ElementName,
  690. NotifyPnpElement->NumberofEntries));
  691. }
  692. //
  693. // If it is a reconfigure, or an add or delete ignore binding,
  694. // don't see if device (provider) is registered.
  695. //
  696. if ((RECONFIGURE == Operation) || (ADD_IGNORE_BINDING == Operation) ||
  697. (DEL_IGNORE_BINDING == Operation))
  698. {
  699. goto DeviceNotRequired;
  700. }
  701. //
  702. // If we are here, the client exists. Check if the provider has registered the device
  703. //
  704. Current = PnpHandlerProviderList.Flink;
  705. while (Current != &PnpHandlerProviderList) {
  706. ProviderElement = CONTAINING_RECORD(
  707. Current,
  708. TDI_PROVIDER_RESOURCE,
  709. Common.Linkage
  710. );
  711. if (ProviderElement->Common.Type != TDI_RESOURCE_DEVICE) {
  712. Current = Current->Flink;
  713. continue;
  714. }
  715. if (!RtlCompareUnicodeString(NCPABindingInfo->TdiProviderName,
  716. &ProviderElement->Specific.Device.DeviceName,
  717. TRUE)) {
  718. TDI_DEBUG(NCPA, ("Provider is registered with TDI\n"));
  719. DeviceRegistered = TRUE;
  720. break;
  721. }
  722. Current = Current->Flink;
  723. }
  724. if (!DeviceRegistered) {
  725. if (NULL != NotifyPnpElement->BindingHandler) {
  726. TDI_LOG(LOG_NOTIFY,
  727. ("Device is not registered, doing OP_UPDATE, %wZ to %wZ\n",
  728. NCPABindingInfo->TdiProviderName,
  729. &NotifyPnpElement->ElementName));
  730. (*(NotifyPnpElement->BindingHandler))(
  731. TDI_PNP_OP_UPDATE,
  732. NCPABindingInfo->TdiProviderName,
  733. (PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
  734. );
  735. } else {
  736. TDI_DEBUG(NCPA, ("Device is not registered, the BindHandler was NULL\n"));
  737. }
  738. return;
  739. }
  740. DeviceNotRequired:
  741. //
  742. // We need to manufacture a NET_PNP_EVENT here.
  743. //
  744. RtlZeroMemory (NetEvent.TdiReserved, sizeof(NetEvent.TdiReserved));
  745. //
  746. // Depending on the NetEvent, we call a different handler.
  747. //
  748. switch (Operation) {
  749. case BIND:
  750. //
  751. // First check if the TDI Client is interested in the Provider
  752. //
  753. if (TdipMultiSzStrStr(
  754. NotifyPnpElement->ListofProviders,
  755. &ProviderElement->Specific.Device.DeviceName
  756. )) {
  757. TDI_DEBUG(NCPA, ("The Client %wZ is interested in provider %wZ\n", &NotifyPnpElement->ElementName,
  758. &ProviderElement->Specific.Device.DeviceName
  759. ));
  760. } else {
  761. TDI_DEBUG(NCPA, ("RANDOM BIND CALL!!!\n"));
  762. TDI_DEBUG(NCPA, ("The Client %wZ is NOT interested in provider %wZ\n", &NotifyPnpElement->ElementName,
  763. &ProviderElement->Specific.Device.DeviceName
  764. ));
  765. }
  766. if (NULL != NotifyPnpElement->BindingHandler) {
  767. TDI_LOG(LOG_NOTIFY, ("Pnp Bind %wZ to %wZ\n",
  768. NCPABindingInfo->TdiProviderName,
  769. &NotifyPnpElement->ElementName));
  770. (*(NotifyPnpElement->BindingHandler))(
  771. TDI_PNP_OP_ADD,
  772. NCPABindingInfo->TdiProviderName,
  773. (PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
  774. );
  775. //
  776. // Here we should also update the NotifyElement's buffer.
  777. //
  778. } else {
  779. TDI_DEBUG(NCPA, ("The BindHandler was NULL\n"));
  780. }
  781. break;
  782. case UNBIND:
  783. //
  784. // The plan is to do a QueryRemove first and then call UnBind.
  785. //
  786. if (NotifyPnpElement->PnpPowerHandler) {
  787. TDI_DEBUG(POWER, ("UNBind Handler Called!: First QueryRemoveDevice\n"));
  788. NetEvent.NetEvent = NetEventQueryRemoveDevice;
  789. NetEvent.Buffer = NULL;
  790. NetEvent.BufferLength = 0;
  791. // The TDI Client should look at the OpCode in NetEvent and decide how to use the buffer.
  792. Status = (*(NotifyPnpElement->PnpPowerHandler)) (
  793. NCPABindingInfo->TdiProviderName,
  794. &NetEvent,
  795. NULL,
  796. NULL
  797. );
  798. if (STATUS_PENDING == Status) {
  799. TDI_DEBUG(POWER, ("Client returned PENDING for QueryPower!\n"));
  800. //DbgBreakPoint();
  801. }
  802. } else {
  803. TDI_DEBUG(NCPA, ("The PnpPowerHandler was NULL\n"));
  804. }
  805. //
  806. // OK, now call the UNBIND HANDLER anyway
  807. //
  808. case UNBIND_FORCE:
  809. // RDR returns PENDING all the time, we need a mechanism to fix this.
  810. // if (((STATUS_PENDING == Status) || (STATUS_SUCCESS == Status)) && (NULL != NotifyPnpElement->BindingHandler)) {
  811. if ((STATUS_SUCCESS == Status) && (NULL != NotifyPnpElement->BindingHandler)) {
  812. TDI_LOG(LOG_NOTIFY, ("Pnp Unbind %wZ from %wZ\n",
  813. NCPABindingInfo->TdiProviderName,
  814. &NotifyPnpElement->ElementName));
  815. (*(NotifyPnpElement->BindingHandler))(
  816. TDI_PNP_OP_DEL,
  817. NCPABindingInfo->TdiProviderName,
  818. (PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
  819. );
  820. } else {
  821. TDI_DEBUG(NCPA, ("The BindHandler was NULL\n"));
  822. }
  823. break;
  824. case RECONFIGURE:
  825. //
  826. // If the Reconfigure Buffer is NULL, we are notifying it of a NetEventBindList
  827. // Otherwise we are notifying it of a NetEventReconfig. Need to do the dirty work
  828. // of setting up the NET_PNP_EVENT accordingly.
  829. //
  830. TDI_DEBUG(POWER, ("Reconfigure Called.\n"));
  831. //
  832. // If the ReconfigBufferLength greater than 0, its Reconfig
  833. //
  834. if (NCPABindingInfo->ReconfigBufferSize) {
  835. NetEvent.BufferLength = NCPABindingInfo->ReconfigBufferSize;
  836. NetEvent.Buffer = NCPABindingInfo->ReconfigBuffer;
  837. NetEvent.NetEvent = NetEventReconfigure;
  838. } else {
  839. //
  840. // Else, its a BindOrder change
  841. //
  842. NetEvent.BufferLength = NCPABindingInfo->BindList->Length;
  843. NetEvent.Buffer = NCPABindingInfo->BindList->Buffer;
  844. NetEvent.NetEvent = NetEventBindList;
  845. }
  846. if (NotifyPnpElement->PnpPowerHandler) {
  847. // The TDI Client should look at the OpCode in NetEvent and decide how to use the buffer.
  848. TDI_LOG(LOG_NOTIFY, ("Pnp Reconfig %wZ to %wZ\n",
  849. NCPABindingInfo->TdiProviderName,
  850. &NotifyPnpElement->ElementName));
  851. Status = (*(NotifyPnpElement->PnpPowerHandler)) (
  852. NCPABindingInfo->TdiProviderName,
  853. &NetEvent,
  854. NULL,
  855. NULL
  856. );
  857. if (STATUS_PENDING == Status) {
  858. TDI_DEBUG(POWER, ("Client returned PENDING for QueryPower!\n"));
  859. //DbgBreakPoint();
  860. }
  861. } else {
  862. TDI_DEBUG(NCPA, ("The PnpPowerHandler was NULL\n"));
  863. }
  864. break;
  865. case ADD_IGNORE_BINDING:
  866. {
  867. // We are being told to add a binding to a list of bindings
  868. // to ignore for this client. These are bindings we will
  869. // not indicate to the client.
  870. //
  871. PWSTR pmszNewIgnoreList;
  872. ASSERT (NCPABindingInfo->BindList);
  873. // If a non-null bindlist was given...
  874. if (NCPABindingInfo->BindList)
  875. {
  876. TDI_DEBUG(BIND, ("Adding the following multi-sz to the ignore list\n"));
  877. //TdipPrintMultiSz (NCPABindingInfo->BindList->Buffer);
  878. // We need to add some bindings to our list of
  879. // bindings to ignore.
  880. //
  881. TdipAddMultiSzToMultiSz (NCPABindingInfo->BindList,
  882. NotifyPnpElement->ListofBindingsToIgnore,
  883. &pmszNewIgnoreList);
  884. if (pmszNewIgnoreList)
  885. {
  886. // If we have a new list, free the old one.
  887. //
  888. if (NotifyPnpElement->ListofBindingsToIgnore)
  889. {
  890. ExFreePool (NotifyPnpElement->ListofBindingsToIgnore);
  891. }
  892. NotifyPnpElement->ListofBindingsToIgnore = pmszNewIgnoreList;
  893. TDI_DEBUG(BIND, ("Printing new ignore list\n"));
  894. TdipPrintMultiSz (NotifyPnpElement->ListofBindingsToIgnore);
  895. }
  896. }
  897. break;
  898. }
  899. case DEL_IGNORE_BINDING:
  900. // We are being told to remove bindings from a list of bindings
  901. // to ignore for this client. These are bindings we will
  902. // now indicate to the client if we need to.
  903. //
  904. // If we don't have a current list of bindings to ignore
  905. // or the bindlist sent was NULL then there is no work to do.
  906. // We assert on a NULL BindList because it shouldn't happen.
  907. ASSERT(NCPABindingInfo->BindList);
  908. if (NotifyPnpElement->ListofBindingsToIgnore &&
  909. NCPABindingInfo->BindList)
  910. {
  911. TDI_DEBUG(BIND, ("Removing the following multi-sz from the ignore list\n"));
  912. //TdipPrintMultiSz (NCPABindingInfo->BindList->Buffer);
  913. // We need to remove some bindings from our list of bindings
  914. // to ignore.
  915. //
  916. TdipRemoveMultiSzFromMultiSz (NCPABindingInfo->BindList->Buffer,
  917. NotifyPnpElement->ListofBindingsToIgnore);
  918. // If the list of bindings to ignore is now empty,
  919. // free the memory.
  920. //
  921. if (*NotifyPnpElement->ListofBindingsToIgnore)
  922. {
  923. ExFreePool (NotifyPnpElement->ListofBindingsToIgnore);
  924. NotifyPnpElement->ListofBindingsToIgnore = NULL;
  925. }
  926. TDI_DEBUG(BIND, ("Printing new ignore list\n"));
  927. TdipPrintMultiSz (NotifyPnpElement->ListofBindingsToIgnore);
  928. }
  929. break;
  930. }
  931. TDI_DEBUG(FUNCTION, ("---------------------------> -- TdiHandlePnpOperation!!\n"));
  932. }
  933. NTSTATUS
  934. TdiExecuteRequest(
  935. IN CTEEvent *Event,
  936. IN PVOID pParams
  937. )
  938. /*++
  939. Routine Description:
  940. Called by TdiHandleSerializedRequest to execute the request.
  941. It has been made another function, so that a worker thread can
  942. execute this function.
  943. Parameters:
  944. CTEEvent (Event) : If this is NULL, it means that we have
  945. been called directly from TdiHandleSerializedRequest.
  946. Otherwise, it is called from the WorkerThread
  947. PVOID (pParams) : This can NEVER be NULL. It tells this function
  948. of the work that needs to be done.
  949. Output:
  950. NT_STATUS.
  951. --*/
  952. {
  953. PTDI_PROVIDER_RESOURCE ProviderElement, Context;
  954. PTDI_NOTIFY_COMMON NotifyElement;
  955. KIRQL OldIrql;
  956. PLIST_ENTRY List;
  957. PTDI_EXEC_PARAMS pTdiExecParams, pNextParams = NULL;
  958. NTSTATUS Status = STATUS_SUCCESS;
  959. ULONG ScheduledTest = 0;
  960. PTDI_NOTIFY_PNP_ELEMENT PnpNotifyElement = NULL;
  961. TDI_DEBUG(FUNCTION2, ("++ TdiExecuteRequest\n"));
  962. // we are in trouble if pParams is NULL
  963. ASSERT(NULL != pParams);
  964. pTdiExecParams = (PTDI_EXEC_PARAMS) pParams;
  965. if (NULL == pTdiExecParams) {
  966. TDI_DEBUG(PARAMETERS, ("TDIExecRequest: params NULL\n"));
  967. DbgBreakPoint();
  968. }
  969. if(0x1234cdef != pTdiExecParams->Signature) {
  970. TDI_DEBUG(PARAMETERS, ("signature is BAD - %d not 0x1234cdef\r\n", pTdiExecParams->Signature));
  971. DbgBreakPoint();
  972. }
  973. ExAcquireSpinLock(
  974. &TDIListLock,
  975. &OldIrql
  976. );
  977. if (pTdiExecParams->Request.Event != NULL) {
  978. *(pTdiExecParams->CurrentThread) = PsGetCurrentThread();
  979. }
  980. // DEBUG TRACKING ++++++++++++++++++
  981. TrackExecs[NextExec].ExecParm = pTdiExecParams;
  982. TrackExecs[NextExec].Type = pTdiExecParams->Request.Type;
  983. TrackExecs[NextExec].Element = pTdiExecParams->Request.Element;
  984. TrackExecs[NextExec].Thread = pTdiExecParams->CurrentThread;
  985. if (++NextExec == EXEC_CNT) NextExec = 0;
  986. // DEBUG TRACKING ++++++++++++++++++
  987. PrevRequestType = pTdiExecParams->Request.Type;
  988. ExReleaseSpinLock(
  989. &TDIListLock,
  990. OldIrql
  991. );
  992. switch (pTdiExecParams->Request.Type) {
  993. case TDI_REGISTER_HANDLERS_PNP:
  994. // This is a client register bind or address handler request.
  995. // Insert this one into the registered client list.
  996. NotifyElement = (PTDI_NOTIFY_COMMON)pTdiExecParams->Request.Element;
  997. InsertTailList(
  998. pTdiExecParams->ClientList,
  999. &NotifyElement->Linkage
  1000. );
  1001. //
  1002. // Generate the list of new TDI_OPEN_BLOCKS caused by the new
  1003. // Client. If the provider isnt here, we set it to NULL for now.
  1004. //
  1005. TdipBuildProviderList(
  1006. (PTDI_NOTIFY_PNP_ELEMENT) NotifyElement
  1007. );
  1008. // Call TdiNotifyNewClient to notify this new client of all
  1009. // all existing providers.
  1010. TdiNotifyNewPnpClient(
  1011. pTdiExecParams->ProviderList,
  1012. pTdiExecParams->Request.Element
  1013. );
  1014. break;
  1015. case TDI_DEREGISTER_HANDLERS_PNP:
  1016. // This is a client deregister request. Pull him from the
  1017. // client list, free it, and we're done.
  1018. NotifyElement = (PTDI_NOTIFY_COMMON)pTdiExecParams->Request.Element;
  1019. CTEAssert(NotifyElement->Linkage.Flink != (PLIST_ENTRY)UlongToPtr(0xabababab));
  1020. CTEAssert(NotifyElement->Linkage.Blink != (PLIST_ENTRY)UlongToPtr(0xefefefef));
  1021. RemoveEntryList(&NotifyElement->Linkage);
  1022. NotifyElement->Linkage.Flink = (PLIST_ENTRY)UlongToPtr(0xabababab);
  1023. NotifyElement->Linkage.Blink = (PLIST_ENTRY)UlongToPtr(0xefefefef);
  1024. // for the new handlers, we also have the name there.
  1025. PnpNotifyElement = (PTDI_NOTIFY_PNP_ELEMENT)pTdiExecParams->Request.Element;
  1026. // the name can be NULL, as in the case of TCP/IP.
  1027. if (NULL != PnpNotifyElement->ElementName.Buffer) {
  1028. ExFreePool(PnpNotifyElement->ElementName.Buffer);
  1029. }
  1030. if (NULL != PnpNotifyElement->ListofProviders) {
  1031. ExFreePool(PnpNotifyElement->ListofProviders);
  1032. }
  1033. ExFreePool(NotifyElement);
  1034. break;
  1035. case TDI_REGISTER_PROVIDER_PNP:
  1036. InterlockedIncrement(&ProvidersRegistered);
  1037. case TDI_REGISTER_DEVICE_PNP:
  1038. case TDI_REGISTER_ADDRESS_PNP:
  1039. // A provider is registering a device or address. Add him to
  1040. // the appropriate provider list, and then notify all
  1041. // existing clients of the new device.
  1042. ProviderElement = (PTDI_PROVIDER_RESOURCE) pTdiExecParams->Request.Element;
  1043. InsertTailList(
  1044. pTdiExecParams->ProviderList,
  1045. &ProviderElement->Common.Linkage
  1046. );
  1047. // Call TdiNotifyClientList to do the hard work.
  1048. TdiNotifyPnpClientList(
  1049. pTdiExecParams->ClientList,
  1050. pTdiExecParams->Request.Element,
  1051. TRUE
  1052. );
  1053. break;
  1054. case TDI_DEREGISTER_PROVIDER_PNP:
  1055. InterlockedDecrement(&ProvidersRegistered);
  1056. case TDI_DEREGISTER_DEVICE_PNP:
  1057. case TDI_DEREGISTER_ADDRESS_PNP:
  1058. // A provider device or address is deregistering. Pull the
  1059. // resource from the provider list, and notify clients that
  1060. // he's gone.
  1061. ProviderElement = (PTDI_PROVIDER_RESOURCE)pTdiExecParams->Request.Element;
  1062. CTEAssert(ProviderElement->Common.Linkage.Flink != (PLIST_ENTRY)UlongToPtr(0xabababab));
  1063. CTEAssert(ProviderElement->Common.Linkage.Blink != (PLIST_ENTRY)UlongToPtr(0xefefefef));
  1064. RemoveEntryList(&ProviderElement->Common.Linkage);
  1065. ProviderElement->Common.Linkage.Flink = (PLIST_ENTRY) UlongToPtr(0xabababab);
  1066. ProviderElement->Common.Linkage.Blink = (PLIST_ENTRY) UlongToPtr(0xefefefef);
  1067. //
  1068. // Dont have to tell the clients if this is a ProviderDeregister.
  1069. //
  1070. if (pTdiExecParams->Request.Type == TDI_DEREGISTER_PROVIDER_PNP) {
  1071. if (ProviderElement->ProviderReady) {
  1072. InterlockedDecrement(&ProvidersReady);
  1073. }
  1074. } else {
  1075. TdiNotifyPnpClientList(
  1076. pTdiExecParams->ClientList,
  1077. pTdiExecParams->Request.Element,
  1078. FALSE
  1079. );
  1080. }
  1081. // Free the tracking structure we had.
  1082. if (pTdiExecParams->Request.Type == TDI_DEREGISTER_DEVICE_PNP) {
  1083. ExFreePool(ProviderElement->Specific.Device.DeviceName.Buffer);
  1084. }
  1085. if (ProviderElement->DeviceName.Buffer) {
  1086. ExFreePool(ProviderElement->DeviceName.Buffer);
  1087. ProviderElement->DeviceName.Buffer = NULL;
  1088. ProviderElement->DeviceName.Length = 0;
  1089. ProviderElement->DeviceName.MaximumLength = 0;
  1090. }
  1091. if (ProviderElement->Context2) {
  1092. ExFreePool(ProviderElement->Context2);
  1093. ProviderElement->Context2 = NULL;
  1094. }
  1095. ExFreePool(ProviderElement);
  1096. break;
  1097. case TDI_REGISTER_PNP_POWER_EVENT:
  1098. // Inform all the Clients of the Power Event, which has come from
  1099. // a transport...
  1100. ProviderElement = (PTDI_PROVIDER_RESOURCE)pTdiExecParams->Request.Element;
  1101. /*
  1102. KeInitializeEvent(
  1103. &ProviderElement->PowerSyncEvent,
  1104. SynchronizationEvent,
  1105. FALSE
  1106. );
  1107. */
  1108. //
  1109. // Figure out how many clients we are going to inform.
  1110. //
  1111. {
  1112. PLIST_ENTRY Current;
  1113. PTDI_NOTIFY_PNP_ELEMENT NotifyPnpElement;
  1114. ProviderElement->PowerHandlers = 1;
  1115. Current = pTdiExecParams->ClientList->Flink;
  1116. while (Current != pTdiExecParams->ClientList) {
  1117. NotifyPnpElement = CONTAINING_RECORD(
  1118. Current,
  1119. TDI_NOTIFY_PNP_ELEMENT,
  1120. Common.Linkage
  1121. );
  1122. // RESOURCE_POWER
  1123. if (NotifyPnpElement->PnpPowerHandler) {
  1124. ProviderElement->PowerHandlers++;
  1125. }
  1126. // Get the next one.
  1127. TDI_DEBUG(POWER, ("%d PowerCallBacks expected\n", ProviderElement->PowerHandlers));
  1128. Current = Current->Flink;
  1129. }
  1130. }
  1131. TDI_LOG(LOG_POWER, ("%X, %d resources to notify\n",
  1132. ProviderElement, ProviderElement->PowerHandlers));
  1133. Status = TdiNotifyPnpClientList(
  1134. pTdiExecParams->ClientList,
  1135. pTdiExecParams->Request.Element,
  1136. FALSE // NOP: this param is ignored
  1137. );
  1138. TDI_DEBUG(POWER, ("The client list returned %lx\n", Status));
  1139. TDI_LOG(LOG_POWER, ("%X, NotityClients returned %X\n",
  1140. ProviderElement, Status));
  1141. if (!InterlockedDecrement(&ProviderElement->PowerHandlers)) {
  1142. PTDI_PROVIDER_RESOURCE Temp;
  1143. TDI_DEBUG(POWER, ("Power Handlers All done...\n", ProviderElement->PowerHandlers));
  1144. Temp =
  1145. Context = *((PTDI_PROVIDER_RESOURCE *) ProviderElement->PnpPowerEvent->TdiReserved);
  1146. //
  1147. // Loop thru and see if there are any previous contexts associated
  1148. // with this netpnp event, in which case, pop it.
  1149. //
  1150. Status = ProviderElement->Status;
  1151. if (Temp->PreviousContext) {
  1152. while (Temp->PreviousContext) {
  1153. Context = Temp;
  1154. Temp = Temp->PreviousContext;
  1155. }
  1156. Context->PreviousContext = NULL; //pop the last guy
  1157. } else {
  1158. //
  1159. // This was the only pointer in the TdiReserved and we dont need it anymore
  1160. //
  1161. RtlZeroMemory(ProviderElement->PnpPowerEvent->TdiReserved,
  1162. sizeof(ProviderElement->PnpPowerEvent->TdiReserved));
  1163. }
  1164. TDI_LOG(LOG_POWER, ("%X, pnp power complete, Call completion at %X\n",
  1165. ProviderElement, ProviderElement->PnPCompleteHandler));
  1166. if (pTdiExecParams->Request.Pending && (*(ProviderElement->PnPCompleteHandler))) {
  1167. (*(ProviderElement->PnPCompleteHandler))(
  1168. ProviderElement->PnpPowerEvent,
  1169. ProviderElement->Status
  1170. );
  1171. }
  1172. } else {
  1173. TDI_DEBUG(POWER, ("At least one of them is pending \n STATUS from ExecuteHAndler:%x\n", Status));
  1174. TDI_LOG(LOG_POWER, ("%X, a client didn't complete pnp power sync\n",
  1175. ProviderElement));
  1176. }
  1177. TDI_DEBUG(POWER, ("<<<<NET NET NET>>>>> : Returning %lx\n", Status));
  1178. break;
  1179. case TDI_NDIS_IOCTL_HANDLER_PNP:
  1180. TdiHandlePnpOperation(
  1181. pTdiExecParams->ClientList,
  1182. pTdiExecParams->Request.Element
  1183. );
  1184. break;
  1185. case TDI_ENUMERATE_ADDRESSES:
  1186. // Insert this one into the registered client list.
  1187. NotifyElement = (PTDI_NOTIFY_COMMON)pTdiExecParams->Request.Element;
  1188. // Call TdiNotifyNewClient to notify this new client of all
  1189. // all existing providers.
  1190. TdiNotifyAddresses(
  1191. pTdiExecParams->ProviderList,
  1192. pTdiExecParams->Request.Element
  1193. );
  1194. break;
  1195. case TDI_PROVIDER_READY_PNP:
  1196. //
  1197. // Loop through and tell each client about it.
  1198. //
  1199. InterlockedIncrement(&ProvidersReady);
  1200. ProviderElement = (PTDI_PROVIDER_RESOURCE)pTdiExecParams->Request.Element;
  1201. ProviderElement->ProviderReady = TRUE;
  1202. TdiNotifyPnpClientList(
  1203. pTdiExecParams->ClientList,
  1204. pTdiExecParams->Request.Element,
  1205. TRUE
  1206. );
  1207. break;
  1208. default:
  1209. TDI_DEBUG(ERROR, ("unknown switch statement\n"));
  1210. CTEAssert(FALSE);
  1211. break;
  1212. }
  1213. // If there was an event specified with this request, signal
  1214. // it now. This should only be a client deregister request, which
  1215. // needs to block until it's completed.
  1216. if (pTdiExecParams->Request.Event != NULL) {
  1217. //
  1218. // If we had this thread marked to prevent re-entrant requests, then
  1219. // clear that. Note that we do this BEFORE we set the event below to
  1220. // let the thread go, since it may immediately resubmit another request.
  1221. //
  1222. *(pTdiExecParams->CurrentThread) = NULL;
  1223. KeSetEvent(pTdiExecParams->Request.Event, 0, FALSE);
  1224. }
  1225. ExAcquireSpinLock(
  1226. &TDIListLock,
  1227. &OldIrql
  1228. );
  1229. // DEBUG TRACKING ++++++++++++++++++
  1230. TrackExecCompletes[NextExecComplete].ExecParm = pTdiExecParams;
  1231. TrackExecCompletes[NextExecComplete].Type = pTdiExecParams->Request.Type;
  1232. TrackExecCompletes[NextExecComplete].Element = pTdiExecParams->Request.Element;
  1233. TrackExecCompletes[NextExecComplete].Thread = pTdiExecParams->CurrentThread;
  1234. if (++NextExecComplete == EXEC_CNT) NextExecComplete = 0;
  1235. // DEBUG TRACKING ++++++++++++++++++
  1236. //
  1237. // If this request occured on a worker thread
  1238. // reset the EventScheduled to FALSE
  1239. //
  1240. if (Event != NULL) {
  1241. EventScheduled = FALSE;
  1242. }
  1243. if (!IsListEmpty(pTdiExecParams->RequestList)) {
  1244. if (EventScheduled == FALSE) {
  1245. //
  1246. // The following should indicate that no new events should be created.
  1247. //
  1248. EventScheduled = TRUE;
  1249. // The request list isn't empty. Pull the next one from
  1250. // the list and process it.
  1251. List = RemoveHeadList(pTdiExecParams->RequestList);
  1252. pNextParams = CONTAINING_RECORD(List, TDI_EXEC_PARAMS, Linkage);
  1253. ExReleaseSpinLock(
  1254. &TDIListLock,
  1255. OldIrql
  1256. );
  1257. // Schedule a thread to deal with this work
  1258. // To fix bug# 33975
  1259. if(0x1234cdef != pNextParams->Signature) {
  1260. TDI_DEBUG(PARAMETERS, ("2 Signature is BAD - %d not 0x1234cdef\r\n", pTdiExecParams->Signature));
  1261. DbgBreakPoint();
  1262. }
  1263. ASSERT(pNextParams != NULL);
  1264. ASSERT(0x1234cdef == pNextParams->Signature);
  1265. PrevRequestType = pNextParams->Request.Type;
  1266. CTEInitEvent(pNextParams->RequestCTEEvent, TdiExecuteRequest);
  1267. CTEScheduleEvent(pNextParams->RequestCTEEvent, pNextParams);
  1268. } else {
  1269. ExReleaseSpinLock(
  1270. &TDIListLock,
  1271. OldIrql
  1272. );
  1273. }
  1274. ExFreePool(pTdiExecParams);
  1275. } else {
  1276. // The request list is empty. Clear the flag and we're done.
  1277. // IMP: Since Serializataion can be bypassed
  1278. // (the TdiSerializeRequest allows one type of request to bypass
  1279. // serialization),
  1280. // we need to make sure there are no other worker threads
  1281. // currently processing TdiRequests
  1282. if (pTdiExecParams->ResetSerializeFlag && EventScheduled == FALSE) {
  1283. *(pTdiExecParams->SerializeFlag) = FALSE;
  1284. } else {
  1285. TDI_LOG(LOG_POWER, ("Not resetting serialized flag\n"));
  1286. }
  1287. PrevRequestType = 0;
  1288. ExReleaseSpinLock(
  1289. &TDIListLock,
  1290. OldIrql
  1291. );
  1292. ExFreePool(pTdiExecParams);
  1293. }
  1294. TDI_DEBUG(FUNCTION2, ("-- TdiExecuteRequest\n"));
  1295. return Status;
  1296. }
  1297. NTSTATUS
  1298. TdiHandleSerializedRequest (
  1299. PVOID RequestInfo,
  1300. UINT RequestType
  1301. )
  1302. /*++
  1303. Routine Description:
  1304. Called when we want to process a request relating to one of the
  1305. lists we manage. We look to see if we are currently processing such
  1306. a request - if we are, we queue this for later. Otherwise we'll
  1307. remember that we are doing this, and we'll process this request.
  1308. When we're done we'll look to see if any more came in while we were
  1309. busy.
  1310. Arguments:
  1311. RequestInfo - Reqeust specific information.
  1312. RequestType - The type of the request.
  1313. Return Value:
  1314. Request completion status.
  1315. --*/
  1316. {
  1317. KIRQL OldIrql;
  1318. PLIST_ENTRY List;
  1319. PLIST_ENTRY ClientList;
  1320. PLIST_ENTRY ProviderList;
  1321. PLIST_ENTRY PnpHandlerList;
  1322. PLIST_ENTRY RequestList;
  1323. PBOOLEAN SerializeFlag;
  1324. PETHREAD *RequestThread;
  1325. PTDI_SERIALIZED_REQUEST Request;
  1326. CTEEvent *pEvent;
  1327. PTDI_EXEC_PARAMS pTdiExecParams;
  1328. NTSTATUS Status = STATUS_SUCCESS;
  1329. PVOID pCallersAddress;
  1330. PVOID pCallersCallers;
  1331. PETHREAD pCallerThread;
  1332. TDI_DEBUG(FUNCTION2, ("++ TdiHandleSerializedRequest\n"));
  1333. // Initialize tracking information
  1334. RtlGetCallersAddress(&pCallersAddress, &pCallersCallers);
  1335. pCallerThread = PsGetCurrentThread ();
  1336. ExAcquireSpinLock(
  1337. &TDIListLock,
  1338. &OldIrql
  1339. );
  1340. // means PnP handlers
  1341. if (RequestType > TDI_MAX_ADDRESS_REQUEST) {
  1342. ClientList = &PnpHandlerClientList;
  1343. ProviderList = &PnpHandlerProviderList;
  1344. RequestList = &PnpHandlerRequestList;
  1345. SerializeFlag = &PnpHandlerRequestInProgress;
  1346. RequestThread = &PnpHandlerRequestThread;
  1347. pEvent = &PnpHandlerEvent;
  1348. } else {
  1349. TDI_DEBUG(FUNCTION2, ("-- TdiHandleSerializedRequest\n"));
  1350. TDI_DEBUG(PARAMETERS, ("TDIHANDLESERIALIZEDREQUEST: BAD Request!!\r\n"));
  1351. ExReleaseSpinLock(
  1352. &TDIListLock,
  1353. OldIrql
  1354. );
  1355. return STATUS_UNSUCCESSFUL;
  1356. }
  1357. // We only need to allocate memory if this isn't a deregister call.
  1358. if (RequestType != TDI_DEREGISTER_HANDLERS_PNP) {
  1359. pTdiExecParams = (PTDI_EXEC_PARAMS)ExAllocatePoolWithTag(
  1360. NonPagedPool,
  1361. sizeof(TDI_EXEC_PARAMS),
  1362. 'aIDT'
  1363. );
  1364. if (NULL == pTdiExecParams) {
  1365. ExReleaseSpinLock(
  1366. &TDIListLock,
  1367. OldIrql
  1368. );
  1369. TDI_DEBUG(FUNCTION2, ("-- TdiHandleSerializedRequest : INSUFFICIENT RESOURCES\n"));
  1370. return STATUS_INSUFFICIENT_RESOURCES;
  1371. }
  1372. } else {
  1373. // We preallocated memory during register for this deregister call
  1374. // so that it won't fail sue to low memory conditions.
  1375. pTdiExecParams = ((PTDI_NOTIFY_PNP_ELEMENT)RequestInfo)->pTdiDeregisterExecParams;
  1376. }
  1377. RtlZeroMemory(&pTdiExecParams->Request, sizeof(TDI_SERIALIZED_REQUEST));
  1378. // Got the request.
  1379. pTdiExecParams->Request.Element = RequestInfo;
  1380. pTdiExecParams->Request.Type = RequestType;
  1381. pTdiExecParams->Request.Event = NULL;
  1382. // marshal params into a structure
  1383. // Set the Request Structure, so that we can process it in the TdiExecute function.
  1384. pTdiExecParams->ClientList = ClientList;
  1385. pTdiExecParams->ProviderList = ProviderList;
  1386. pTdiExecParams->RequestList = RequestList;
  1387. pTdiExecParams->SerializeFlag = SerializeFlag;
  1388. pTdiExecParams->RequestCTEEvent = pEvent;
  1389. pTdiExecParams->CurrentThread = RequestThread;
  1390. pTdiExecParams->Signature = 0x1234cdef;
  1391. pTdiExecParams->ResetSerializeFlag = TRUE;
  1392. pTdiExecParams->pCallersAddress = pCallersAddress;
  1393. pTdiExecParams->pCallersCaller = pCallersCallers;
  1394. pTdiExecParams->pCallerThread = pCallerThread;
  1395. // If we're not already here, handle it right away.
  1396. if ((!(*SerializeFlag)) ||
  1397. (((PrevRequestType == TDI_REGISTER_PNP_POWER_EVENT) ||
  1398. (PrevRequestType == TDI_NDIS_IOCTL_HANDLER_PNP)) &&
  1399. (RequestType == TDI_REGISTER_PNP_POWER_EVENT)) ) {
  1400. if (*SerializeFlag == TRUE) {
  1401. // A request is currently executing so don't
  1402. // reset the serialize flag when this one
  1403. // completes!!
  1404. pTdiExecParams->ResetSerializeFlag = FALSE;
  1405. }
  1406. *SerializeFlag = TRUE;
  1407. PrevRequestType = RequestType;
  1408. // We're done with the lock for now, so free it.
  1409. ExReleaseSpinLock(
  1410. &TDIListLock,
  1411. OldIrql
  1412. );
  1413. // Figure out and execute the type of request we have here.
  1414. Status = TdiExecuteRequest(NULL, pTdiExecParams);
  1415. TDI_LOG(LOG_REGISTER, ("-TdiSerialized sync\n"));
  1416. return Status;
  1417. } else {
  1418. // We're already running, so we'll have to queue. If this is a
  1419. // deregister bind or address notify call, we'll see if the issueing
  1420. // thread is the same one that is currently busy. If so, we'll fail
  1421. // to avoid deadlock. Otherwise for deregister calls we'll block until
  1422. // it's done.
  1423. //
  1424. // For Nt5, we have devicename and a context coming in along with net addresses/device objects.
  1425. // It is the transport's responsibility to ensure that these are correct.
  1426. // The Register_PNP_Handlers on the other hand need not be made synch.
  1427. //
  1428. if (
  1429. pTdiExecParams->Request.Type == TDI_DEREGISTER_HANDLERS_PNP ||
  1430. pTdiExecParams->Request.Type == TDI_NDIS_IOCTL_HANDLER_PNP
  1431. ) {
  1432. // This is a deregister request. See if it's the same thread
  1433. // that's busy. If not, block for it to complete.
  1434. if (*RequestThread == PsGetCurrentThread()) {
  1435. // It's the same one, so give up now.
  1436. ExReleaseSpinLock(
  1437. &TDIListLock,
  1438. OldIrql
  1439. );
  1440. ExFreePool(pTdiExecParams);
  1441. TDI_DEBUG(FUNCTION2, ("-- TdiHandleSerializedRequest: Network Busy\n"));
  1442. TDI_LOG(LOG_ERROR, ("-TdiSerializedRequest rc=busy\n"));
  1443. return STATUS_NETWORK_BUSY;
  1444. } else {
  1445. // He's not currently busy, go ahead and block.
  1446. KEVENT Event;
  1447. NTSTATUS Status;
  1448. KeInitializeEvent(
  1449. &Event,
  1450. SynchronizationEvent,
  1451. FALSE
  1452. );
  1453. pTdiExecParams->Request.Event = &Event;
  1454. // Put this guy on the end of the request list.
  1455. InsertTailList(pTdiExecParams->RequestList, &pTdiExecParams->Linkage);
  1456. ExReleaseSpinLock(
  1457. &TDIListLock,
  1458. OldIrql
  1459. );
  1460. TDI_LOG(LOG_REGISTER, ("TdiSerializedRequest blocked\n"));
  1461. Status = KeWaitForSingleObject(
  1462. &Event,
  1463. UserRequest,
  1464. KernelMode,
  1465. FALSE,
  1466. NULL
  1467. );
  1468. // I don't know what we'd do is the wait failed....
  1469. TDI_DEBUG(FUNCTION2, ("-- TdiHandleSerializedRequest\n"));
  1470. TDI_LOG(LOG_REGISTER, ("-TdiSerializeRequest rc=0\n"));
  1471. return STATUS_SUCCESS;
  1472. }
  1473. } else {
  1474. // This isn't a deregister request, so there's no special handling
  1475. // necessary. Just put the request on the end of the list.
  1476. InsertTailList(pTdiExecParams->RequestList, &pTdiExecParams->Linkage);
  1477. if (TDI_REGISTER_PNP_POWER_EVENT == pTdiExecParams->Request.Type) {
  1478. //
  1479. // For the PnP/PM event, there is now a completion handler, so
  1480. // we can return pending here only for this case.
  1481. // The other cases, we assume success.
  1482. //
  1483. pTdiExecParams->Request.Pending = TRUE;
  1484. ExReleaseSpinLock(
  1485. &TDIListLock,
  1486. OldIrql
  1487. );
  1488. TDI_DEBUG(FUNCTION2, ("-- TdiHandleSerializedRequest\n"));
  1489. TDI_LOG(LOG_REGISTER, ("-TdiSerialzied Pending\n"));
  1490. return STATUS_PENDING;
  1491. }
  1492. ExReleaseSpinLock(
  1493. &TDIListLock,
  1494. OldIrql
  1495. );
  1496. TDI_LOG(LOG_REGISTER, ("-TdiSerialized sync~sync\n"));
  1497. return STATUS_SUCCESS;
  1498. }
  1499. }
  1500. }
  1501. NTSTATUS
  1502. TdiRegisterNotificationHandler(
  1503. IN TDI_BIND_HANDLER BindHandler,
  1504. IN TDI_UNBIND_HANDLER UnbindHandler,
  1505. OUT HANDLE *BindingHandle
  1506. )
  1507. /*++
  1508. Routine Description:
  1509. This function is called when a TDI client wants to register for
  1510. notification of the arrival of TDI providers. We allocate a
  1511. TDI_NOTIFY_ELEMENT for the provider and then call the serialized
  1512. worker routine to do the real work.
  1513. Arguments:
  1514. BindHandler - A pointer to the routine to be called when
  1515. a new provider arrives.
  1516. UnbindHandler - A pointer to the routine to be called when a
  1517. provider leaves.
  1518. BindingHandle - A handle we pass back that identifies this
  1519. client to us.
  1520. Return Value:
  1521. The status of the attempt to register the client.
  1522. --*/
  1523. {
  1524. TDI_CLIENT_INTERFACE_INFO tdiInterface;
  1525. //
  1526. // Make sure Tdi is intialized. If there are no pnp transports, then this is
  1527. // called by the tdi client and if tdi is not initialized, it is toast
  1528. // Multiple calls to TdiIntialize are safe since only the first one does
  1529. // the real work
  1530. //
  1531. TdiInitialize();
  1532. RtlZeroMemory(&tdiInterface, sizeof(tdiInterface));
  1533. tdiInterface.MajorTdiVersion = 1;
  1534. tdiInterface.MinorTdiVersion = 0;
  1535. tdiInterface.BindHandler = BindHandler;
  1536. tdiInterface.UnBindHandler = UnbindHandler;
  1537. return (TdiRegisterPnPHandlers(
  1538. &tdiInterface,
  1539. sizeof(tdiInterface),
  1540. BindingHandle
  1541. ));
  1542. }
  1543. NTSTATUS
  1544. TdiDeregisterNotificationHandler(
  1545. IN HANDLE BindingHandle
  1546. )
  1547. /*++
  1548. Routine Description:
  1549. This function is called when a TDI client wants to deregister a
  1550. previously registered bind notification handler. All we really
  1551. do is call TdiHandleSerializedRequest, which does the hard work.
  1552. Arguments:
  1553. BindingHandle - A handle we passed back to the client
  1554. on the register call. This is really
  1555. a pointer to the notify element.
  1556. Return Value:
  1557. The status of the attempt to deregister the client.
  1558. --*/
  1559. {
  1560. return (TdiDeregisterPnPHandlers(
  1561. BindingHandle));
  1562. }
  1563. NTSTATUS
  1564. TdiRegisterDeviceObject(
  1565. IN PUNICODE_STRING DeviceName,
  1566. OUT HANDLE *RegistrationHandle
  1567. )
  1568. /*++
  1569. Routine Description:
  1570. Called when a TDI provider wants to register a device object.
  1571. Arguments:
  1572. DeviceName - Name of the device to be registered.
  1573. RegistrationHandle - A handle we pass back to the provider,
  1574. identifying this registration.
  1575. Return Value:
  1576. The status of the attempt to register the provider.
  1577. --*/
  1578. {
  1579. PTDI_PROVIDER_RESOURCE NewResource;
  1580. NTSTATUS Status;
  1581. PWCHAR Buffer;
  1582. int i;
  1583. TDI_DEBUG(FUNCTION, ("++ TdiRegisterDeviceObject\n"));
  1584. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1585. TdiInitialize();
  1586. // First, try and allocate the needed resource.
  1587. NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePoolWithTag(
  1588. NonPagedPool,
  1589. sizeof(TDI_PROVIDER_RESOURCE),
  1590. 'cIDT'
  1591. );
  1592. // If we couldn't get it, fail the request.
  1593. if (NewResource == NULL) {
  1594. return STATUS_INSUFFICIENT_RESOURCES;
  1595. }
  1596. RtlZeroMemory(NewResource, sizeof(TDI_PROVIDER_RESOURCE));
  1597. // Try and get a buffer to hold the name.
  1598. Buffer = (PWCHAR)ExAllocatePoolWithTag(
  1599. NonPagedPool,
  1600. DeviceName->MaximumLength,
  1601. 'dIDT'
  1602. );
  1603. if (Buffer == NULL) {
  1604. ExFreePool(NewResource);
  1605. return STATUS_INSUFFICIENT_RESOURCES;
  1606. }
  1607. // Fill in the basic stuff.
  1608. NewResource->Common.Type = TDI_RESOURCE_DEVICE;
  1609. NewResource->Specific.Device.DeviceName.MaximumLength =
  1610. DeviceName->MaximumLength;
  1611. NewResource->Specific.Device.DeviceName.Buffer = Buffer;
  1612. RtlCopyUnicodeString(
  1613. &NewResource->Specific.Device.DeviceName,
  1614. DeviceName
  1615. );
  1616. *RegistrationHandle = (HANDLE)NewResource;
  1617. TDI_DEBUG(PROVIDERS, ("Registering Device Object\n"));
  1618. Status = TdiHandleSerializedRequest(
  1619. NewResource,
  1620. TDI_REGISTER_DEVICE_PNP
  1621. );
  1622. CTEAssert(STATUS_SUCCESS == Status);
  1623. if (STATUS_SUCCESS != Status) {
  1624. ExFreePool(Buffer);
  1625. ExFreePool(NewResource);
  1626. *RegistrationHandle = NULL;
  1627. }
  1628. TDI_DEBUG(FUNCTION, ("-- TdiRegisterDeviceObject\n"));
  1629. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1630. TDI_LOG(LOG_REGISTER, ("-RegisterDeviceObject rc=%X h=%X %wZ\n",
  1631. Status, NewResource, DeviceName));
  1632. return Status;
  1633. }
  1634. NTSTATUS
  1635. TdiDeregisterDeviceObject(
  1636. IN HANDLE RegistrationHandle
  1637. )
  1638. /*++
  1639. Routine Description:
  1640. This function is called when a TDI provider want's to deregister
  1641. a device object.
  1642. Arguments:
  1643. RegistrationHandle - A handle we passed back to the provider
  1644. on the register call. This is really
  1645. a pointer to the resource element.
  1646. Return Value:
  1647. The status of the attempt to deregister the provider.
  1648. --*/
  1649. {
  1650. NTSTATUS Status;
  1651. TDI_DEBUG(FUNCTION, ("++ TdiDERegisterDeviceObject\n"));
  1652. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1653. CTEAssert(RegistrationHandle);
  1654. Status = TdiHandleSerializedRequest(
  1655. RegistrationHandle,
  1656. TDI_DEREGISTER_DEVICE_PNP
  1657. );
  1658. TDI_DEBUG(FUNCTION, ("-- TdiDERegisterDeviceObject\n"));
  1659. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1660. TDI_LOG(LOG_REGISTER, ("TdiDeregisterDeviceObject rc=%d\n", Status));
  1661. return Status;
  1662. }
  1663. NTSTATUS
  1664. TdiRegisterAddressChangeHandler(
  1665. IN TDI_ADD_ADDRESS_HANDLER AddHandler,
  1666. IN TDI_DEL_ADDRESS_HANDLER DeleteHandler,
  1667. OUT HANDLE *BindingHandle
  1668. )
  1669. /*++
  1670. Routine Description:
  1671. This function is called when a TDI client wants to register for
  1672. notification of the arrival of network addresses. We allocate a
  1673. TDI_NOTIFY_ELEMENT for the provider and then call the serialized
  1674. worker routine to do the real work.
  1675. Arguments:
  1676. AddHandler - A pointer to the routine to be called when
  1677. a new address arrives.
  1678. DeleteHandler - A pointer to the routine to be called when an
  1679. address leaves.
  1680. BindingHandle - A handle we pass back that identifies this
  1681. client to us.
  1682. Return Value:
  1683. The status of the attempt to register the client.
  1684. --*/
  1685. {
  1686. TDI_CLIENT_INTERFACE_INFO tdiInterface;
  1687. //
  1688. // Make sure Tdi is intialized. If there are no pnp transports, then this is
  1689. // called by the tdi client and if tdi is not initialized, it is toast
  1690. // Multiple calls to TdiIntialize are safe since only the first one does
  1691. // the real work
  1692. //
  1693. TdiInitialize();
  1694. RtlZeroMemory(&tdiInterface, sizeof(tdiInterface));
  1695. tdiInterface.MajorTdiVersion = 1;
  1696. tdiInterface.MinorTdiVersion = 0;
  1697. tdiInterface.AddAddressHandler = AddHandler;
  1698. tdiInterface.DelAddressHandler = DeleteHandler;
  1699. return (TdiRegisterPnPHandlers(
  1700. &tdiInterface,
  1701. sizeof(tdiInterface),
  1702. BindingHandle
  1703. ));
  1704. }
  1705. NTSTATUS
  1706. TdiDeregisterAddressChangeHandler(
  1707. IN HANDLE BindingHandle
  1708. )
  1709. /*++
  1710. Routine Description:
  1711. This function is called when a TDI client wants to deregister a
  1712. previously registered address change notification handler. All we
  1713. really do is call TdiHandleSerializedRequest, which does the hard work.
  1714. Arguments:
  1715. BindingHandle - A handle we passed back to the client
  1716. on the register call. This is really
  1717. a pointer to the notify element.
  1718. Return Value:
  1719. The status of the attempt to deregister the client.
  1720. --*/
  1721. {
  1722. return (TdiDeregisterPnPHandlers(
  1723. BindingHandle));
  1724. }
  1725. NTSTATUS
  1726. TdiRegisterNetAddress(
  1727. IN PTA_ADDRESS Address,
  1728. IN PUNICODE_STRING DeviceName,
  1729. IN PTDI_PNP_CONTEXT Context2,
  1730. OUT HANDLE *RegistrationHandle
  1731. )
  1732. /*++
  1733. Routine Description:
  1734. Called when a TDI provider wants to register a new net address.
  1735. Arguments:
  1736. Address - New net address to be registered.
  1737. Context1 - Protocol defined context1. For example,
  1738. TCPIP will pass the list of IP addresses associated
  1739. with this device.
  1740. Context2 - Protocol defined context2. For example, TCPIP may pass
  1741. the PDO of the device on which this PnP event is being notified.
  1742. RegistrationHandle - A handle we pass back to the provider,
  1743. identifying this registration.
  1744. Return Value:
  1745. The status of the attempt to register the provider.
  1746. --*/
  1747. {
  1748. PTDI_PROVIDER_RESOURCE NewResource;
  1749. NTSTATUS Status;
  1750. TDI_DEBUG(FUNCTION, ("++ TdiRegisterNetAddress\n"));
  1751. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1752. // First, try and allocate the needed resource.
  1753. NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePoolWithTag(
  1754. NonPagedPool,
  1755. FIELD_OFFSET(
  1756. TDI_PROVIDER_RESOURCE,
  1757. Specific.NetAddress
  1758. ) +
  1759. FIELD_OFFSET(TA_ADDRESS, Address) +
  1760. Address->AddressLength,
  1761. 'eIDT'
  1762. );
  1763. // If we couldn't get it, fail the request.
  1764. if (NewResource == NULL) {
  1765. return STATUS_INSUFFICIENT_RESOURCES;
  1766. }
  1767. RtlZeroMemory(
  1768. NewResource,
  1769. FIELD_OFFSET(
  1770. TDI_PROVIDER_RESOURCE,
  1771. Specific.NetAddress
  1772. ) +
  1773. FIELD_OFFSET(
  1774. TA_ADDRESS,
  1775. Address
  1776. ) +
  1777. Address->AddressLength
  1778. );
  1779. // Fill in the basic stuff.
  1780. NewResource->Common.Type = TDI_RESOURCE_NET_ADDRESS;
  1781. NewResource->Specific.NetAddress.Address.AddressLength =
  1782. Address->AddressLength;
  1783. NewResource->Specific.NetAddress.Address.AddressType =
  1784. Address->AddressType;
  1785. RtlCopyMemory(
  1786. NewResource->Specific.NetAddress.Address.Address,
  1787. Address->Address,
  1788. Address->AddressLength
  1789. );
  1790. *RegistrationHandle = (HANDLE)NewResource;
  1791. // Now call HandleBindRequest to handle this one.
  1792. // we have to fill in the contexts here
  1793. if (DeviceName) {
  1794. NewResource->DeviceName.Buffer = ExAllocatePoolWithTag(
  1795. NonPagedPool,
  1796. DeviceName->MaximumLength,
  1797. 'uIDT'
  1798. );
  1799. if (NULL == NewResource->DeviceName.Buffer) {
  1800. ExFreePool(NewResource);
  1801. return STATUS_INSUFFICIENT_RESOURCES;
  1802. }
  1803. RtlCopyMemory(
  1804. NewResource->DeviceName.Buffer,
  1805. DeviceName->Buffer,
  1806. DeviceName->MaximumLength
  1807. );
  1808. NewResource->DeviceName.Length = DeviceName->Length;
  1809. NewResource->DeviceName.MaximumLength = DeviceName->MaximumLength;
  1810. } else {
  1811. NewResource->DeviceName.Buffer = NULL;
  1812. }
  1813. if (Context2) {
  1814. NewResource->Context2 = ExAllocatePoolWithTag(
  1815. NonPagedPool,
  1816. FIELD_OFFSET(TDI_PNP_CONTEXT, ContextData)
  1817. + Context2->ContextSize,
  1818. 'vIDT'
  1819. );
  1820. if (NULL == NewResource->Context2) {
  1821. if (NewResource->DeviceName.Buffer) {
  1822. ExFreePool(NewResource->DeviceName.Buffer);
  1823. }
  1824. ExFreePool(NewResource);
  1825. return STATUS_INSUFFICIENT_RESOURCES;
  1826. }
  1827. NewResource->Context2->ContextType = Context2->ContextType;
  1828. NewResource->Context2->ContextSize = Context2->ContextSize;
  1829. RtlCopyMemory(
  1830. NewResource->Context2->ContextData,
  1831. Context2->ContextData,
  1832. Context2->ContextSize
  1833. );
  1834. } else {
  1835. NewResource->Context2 = NULL;
  1836. }
  1837. Status = TdiHandleSerializedRequest(
  1838. NewResource,
  1839. TDI_REGISTER_ADDRESS_PNP
  1840. );
  1841. CTEAssert(STATUS_SUCCESS == Status);
  1842. if (STATUS_SUCCESS != Status) {
  1843. *RegistrationHandle = NULL;
  1844. TDI_DEBUG(ERROR, ("Freeing Contexts due to failure!!\n"));
  1845. if (NewResource->DeviceName.Buffer) {
  1846. TDI_DEBUG(ERROR, ("Freeing context1: %x", NewResource->DeviceName));
  1847. ExFreePool(NewResource->DeviceName.Buffer);
  1848. NewResource->DeviceName.Buffer = NULL;
  1849. }
  1850. if (NewResource->Context2) {
  1851. TDI_DEBUG(ERROR, ("Freeing context2: %x", NewResource->Context2));
  1852. ExFreePool(NewResource->Context2);
  1853. NewResource->Context2 = NULL;
  1854. }
  1855. TDI_DEBUG(ERROR, ("Freeing Provider: %x", NewResource));
  1856. ExFreePool(NewResource);
  1857. }
  1858. TDI_DEBUG(FUNCTION, ("-- TdiRegisterNetAddress\n"));
  1859. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1860. TDI_LOG(LOG_REGISTER, ("-RegisterNetAddress rc=%d h=%X %wZ\n",
  1861. Status, *RegistrationHandle, DeviceName));
  1862. return Status;
  1863. }
  1864. NTSTATUS
  1865. TdiDeregisterNetAddress(
  1866. IN HANDLE RegistrationHandle
  1867. )
  1868. /*++
  1869. Routine Description:
  1870. This function is called when a TDI provider wants to deregister
  1871. a net addres.
  1872. Arguments:
  1873. RegistrationHandle - A handle we passed back to the provider
  1874. on the register call. This is really
  1875. a pointer to the resource element.
  1876. Return Value:
  1877. The status of the attempt to deregister the provider.
  1878. --*/
  1879. {
  1880. NTSTATUS Status;
  1881. TDI_DEBUG(FUNCTION, ("++ TdiDERegisterNetAddress\n"));
  1882. CTEAssert(RegistrationHandle);
  1883. if (NULL == RegistrationHandle) {
  1884. TDI_DEBUG(ERROR, ("NULL Address Deregistration\n"));
  1885. }
  1886. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1887. CTEAssert(((PTDI_PROVIDER_RESOURCE)RegistrationHandle)->Common.Linkage.Flink != (PLIST_ENTRY)UlongToPtr(0xabababab));
  1888. CTEAssert(((PTDI_PROVIDER_RESOURCE)RegistrationHandle)->Common.Linkage.Blink != (PLIST_ENTRY)UlongToPtr(0xefefefef));
  1889. Status = TdiHandleSerializedRequest(
  1890. RegistrationHandle,
  1891. TDI_DEREGISTER_ADDRESS_PNP
  1892. );
  1893. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1894. TDI_DEBUG(FUNCTION, ("-- TdiDERegisterNetAddress\n"));
  1895. return Status;
  1896. }
  1897. // The PnP/PM extension code
  1898. NTSTATUS
  1899. TdiRegisterPnPHandlers(
  1900. IN PTDI_CLIENT_INTERFACE_INFO ClientInterfaceInfo,
  1901. IN ULONG InterfaceInfoSize,
  1902. OUT HANDLE *BindingHandle
  1903. )
  1904. /*++
  1905. Routine Description:
  1906. This function is called when a TDI client wants to register
  1907. its set of PnP/PM handlers
  1908. Arguments:
  1909. ClientName
  1910. BindingHandler
  1911. AddAddressHandler
  1912. DelAddressHandler
  1913. PowerHandler
  1914. BindingHandle
  1915. Return Value:
  1916. The status of the client's attempt to register the handlers.
  1917. --*/
  1918. {
  1919. PTDI_NOTIFY_PNP_ELEMENT NewElement;
  1920. NTSTATUS Status;
  1921. PWCHAR Buffer = NULL;
  1922. TDI_DEBUG(FUNCTION, ("++ TdiRegisterPnPHandlers\n"));
  1923. //
  1924. // Check that this is a TDI 2.0 Client
  1925. //
  1926. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1927. if (ClientInterfaceInfo->MajorTdiVersion > 2)
  1928. {
  1929. TDI_DEBUG(PROVIDERS, ("TDI Client: Bad Version!\n"));
  1930. return TDI_STATUS_BAD_VERSION;
  1931. }
  1932. //
  1933. // Check that ClientInfoLength is enough.
  1934. //
  1935. if (InterfaceInfoSize < sizeof(TDI_CLIENT_INTERFACE_INFO))
  1936. {
  1937. TDI_DEBUG(PROVIDERS, ("TDI Client Info length was incorrect\n"));
  1938. return TDI_STATUS_BAD_CHARACTERISTICS;
  1939. }
  1940. // This could be the first provider/client to call into TDI.
  1941. TdiInitialize();
  1942. // First, try and allocate the needed resource.
  1943. NewElement = (PTDI_NOTIFY_PNP_ELEMENT)ExAllocatePoolWithTag(
  1944. NonPagedPool,
  1945. sizeof(TDI_NOTIFY_PNP_ELEMENT),
  1946. 'fIDT'
  1947. );
  1948. // If we couldn't get it, fail the request.
  1949. if (NewElement == NULL) {
  1950. return STATUS_INSUFFICIENT_RESOURCES;
  1951. }
  1952. // Allocate space for the deregister exec request.
  1953. NewElement->pTdiDeregisterExecParams = (PTDI_EXEC_PARAMS)ExAllocatePoolWithTag(
  1954. NonPagedPool,
  1955. sizeof(TDI_EXEC_PARAMS),
  1956. 'aIDT'
  1957. );
  1958. if (NULL == NewElement->pTdiDeregisterExecParams) {
  1959. ExFreePool(NewElement);
  1960. return STATUS_INSUFFICIENT_RESOURCES;
  1961. }
  1962. RtlZeroMemory(NewElement->pTdiDeregisterExecParams, sizeof (TDI_EXEC_PARAMS));
  1963. // Try and get a buffer to hold the name, if required.
  1964. if (NULL != ClientInterfaceInfo->ClientName) {
  1965. Buffer = (PWCHAR)ExAllocatePoolWithTag(
  1966. NonPagedPool,
  1967. ClientInterfaceInfo->ClientName->MaximumLength,
  1968. 'gIDT'
  1969. );
  1970. if (Buffer == NULL) {
  1971. ExFreePool(NewElement->pTdiDeregisterExecParams);
  1972. ExFreePool(NewElement);
  1973. return STATUS_INSUFFICIENT_RESOURCES;
  1974. }
  1975. NewElement->ElementName.Length = ClientInterfaceInfo->ClientName->Length;
  1976. NewElement->ElementName.MaximumLength = ClientInterfaceInfo->ClientName->MaximumLength;
  1977. NewElement->ElementName.Buffer = Buffer;
  1978. RtlCopyUnicodeString(
  1979. &NewElement->ElementName,
  1980. ClientInterfaceInfo->ClientName
  1981. );
  1982. } else {
  1983. NewElement->ElementName.Length = 0;
  1984. NewElement->ElementName.MaximumLength = 0;
  1985. NewElement->ElementName.Buffer = NULL;
  1986. }
  1987. // Fill in the basic stuff.
  1988. NewElement->TdiVersion = ClientInterfaceInfo->TdiVersion;
  1989. NewElement->Common.Type = TDI_NOTIFY_PNP_HANDLERS;
  1990. if (TDI_VERSION_ONE == ClientInterfaceInfo->TdiVersion) {
  1991. NewElement->Bind.BindHandler = ClientInterfaceInfo->BindHandler;
  1992. NewElement->Bind.UnbindHandler = ClientInterfaceInfo->UnBindHandler;
  1993. NewElement->AddressElement.AddHandler = ClientInterfaceInfo->AddAddressHandler;
  1994. NewElement->AddressElement.DeleteHandler = ClientInterfaceInfo->DelAddressHandler;
  1995. NewElement->PnpPowerHandler = NULL;
  1996. } else {
  1997. NewElement->BindingHandler = ClientInterfaceInfo->BindingHandler;
  1998. NewElement->AddressElement.AddHandlerV2 = ClientInterfaceInfo->AddAddressHandlerV2;
  1999. NewElement->AddressElement.DeleteHandlerV2 = ClientInterfaceInfo->DelAddressHandlerV2;
  2000. NewElement->PnpPowerHandler = ClientInterfaceInfo->PnPPowerHandler;
  2001. }
  2002. NewElement->ListofBindingsToIgnore = NULL;
  2003. // Now call HandleBindRequest to handle this one.
  2004. *BindingHandle = (HANDLE)NewElement;
  2005. TDI_DEBUG(PROVIDERS, ("TDI.SYS: Registering PnPHandlers ..."));
  2006. Status = TdiHandleSerializedRequest(
  2007. NewElement,
  2008. TDI_REGISTER_HANDLERS_PNP
  2009. );
  2010. CTEAssert(STATUS_SUCCESS == Status);
  2011. if (Status != STATUS_SUCCESS) {
  2012. if (Buffer) {
  2013. ExFreePool(Buffer);
  2014. }
  2015. ExFreePool(NewElement->pTdiDeregisterExecParams);
  2016. ExFreePool(NewElement);
  2017. *BindingHandle = NULL;
  2018. TDI_DEBUG(PROVIDERS, ("... NOT SUCCESS (%x)!\n", Status));
  2019. } else {
  2020. TDI_DEBUG(PROVIDERS, ("... SUCCESS!\n"));
  2021. }
  2022. TDI_DEBUG(FUNCTION, ("-- TdiRegisterPnPHandlers\n"));
  2023. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2024. TDI_LOG(LOG_REGISTER, ("-RegisterPnpHandlers rc=%d h=%X %wZ\n",
  2025. Status, *BindingHandle, ClientInterfaceInfo->ClientName));
  2026. return Status;
  2027. }
  2028. VOID
  2029. TdiPnPPowerComplete(
  2030. IN HANDLE BindingHandle,
  2031. //IN PUNICODE_STRING DeviceName,
  2032. IN PNET_PNP_EVENT PnpPowerEvent,
  2033. IN NTSTATUS Status
  2034. )
  2035. /*++
  2036. Routine Description:
  2037. Arguments:
  2038. Return Value:
  2039. --*/
  2040. {
  2041. PTDI_PROVIDER_RESOURCE Provider, Context, Temp;
  2042. TDI_DEBUG(FUNCTION, ("++ TdiPnPPowerComplete\n"));
  2043. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2044. ASSERT (NULL != PnpPowerEvent);
  2045. Context = *((PTDI_PROVIDER_RESOURCE *) PnpPowerEvent->TdiReserved);
  2046. TDI_LOG(LOG_POWER, ("TdiPnpPowerComplete for %X\n", Context));
  2047. if (NULL != Context) {
  2048. while(Context->PreviousContext) {
  2049. Context = Context->PreviousContext;
  2050. }
  2051. Provider = Context;
  2052. ASSERT(Provider->PowerHandlers != 0);
  2053. //
  2054. // Return Status only if Status was not SUCCESS.
  2055. //
  2056. if (Status != STATUS_SUCCESS) {
  2057. Provider->Status = Status;
  2058. }
  2059. if (!InterlockedDecrement(&Provider->PowerHandlers)) {
  2060. TDI_DEBUG(POWER, ("Calling ProtocolPnPCompletion handler\n"));
  2061. if (Provider->PreviousContext) {
  2062. while (Provider->PreviousContext) {
  2063. Context = Provider;
  2064. Provider = Provider->PreviousContext;
  2065. }
  2066. Context->PreviousContext = NULL; //pop the last guy
  2067. Status = STATUS_SUCCESS;
  2068. } else {
  2069. //
  2070. // This was the only pointer in the TdiReserved and we dont need it anymore
  2071. //
  2072. RtlZeroMemory(PnpPowerEvent->TdiReserved,
  2073. sizeof(PnpPowerEvent->TdiReserved));
  2074. }
  2075. if (Provider->PnPCompleteHandler != NULL) {
  2076. TDI_LOG(LOG_POWER, ("%X, pnp power complete, Call completion at %X\n",
  2077. Provider, Provider->PnPCompleteHandler));
  2078. (*(Provider->PnPCompleteHandler))(
  2079. PnpPowerEvent,
  2080. Status
  2081. );
  2082. TDI_DEBUG(POWER, ("Done calling %wZ's ProtocolPnPCompletion handler\n", &Provider->Specific.Device.DeviceName));
  2083. TDI_DEBUG(POWER, ("The Previous Context at this point is %lx\n", Provider->PreviousContext));
  2084. //DbgBreakPoint();
  2085. }
  2086. ExFreePool(Provider->Specific.Device.DeviceName.Buffer);
  2087. if (Provider->Context1) {
  2088. ExFreePool(Provider->Context1);
  2089. Provider->Context1 = NULL;
  2090. }
  2091. if (Provider->Context2) {
  2092. ExFreePool(Provider->Context2);
  2093. Provider->Context2 = NULL;
  2094. }
  2095. ExFreePool(Provider); // free resources anyways
  2096. } else {
  2097. TDI_DEBUG(POWER, ("There are %d callbacks remaining for %wZ\n", Provider->PowerHandlers, &Provider->Specific.Device.DeviceName));
  2098. }
  2099. } else {
  2100. TDI_DEBUG(POWER, ("This was called separately, so we just return\n"));
  2101. }
  2102. TDI_DEBUG(FUNCTION, ("-- TdiPnPPowerComplete\n"));
  2103. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2104. return ;
  2105. }
  2106. NTSTATUS
  2107. TdiDeregisterPnPHandlers(
  2108. IN HANDLE BindingHandle
  2109. )
  2110. /*++
  2111. Routine Description:
  2112. Arguments:
  2113. Return Value:
  2114. The status of the attempt to deregister the provider.
  2115. --*/
  2116. {
  2117. NTSTATUS Status;
  2118. TDI_DEBUG(FUNCTION, ("++ TdiDERegisterPnPHandlers\n"));
  2119. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2120. Status = TdiHandleSerializedRequest(
  2121. BindingHandle,
  2122. TDI_DEREGISTER_HANDLERS_PNP
  2123. );
  2124. TDI_DEBUG(FUNCTION, ("-- TdiDERegisterPnPHandlers\n"));
  2125. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2126. return Status;
  2127. }
  2128. NTSTATUS
  2129. TdiPnPPowerRequest(
  2130. IN PUNICODE_STRING DeviceName,
  2131. IN PNET_PNP_EVENT PnpPowerEvent,
  2132. IN PTDI_PNP_CONTEXT Context1,
  2133. IN PTDI_PNP_CONTEXT Context2,
  2134. IN ProviderPnPPowerComplete ProtocolCompletionHandler
  2135. )
  2136. /*++
  2137. Routine Description:
  2138. Arguments:
  2139. DeviceName
  2140. PowerEvent: Choice of QUERYPOWER/SETPOWER
  2141. Return Value:
  2142. The status of the attempt to deregister the provider.
  2143. --*/
  2144. {
  2145. PTDI_PROVIDER_RESOURCE NewResource, Context;
  2146. NTSTATUS Status;
  2147. PWCHAR Buffer;
  2148. TDI_DEBUG(FUNCTION, ("++ TdiPnPPowerRequest\n"));
  2149. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2150. CTEAssert(ProtocolCompletionHandler);
  2151. // First, try and allocate the needed resource.
  2152. NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePoolWithTag(
  2153. NonPagedPool,
  2154. sizeof(TDI_PROVIDER_RESOURCE),
  2155. 'hIDT'
  2156. );
  2157. // If we couldn't get it, fail the request.
  2158. if (NewResource == NULL) {
  2159. return STATUS_INSUFFICIENT_RESOURCES;
  2160. }
  2161. // Try and get a buffer to hold the name.
  2162. Buffer = (PWCHAR)ExAllocatePoolWithTag(
  2163. NonPagedPool,
  2164. DeviceName->MaximumLength,
  2165. 'iIDT'
  2166. );
  2167. if (Buffer == NULL) {
  2168. ExFreePool(NewResource);
  2169. return STATUS_INSUFFICIENT_RESOURCES;
  2170. }
  2171. // Fill in the basic stuff.
  2172. NewResource->Common.Type = TDI_RESOURCE_POWER;
  2173. NewResource->Specific.Device.DeviceName.MaximumLength =
  2174. DeviceName->MaximumLength;
  2175. NewResource->Specific.Device.DeviceName.Buffer = Buffer;
  2176. NewResource->PnPCompleteHandler = ProtocolCompletionHandler;
  2177. Context = *((PTDI_PROVIDER_RESOURCE *) PnpPowerEvent->TdiReserved);
  2178. if (NULL == Context) {
  2179. TDI_DEBUG(POWER, ("New NetPnP Event\n"));
  2180. TDI_LOG(LOG_POWER, ("New pnp event %X, %wZ\n", NewResource, DeviceName));
  2181. *((PVOID *) PnpPowerEvent->TdiReserved) = (PVOID) NewResource;
  2182. } else {
  2183. //
  2184. // This NetPnp structure has looped thru before
  2185. // Loop thru and find out the last one.
  2186. //
  2187. while (Context->PreviousContext) {
  2188. Context = Context->PreviousContext;
  2189. }
  2190. Context->PreviousContext = NewResource;
  2191. TDI_LOG(LOG_POWER, ("pnp event linking %X to %X, %wZ\n",
  2192. Context, NewResource, DeviceName));
  2193. }
  2194. NewResource->PreviousContext = NULL;
  2195. NewResource->PnpPowerEvent = PnpPowerEvent;
  2196. NewResource->Status = STATUS_SUCCESS;
  2197. // Note: These pointers must be good for the duration of this call.
  2198. if (Context1) {
  2199. NewResource->Context1 = ExAllocatePoolWithTag(
  2200. NonPagedPool,
  2201. FIELD_OFFSET(TDI_PNP_CONTEXT, ContextData)
  2202. + Context1->ContextSize,
  2203. 'xIDT'
  2204. );
  2205. if (NULL == NewResource->Context1) {
  2206. if (Context) {
  2207. Context->PreviousContext = NULL;
  2208. }
  2209. ExFreePool(NewResource);
  2210. ExFreePool(Buffer);
  2211. return STATUS_INSUFFICIENT_RESOURCES;
  2212. }
  2213. NewResource->Context1->ContextSize = Context1->ContextSize;
  2214. NewResource->Context1->ContextType = Context1->ContextType;
  2215. RtlCopyMemory(
  2216. NewResource->Context1->ContextData,
  2217. Context1->ContextData,
  2218. Context1->ContextSize
  2219. );
  2220. } else {
  2221. NewResource->Context1 = NULL;
  2222. }
  2223. if (Context2) {
  2224. NewResource->Context2 = ExAllocatePoolWithTag(
  2225. NonPagedPool,
  2226. FIELD_OFFSET(TDI_PNP_CONTEXT, ContextData)
  2227. + Context2->ContextSize,
  2228. 'yIDT'
  2229. );
  2230. if (NULL == NewResource->Context2) {
  2231. ExFreePool(Buffer);
  2232. if (NewResource->Context1) {
  2233. ExFreePool(NewResource->Context1);
  2234. }
  2235. if (Context) {
  2236. Context->PreviousContext = NULL;
  2237. }
  2238. ExFreePool(NewResource);
  2239. return STATUS_INSUFFICIENT_RESOURCES;
  2240. }
  2241. NewResource->Context2->ContextSize = Context2->ContextSize;
  2242. NewResource->Context2->ContextType = Context2->ContextType;
  2243. RtlCopyMemory(
  2244. NewResource->Context2->ContextData,
  2245. Context2->ContextData,
  2246. Context2->ContextSize
  2247. );
  2248. } else {
  2249. NewResource->Context2 = NULL;
  2250. }
  2251. RtlCopyUnicodeString(
  2252. &NewResource->Specific.Device.DeviceName,
  2253. DeviceName
  2254. );
  2255. // Now call HandleBindRequest to handle this one.
  2256. Status = TdiHandleSerializedRequest(
  2257. NewResource,
  2258. TDI_REGISTER_PNP_POWER_EVENT
  2259. );
  2260. //
  2261. // If TdiHandleSerialized returns PENDING, then the contexts and Resource
  2262. // structures are freed up in the TdiPnPComplete call.
  2263. //
  2264. if (STATUS_PENDING != Status) {
  2265. Status = NewResource->Status; // The status is stored in the newresource.
  2266. ExFreePool(Buffer);
  2267. if (NewResource->Context1) {
  2268. ExFreePool(NewResource->Context1);
  2269. NewResource->Context1 = NULL;
  2270. }
  2271. if (NewResource->Context2) {
  2272. ExFreePool(NewResource->Context2);
  2273. NewResource->Context2 = NULL;
  2274. }
  2275. if (Context) {
  2276. Context->PreviousContext = NULL;
  2277. }
  2278. TDI_LOG(LOG_POWER, ("%X completed sync, Status %X\n",
  2279. NewResource, Status));
  2280. ExFreePool(NewResource); // free resources anyways
  2281. }
  2282. TDI_DEBUG(FUNCTION, ("-- TdiPnPPowerRequest : %lx\n", Status));
  2283. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2284. return Status;
  2285. }
  2286. // This function is private between NDIS and TDI
  2287. // In TdiInitialize we need to pass a pointer to this function.
  2288. NTSTATUS
  2289. TdiMakeNCPAChanges(
  2290. IN TDI_NCPA_BINDING_INFO NcpaBindingInfo
  2291. )
  2292. {
  2293. return STATUS_NOT_IMPLEMENTED;
  2294. }
  2295. //+---------------------------------------------------------------------------
  2296. // Purpose: Count the number of bytes of a double NULL terminated
  2297. // multi-sz, including all NULLs except for the final terminating
  2298. // NULL.
  2299. //
  2300. // Arguments:
  2301. // pmsz [in] The multi-sz to count bytes for.
  2302. //
  2303. // Returns: The count of bytes.
  2304. //
  2305. ULONG
  2306. TdipCbOfMultiSzSafe (
  2307. IN PCWSTR pmsz)
  2308. {
  2309. ULONG cchTotal = 0;
  2310. ULONG cch;
  2311. // NULL strings have zero length by definition.
  2312. if (!pmsz)
  2313. {
  2314. return 0;
  2315. }
  2316. while (*pmsz)
  2317. {
  2318. cch = wcslen (pmsz) + 1;
  2319. cchTotal += cch;
  2320. pmsz += cch;
  2321. }
  2322. // Return the count of bytes.
  2323. return cchTotal * sizeof (WCHAR);
  2324. }
  2325. //+---------------------------------------------------------------------------
  2326. // Purpose: Search for a string in a multi-sz.
  2327. //
  2328. // Arguments:
  2329. // psz [in] The string to search for.
  2330. // pmsz [in] The multi-sz search in.
  2331. //
  2332. // Returns: TRUE if string was found in the multi-sz.
  2333. //
  2334. BOOLEAN
  2335. TdipIsSzInMultiSzSafe (
  2336. IN PCWSTR pszSearchString,
  2337. IN PCWSTR pmsz)
  2338. {
  2339. if (!pmsz || !pszSearchString)
  2340. {
  2341. return FALSE;
  2342. }
  2343. while (*pmsz)
  2344. {
  2345. if (0 == _wcsicmp (pmsz, pszSearchString))
  2346. {
  2347. return TRUE;
  2348. }
  2349. pmsz += wcslen (pmsz) + 1;
  2350. }
  2351. return FALSE;
  2352. }
  2353. //+---------------------------------------------------------------------------
  2354. // Purpose: Remove strings in a multi-sz list from an array of strings.
  2355. //
  2356. // Arguments:
  2357. // pmszToRemove [in] The strings we need to remove.
  2358. // pszArray [inout] The array of strings to modify.
  2359. // ItemsInArray [in] The number of items in the array.
  2360. // pRemainingItems [out] The number of items remaining in the array
  2361. // after we have removed all items that
  2362. // match pmszToRemove.
  2363. //
  2364. // Returns: nothing
  2365. //
  2366. VOID
  2367. TdipRemoveMultiSzFromSzArray (
  2368. IN PWSTR pmszToRemove,
  2369. IN OUT PWSTR* pszArray,
  2370. IN ULONG ItemsInArray,
  2371. OUT ULONG* pRemainingItems)
  2372. {
  2373. PWSTR pszScan;
  2374. ULONG i, j;
  2375. ULONG ItemsRemoved;
  2376. ASSERT(pRemainingItems);
  2377. *pRemainingItems = ItemsInArray;
  2378. if (!pszArray || !pszArray[0] ||
  2379. !pmszToRemove || !*pmszToRemove)
  2380. {
  2381. return;
  2382. }
  2383. // Go through the string array.
  2384. //
  2385. ItemsRemoved = 0;
  2386. for (i = 0; pszArray[i]; i++)
  2387. {
  2388. // Check each string in the remove multi-sz against
  2389. // the current array string.
  2390. //
  2391. pszScan = pmszToRemove;
  2392. while (*pszScan)
  2393. {
  2394. if (0 == _wcsicmp (pszScan, pszArray[i]))
  2395. {
  2396. ItemsRemoved++;
  2397. // The string needs to be removed.
  2398. // Just move the indexes down one slot.
  2399. //
  2400. for (j = i; pszArray[j]; j++)
  2401. {
  2402. pszArray[j] = pszArray[j + 1];
  2403. }
  2404. // If we removed the last item in the list, get out of the
  2405. // loop. Note that the next entry is also NULL which
  2406. // will cause us to get out of our paraent for loop as
  2407. // well.
  2408. //
  2409. if (!pszArray[i])
  2410. {
  2411. break;
  2412. }
  2413. // Reset the scan string since the current indexed
  2414. // entry is now the next entry. This means we run the
  2415. // scan again.
  2416. pszScan = pmszToRemove;
  2417. }
  2418. else
  2419. {
  2420. pszScan += wcslen (pszScan) + 1;
  2421. }
  2422. }
  2423. }
  2424. // Update the count of items in the array.
  2425. *pRemainingItems = ItemsInArray - ItemsRemoved;
  2426. }
  2427. //+---------------------------------------------------------------------------
  2428. // Purpose: Remove a multi-sz of strings from another multi-sz of strings.
  2429. //
  2430. // Arguments:
  2431. // pmszToRemove [in] The strings to remove.
  2432. // pmszToModify [in] The list to modify.
  2433. //
  2434. // Returns: nothing.
  2435. //
  2436. VOID
  2437. TdipRemoveMultiSzFromMultiSz (
  2438. IN PCWSTR pmszToRemove,
  2439. IN OUT PWSTR pmszToModify)
  2440. {
  2441. BOOLEAN fRemoved;
  2442. PCWSTR pszScan;
  2443. if (!pmszToModify || !pmszToRemove || !*pmszToRemove)
  2444. {
  2445. return;
  2446. }
  2447. // Look for each pmszToRemove string in pmsz. When it is found, move
  2448. // the remaining part of the pmsz over it.
  2449. //
  2450. while (*pmszToModify)
  2451. {
  2452. fRemoved = FALSE;
  2453. pszScan = pmszToRemove;
  2454. while (*pszScan)
  2455. {
  2456. ULONG cchScan = wcslen (pszScan);
  2457. if (0 == _wcsicmp (pmszToModify, pszScan))
  2458. {
  2459. PWSTR pmszRemain = pmszToModify + cchScan + 1;
  2460. // Count the remaining bytes including the final terminator;
  2461. INT cbRemain = TdipCbOfMultiSzSafe (pmszRemain) + sizeof (WCHAR);
  2462. RtlMoveMemory (pmszToModify, pmszRemain, cbRemain);
  2463. fRemoved = TRUE;
  2464. break;
  2465. }
  2466. pszScan += cchScan + 1;
  2467. }
  2468. // If we didn't remove the current modify string, advance our
  2469. // pointer.
  2470. //
  2471. if (!fRemoved)
  2472. {
  2473. pmszToModify += wcslen (pmszToModify) + 1;
  2474. }
  2475. }
  2476. }
  2477. //+---------------------------------------------------------------------------
  2478. // Purpose: Adds a multi-sz of strings to another multi-sz.
  2479. //
  2480. // Arguments:
  2481. // pUniStringToAdd - [in] The Unicode string that contains the multisz.
  2482. // pmszModify [in] The multi-sz to add to.
  2483. //
  2484. // Returns: NT status code. Either STATUS_SUCCESS or
  2485. // STATUS_INSUFFICIENT_RESOURCES
  2486. //
  2487. NTSTATUS
  2488. TdipAddMultiSzToMultiSz (
  2489. IN PUNICODE_STRING pUniStringToAdd,
  2490. IN PCWSTR pmszModify,
  2491. OUT PWSTR* ppmszOut)
  2492. {
  2493. NTSTATUS status = STATUS_SUCCESS;
  2494. PCWSTR pszScan;
  2495. ULONG cbNeeded;
  2496. PCWSTR pmszAdd = NULL;
  2497. ASSERT(ppmszOut);
  2498. // Initialize the output parameters.
  2499. //
  2500. *ppmszOut = NULL;
  2501. pmszAdd = pUniStringToAdd->Buffer;
  2502. ASSERT(pmszAdd);
  2503. // Validate the input - all multisz have 2 End -Of -String
  2504. // characters at the end of the unicode string
  2505. //
  2506. {
  2507. ULONG LenWchar = pUniStringToAdd->Length/2; // Length is in bytes
  2508. if(LenWchar <= 2) // is Multisz long enough for our checks
  2509. {
  2510. return (STATUS_INVALID_PARAMETER);
  2511. }
  2512. if (pmszAdd[LenWchar -1] != 0) // is Multisz null terminated
  2513. {
  2514. return (STATUS_INVALID_PARAMETER);
  2515. }
  2516. if (pmszAdd[LenWchar-2] != 0) // is the last string in multisz null terminated
  2517. {
  2518. return (STATUS_INVALID_PARAMETER);
  2519. }
  2520. }
  2521. // Go through the multi-sz to add and compute how much space we need.
  2522. //
  2523. for (pszScan = pmszAdd, cbNeeded = 0; *pszScan; pszScan += wcslen (pszScan) + 1)
  2524. {
  2525. // Check if the string is already present in the pmszModify.
  2526. // If it is not, add its size to our total.
  2527. if (!TdipIsSzInMultiSzSafe (pszScan, pmszModify))
  2528. {
  2529. cbNeeded += (wcslen (pszScan) + 1) * sizeof (WCHAR);
  2530. }
  2531. }
  2532. // If we have something to add...
  2533. //
  2534. if (cbNeeded)
  2535. {
  2536. ULONG cbDataSize;
  2537. ULONG cbAllocSize;
  2538. PWSTR pmszNew;
  2539. // Get size of current multi-sz.
  2540. cbDataSize = TdipCbOfMultiSzSafe (pmszModify);
  2541. // Enough space for the old data plus the new string and NULL, and for the
  2542. // second trailing NULL (multi-szs are double-terminated)
  2543. cbAllocSize = cbDataSize + cbNeeded + sizeof (WCHAR);
  2544. pmszNew = (PWSTR)ExAllocatePoolWithTag (
  2545. NonPagedPool, cbAllocSize, 'jIDT');
  2546. if (pmszNew)
  2547. {
  2548. ULONG cchOffset;
  2549. cchOffset = cbDataSize / sizeof (WCHAR);
  2550. RtlZeroMemory (pmszNew, cbAllocSize);
  2551. // Copy the current buffer into the new buffer.
  2552. RtlCopyMemory (pmszNew, pmszModify, cbDataSize);
  2553. pszScan = pmszAdd;
  2554. while (*pszScan)
  2555. {
  2556. // Check if the string is already present in the new buffer.
  2557. if (!TdipIsSzInMultiSzSafe (pszScan, pmszNew))
  2558. {
  2559. wcscpy (pmszNew + cchOffset, pszScan);
  2560. cchOffset += wcslen (pmszNew + cchOffset) + 1;
  2561. }
  2562. pszScan += wcslen (pszScan) + 1;
  2563. }
  2564. *ppmszOut = pmszNew;
  2565. }
  2566. else
  2567. {
  2568. status = STATUS_INSUFFICIENT_RESOURCES;
  2569. TDI_DEBUG(ERROR, ("TdipAddMultiSzToMultiSz: Insufficient resources\n"));
  2570. }
  2571. }
  2572. return status;
  2573. }
  2574. //+---------------------------------------------------------------------------
  2575. // Purpose: Prints the contents of a multi-sz list.
  2576. //
  2577. // Arguments:
  2578. // pmsz [in] The multi-sz to print.
  2579. //
  2580. // Returns: nothing.
  2581. //
  2582. #if DBG
  2583. VOID
  2584. TdipPrintMultiSz (
  2585. IN PCWSTR pmsz)
  2586. {
  2587. if (pmsz && *pmsz)
  2588. {
  2589. while (*pmsz)
  2590. {
  2591. TDI_DEBUG(BIND, ("%S\n", pmsz));
  2592. pmsz += wcslen (pmsz) + 1;
  2593. }
  2594. }
  2595. }
  2596. #endif
  2597. BOOLEAN
  2598. TdipMultiSzStrStr(
  2599. PWSTR *TdiClientBindingList,
  2600. PUNICODE_STRING DeviceName
  2601. )
  2602. {
  2603. int i;
  2604. TDI_DEBUG(FUNCTION2, ("++ TdipMultiSzStrStr\n"));
  2605. // look for the string in the multiszstring
  2606. if( TdiClientBindingList == NULL ) {
  2607. return FALSE;
  2608. }
  2609. //
  2610. // Check to see if this device is one of the devices
  2611. // we're interested in.
  2612. //
  2613. for( i=0; TdiClientBindingList[i]; i++ ) {
  2614. if( DeviceName->Length / sizeof( WCHAR ) != wcslen( TdiClientBindingList[i] ) ) {
  2615. continue;
  2616. }
  2617. if( _wcsnicmp( DeviceName->Buffer,
  2618. TdiClientBindingList[i],
  2619. DeviceName->Length / sizeof( WCHAR ) ) == 0 ) {
  2620. break;
  2621. }
  2622. }
  2623. //
  2624. // If we hit the end of the list, then DeviceName is not a device we're
  2625. // interested in.
  2626. //
  2627. if( TdiClientBindingList[i] == NULL ) {
  2628. TDI_DEBUG(FUNCTION2, ("-- TdipMultiSzStrStr: NULL\n"));
  2629. return FALSE;
  2630. }
  2631. TDI_DEBUG(FUNCTION2, ("-- TdipMultiSzStrStr\n"));
  2632. return TRUE;
  2633. }
  2634. VOID
  2635. TdipGetMultiSZList(
  2636. OUT PWSTR **ListPointer,
  2637. IN PWSTR BaseKeyName,
  2638. IN PUNICODE_STRING DeviceName,
  2639. IN PWSTR Linkage,
  2640. IN PWSTR ParameterKeyName,
  2641. OUT PUINT NumEntries
  2642. )
  2643. /*++
  2644. Routine Description:
  2645. This routine queries a registry value key for its MULTI_SZ values.
  2646. Arguments:
  2647. ListPointer - Pointer to receive the pointer.
  2648. ParameterKeyValue - Name of the value parameter to query.
  2649. Return Value:
  2650. none.
  2651. --*/
  2652. {
  2653. UNICODE_STRING unicodeKeyName;
  2654. UNICODE_STRING unicodeParamPath;
  2655. OBJECT_ATTRIBUTES objAttributes;
  2656. HANDLE keyHandle;
  2657. WCHAR ParamBuffer[MAX_UNICODE_BUFLEN];
  2658. ULONG lengthNeeded;
  2659. ULONG i;
  2660. ULONG numberOfEntries;
  2661. ULONG numberOfDefaultEntries = 0;
  2662. NTSTATUS status;
  2663. INT copyflag = 0;
  2664. PWCHAR regEntry;
  2665. PWCHAR dataEntry;
  2666. PWSTR *ptrEntry;
  2667. PCHAR newBuffer;
  2668. PKEY_VALUE_FULL_INFORMATION infoBuffer = NULL;
  2669. TDI_DEBUG(FUNCTION2, ("++ TdipGetMultiSzList\n"));
  2670. unicodeParamPath.Length = 0;
  2671. unicodeParamPath.MaximumLength = MAX_UNICODE_BUFLEN;
  2672. unicodeParamPath.Buffer = ParamBuffer;
  2673. // BaseKeyName :\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
  2674. RtlAppendUnicodeToString(&unicodeParamPath, BaseKeyName);
  2675. // Add DeviceName to it.
  2676. RtlAppendUnicodeStringToString(&unicodeParamPath, DeviceName);
  2677. // Add Linkage to it.
  2678. RtlAppendUnicodeToString(&unicodeParamPath, Linkage);
  2679. RtlInitUnicodeString( &unicodeKeyName, ParameterKeyName );
  2680. InitializeObjectAttributes(
  2681. &objAttributes,
  2682. &unicodeParamPath,
  2683. OBJ_CASE_INSENSITIVE,
  2684. NULL,
  2685. NULL
  2686. );
  2687. status = ZwOpenKey(
  2688. &keyHandle,
  2689. KEY_QUERY_VALUE,
  2690. &objAttributes
  2691. );
  2692. if ( !NT_SUCCESS(status) ) {
  2693. TDI_DEBUG(REGISTRY, ("tdi.sys Cannot open key: %x!!\n", status));
  2694. goto use_default;
  2695. }
  2696. status = ZwQueryValueKey(
  2697. keyHandle,
  2698. &unicodeKeyName,
  2699. KeyValueFullInformation,
  2700. NULL,
  2701. 0,
  2702. &lengthNeeded
  2703. );
  2704. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  2705. NtClose( keyHandle );
  2706. TDI_DEBUG(REGISTRY, ("tdi.sys Cannot query buffer!!\n"));
  2707. goto use_default;
  2708. }
  2709. infoBuffer = ExAllocatePoolWithTag(
  2710. NonPagedPool,
  2711. lengthNeeded,
  2712. 'jIDT'
  2713. );
  2714. if ( infoBuffer == NULL ) {
  2715. NtClose( keyHandle );
  2716. TDI_DEBUG(REGISTRY, ("tdi.sys Cannot alloc buffer!!\n"));
  2717. goto use_default;
  2718. }
  2719. status = ZwQueryValueKey(
  2720. keyHandle,
  2721. &unicodeKeyName,
  2722. KeyValueFullInformation,
  2723. infoBuffer,
  2724. lengthNeeded,
  2725. &lengthNeeded
  2726. );
  2727. NtClose( keyHandle );
  2728. if ( !NT_SUCCESS(status) ) {
  2729. TDI_DEBUG(REGISTRY, ("tdi.sys Cannot query buffer (2) !!\n"));
  2730. goto freepool_and_use_default;
  2731. }
  2732. //
  2733. // Figure out how many entries there are.
  2734. //
  2735. // numberOfEntries should be total number of entries + 1. The extra
  2736. // one is for the NULL sentinel entry.
  2737. //
  2738. lengthNeeded = infoBuffer->DataLength;
  2739. if ( lengthNeeded <= sizeof(WCHAR) ) {
  2740. //
  2741. // No entries on the list. Use default.
  2742. //
  2743. goto freepool_and_use_default;
  2744. }
  2745. dataEntry = (PWCHAR)((PCHAR)infoBuffer + infoBuffer->DataOffset);
  2746. for ( i = 0, regEntry = dataEntry, numberOfEntries = 0;
  2747. i < lengthNeeded;
  2748. i += sizeof(WCHAR) ) {
  2749. if ( *regEntry++ == L'\0' ) {
  2750. numberOfEntries++;
  2751. }
  2752. }
  2753. //
  2754. // Allocate space needed for the array of pointers. This is in addition
  2755. // to the ones in the default list.
  2756. //
  2757. newBuffer = ExAllocatePoolWithTag(
  2758. NonPagedPool,
  2759. lengthNeeded +
  2760. (numberOfEntries) *
  2761. sizeof( PWSTR ),
  2762. 'kIDT'
  2763. );
  2764. if ( newBuffer == NULL ) {
  2765. goto freepool_and_use_default;
  2766. }
  2767. //
  2768. // Copy the names
  2769. //
  2770. regEntry = (PWCHAR)(newBuffer + (numberOfEntries) * sizeof(PWSTR));
  2771. RtlCopyMemory(
  2772. regEntry,
  2773. dataEntry,
  2774. lengthNeeded
  2775. );
  2776. //
  2777. // Free the info buffer
  2778. //
  2779. ExFreePool(infoBuffer);
  2780. ptrEntry = (PWSTR *) newBuffer;
  2781. //
  2782. // Build the array of pointers. If numberOfEntries is 1, then
  2783. // it means that the list is empty.
  2784. //
  2785. if ( numberOfEntries > 1 ) {
  2786. *ptrEntry++ = regEntry++;
  2787. //
  2788. // Skip the first WCHAR and the last 2 NULL terminators.
  2789. //
  2790. for ( i = 3*sizeof(WCHAR) ; i < lengthNeeded ; i += sizeof(WCHAR) ) {
  2791. if ( *regEntry++ == L'\0' ) {
  2792. *ptrEntry++ = regEntry;
  2793. }
  2794. }
  2795. }
  2796. *ptrEntry = NULL;
  2797. *ListPointer = (PWSTR *)newBuffer;
  2798. TDI_DEBUG(FUNCTION2, ("-- TdipGetMultiSzList\n"));
  2799. *NumEntries = numberOfEntries;
  2800. return;
  2801. freepool_and_use_default:
  2802. ExFreePool(infoBuffer); // doesnt get freed otherwise
  2803. use_default:
  2804. *ListPointer = NULL;
  2805. *NumEntries = 0;
  2806. TDI_DEBUG(REGISTRY, ("GetRegStrings: There was an error : returning NULL\r\n"));
  2807. TDI_DEBUG(FUNCTION2, ("-- TdipGetMultiSzList: error\n"));
  2808. return;
  2809. } // TdipGetMultiSZList
  2810. NTSTATUS
  2811. TdiPnPHandler(
  2812. IN PUNICODE_STRING UpperComponent,
  2813. IN PUNICODE_STRING LowerComponent,
  2814. IN PUNICODE_STRING BindList,
  2815. IN PVOID ReconfigBuffer,
  2816. IN UINT ReconfigBufferSize,
  2817. IN UINT Operation
  2818. )
  2819. {
  2820. PTDI_NCPA_BINDING_INFO NdisElement;
  2821. NTSTATUS Status = STATUS_SUCCESS;
  2822. TDI_DEBUG(FUNCTION, ("++ TdiPnPHandler\n"));
  2823. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2824. NdisElement = ExAllocatePoolWithTag(
  2825. NonPagedPool,
  2826. sizeof(TDI_NCPA_BINDING_INFO),
  2827. 'kIDT'
  2828. );
  2829. if (NdisElement == NULL) {
  2830. return STATUS_INSUFFICIENT_RESOURCES;
  2831. }
  2832. NdisElement->TdiClientName = UpperComponent;
  2833. NdisElement->TdiProviderName = LowerComponent;
  2834. NdisElement->BindList = BindList;
  2835. NdisElement->ReconfigBuffer = ReconfigBuffer;
  2836. NdisElement->ReconfigBufferSize = ReconfigBufferSize;
  2837. NdisElement->PnpOpcode = Operation;
  2838. Status = TdiHandleSerializedRequest(
  2839. NdisElement,
  2840. TDI_NDIS_IOCTL_HANDLER_PNP
  2841. );
  2842. ExFreePool(NdisElement);
  2843. TDI_DEBUG(FUNCTION, ("-- TdiPnPHandler\n"));
  2844. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2845. return Status;
  2846. }
  2847. /*++
  2848. Routine Description:
  2849. Call the AddAddress handler of the client along with all the
  2850. registered TDI addresses.
  2851. Arguments:
  2852. Input: Handle to the client context
  2853. Output: NTSTATUS = Success/Failure
  2854. Return Value:
  2855. none.
  2856. --*/
  2857. NTSTATUS
  2858. TdiEnumerateAddresses(
  2859. IN HANDLE BindingHandle
  2860. )
  2861. {
  2862. NTSTATUS Status = STATUS_SUCCESS;
  2863. TDI_DEBUG(FUNCTION, ("++ TdiEnumerateAddresses\n"));
  2864. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2865. // Now call HandleBindRequest to handle this one.
  2866. Status = TdiHandleSerializedRequest(
  2867. BindingHandle,
  2868. TDI_ENUMERATE_ADDRESSES
  2869. );
  2870. TDI_DEBUG(FUNCTION, ("-- TdiEnumerateAddresses\n"));
  2871. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2872. TDI_LOG(LOG_REGISTER, ("-TdiEnumerateAddresses %d\n", Status));
  2873. return Status;
  2874. }
  2875. /*++
  2876. Routine Description:
  2877. Register a generic provider with TDI.
  2878. Each transport is a provider and teh devices that it registers are
  2879. what constitute a transport. When a transport thinks it has all the
  2880. devices ready, it calls TdiNetReady API.
  2881. Arguments:
  2882. Input: Device Name
  2883. Output: Handle to be used in future references.
  2884. Return Value:
  2885. none.
  2886. */
  2887. NTSTATUS
  2888. TdiRegisterProvider(
  2889. PUNICODE_STRING ProviderName,
  2890. HANDLE *ProviderHandle
  2891. )
  2892. {
  2893. PTDI_PROVIDER_RESOURCE NewResource;
  2894. NTSTATUS Status;
  2895. PWCHAR Buffer;
  2896. TDI_DEBUG(FUNCTION, ("++ TdiRegisterProvider\n"));
  2897. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2898. TdiInitialize();
  2899. // make sure that the transports arent screwing us.
  2900. CTEAssert(ProviderName);
  2901. CTEAssert(ProviderName->Buffer);
  2902. CTEAssert(ProviderHandle);
  2903. TDI_DEBUG(PROVIDERS, (" %wZ provider is being Registered\n", ProviderName));
  2904. // First, try and allocate the needed resource.
  2905. NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePoolWithTag(
  2906. NonPagedPool,
  2907. sizeof(TDI_PROVIDER_RESOURCE),
  2908. 'cIDT'
  2909. );
  2910. // If we couldn't get it, fail the request.
  2911. if (NewResource == NULL) {
  2912. return STATUS_INSUFFICIENT_RESOURCES;
  2913. }
  2914. // Try and get a buffer to hold the name.
  2915. Buffer = (PWCHAR)ExAllocatePoolWithTag(
  2916. NonPagedPool,
  2917. ProviderName->MaximumLength,
  2918. 'dIDT'
  2919. );
  2920. if (Buffer == NULL) {
  2921. ExFreePool(NewResource);
  2922. return STATUS_INSUFFICIENT_RESOURCES;
  2923. }
  2924. // Fill in the basic stuff.
  2925. RtlZeroMemory(
  2926. NewResource,
  2927. sizeof(TDI_PROVIDER_RESOURCE)
  2928. );
  2929. NewResource->Common.Type = TDI_RESOURCE_PROVIDER;
  2930. NewResource->Specific.Device.DeviceName.MaximumLength =
  2931. ProviderName->MaximumLength;
  2932. NewResource->Specific.Device.DeviceName.Buffer = Buffer;
  2933. RtlCopyUnicodeString(
  2934. &NewResource->Specific.Device.DeviceName,
  2935. ProviderName
  2936. );
  2937. *ProviderHandle = (HANDLE)NewResource;
  2938. TDI_DEBUG(PROVIDERS, ("Registering Device Object\n"));
  2939. NewResource->Context1 = NULL;
  2940. NewResource->Context2 = NULL;
  2941. Status = TdiHandleSerializedRequest(
  2942. NewResource,
  2943. TDI_REGISTER_PROVIDER_PNP
  2944. );
  2945. CTEAssert(STATUS_SUCCESS == Status);
  2946. if (STATUS_SUCCESS != Status) {
  2947. ExFreePool(Buffer);
  2948. ExFreePool(NewResource);
  2949. *ProviderHandle = NULL;
  2950. }
  2951. TDI_DEBUG(FUNCTION, ("-- TdiRegisterProvider\n"));
  2952. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2953. TDI_LOG(LOG_REGISTER, ("-RegisterProvider rc=%d h=%X %wZ\n",
  2954. Status, *ProviderHandle, ProviderName));
  2955. return Status;
  2956. }
  2957. /*++
  2958. Routine Description:
  2959. Indicate that a registered provider is ready.
  2960. This means that it thinks that all its devices are
  2961. ready to be used.
  2962. Arguments:
  2963. Input: Handle to the client context
  2964. Output: NTSTATUS = Success/Failure
  2965. Return Value:
  2966. none.
  2967. */
  2968. NTSTATUS
  2969. TdiProviderReady(
  2970. HANDLE ProviderHandle
  2971. )
  2972. {
  2973. PTDI_PROVIDER_RESOURCE ProvResource = ProviderHandle;
  2974. NTSTATUS Status;
  2975. TDI_DEBUG(FUNCTION, ("++ TdiProviderReady\n"));
  2976. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2977. CTEAssert(ProviderHandle);
  2978. TDI_DEBUG(PROVIDERS, (" %wZ provider is READY\n", &ProvResource->Specific.Device.DeviceName));
  2979. CTEAssert(!ProvResource->ProviderReady); // doing it twice?
  2980. Status = TdiHandleSerializedRequest(
  2981. ProvResource,
  2982. TDI_PROVIDER_READY_PNP
  2983. );
  2984. TDI_DEBUG(FUNCTION, ("-- TdiProviderReady\n"));
  2985. CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2986. TDI_LOG(LOG_REGISTER, ("-TdiProviderReady rc=%d %wZ\n",
  2987. Status, &ProvResource->Specific.Device.DeviceName));
  2988. return Status;
  2989. }
  2990. /*++
  2991. Routine Description:
  2992. Deregister a generic provider with TDI.
  2993. Arguments:
  2994. Inpute: Handle to the provider structure.
  2995. Return Value:
  2996. none.
  2997. */
  2998. NTSTATUS
  2999. TdiDeregisterProvider(
  3000. HANDLE ProviderHandle
  3001. )
  3002. {
  3003. PTDI_PROVIDER_RESOURCE ProvResource = ProviderHandle;
  3004. NTSTATUS Status;
  3005. TDI_DEBUG(FUNCTION, ("++ TdiDeregisterProvider\n"));
  3006. CTEAssert(ProviderHandle);
  3007. TDI_DEBUG(PROVIDERS, (" %wZ provider is being Deregistered\n", &ProvResource->Specific.Device.DeviceName));
  3008. Status = TdiHandleSerializedRequest(
  3009. ProvResource,
  3010. TDI_DEREGISTER_PROVIDER_PNP
  3011. );
  3012. TDI_DEBUG(FUNCTION, ("-- TdiDeregisterProvider\n"));
  3013. return Status;
  3014. }
  3015. //
  3016. // Input: New Client
  3017. // Pointer to the OpenList
  3018. // Output: success/failure (boolean)
  3019. //
  3020. // This function takes in the new client and builds all the OPEN structures that
  3021. // need to be built (all the providers that this client is bound to). If the
  3022. // provider doesnt exist at this time, we just point it to NULL and change it
  3023. // when the provider (deviceobject) registers itself.
  3024. //
  3025. //
  3026. BOOLEAN
  3027. TdipBuildProviderList(
  3028. PTDI_NOTIFY_PNP_ELEMENT NotifyElement
  3029. )
  3030. {
  3031. ULONG i;
  3032. TDI_DEBUG(FUNCTION2, ("++ TdipBuildOpenList\n"));
  3033. TdipGetMultiSZList(
  3034. &NotifyElement->ListofProviders,
  3035. StrRegTdiBindingsBasicPath,
  3036. &NotifyElement->ElementName,
  3037. StrRegTdiLinkage,
  3038. StrRegTdiBindList,
  3039. &NotifyElement->NumberofEntries
  3040. );
  3041. // look for the string in the multiszstring
  3042. if (NotifyElement->ListofProviders == NULL) {
  3043. return FALSE;
  3044. }
  3045. TDI_DEBUG(BIND, ("Added %d Entries\n", NotifyElement->NumberofEntries));
  3046. TDI_DEBUG(FUNCTION2, ("-- TdipBuildOpenList\n"));
  3047. return TRUE;
  3048. }
  3049. //
  3050. // Takes provider (devicename) and returns a pointer to the
  3051. // internal provider structure if it exists.
  3052. //
  3053. PTDI_PROVIDER_RESOURCE
  3054. LocateProviderContext(
  3055. PUNICODE_STRING ProviderName
  3056. )
  3057. {
  3058. PLIST_ENTRY Current;
  3059. PTDI_PROVIDER_RESOURCE ProviderElement = NULL;
  3060. TDI_DEBUG(FUNCTION2, ("++ LocateProviderContext\n"));
  3061. Current = PnpHandlerProviderList.Flink;
  3062. while (Current != &PnpHandlerProviderList) {
  3063. ProviderElement = CONTAINING_RECORD(
  3064. Current,
  3065. TDI_PROVIDER_RESOURCE,
  3066. Common.Linkage
  3067. );
  3068. if (ProviderElement->Common.Type != TDI_RESOURCE_DEVICE) {
  3069. Current = Current->Flink;
  3070. continue;
  3071. }
  3072. if (!RtlCompareUnicodeString(
  3073. ProviderName,
  3074. &ProviderElement->Specific.Device.DeviceName,
  3075. TRUE)) {
  3076. TDI_DEBUG(BIND, ("Provider is registered with TDI\n"));
  3077. break;
  3078. }
  3079. Current = Current->Flink;
  3080. }
  3081. TDI_DEBUG(FUNCTION2, ("-- LocateProviderContext\n"));
  3082. return ProviderElement;
  3083. }
  3084. #if DBG
  3085. //
  3086. // Cool new memory logging functions added to keep track of the store
  3087. // and forward functionality in TDI (while debugging).
  3088. //
  3089. VOID
  3090. DbgMsgInit()
  3091. {
  3092. First = 0;
  3093. Last = 0;
  3094. CTEInitLock(&DbgLock);
  3095. }
  3096. VOID
  3097. DbgMsg(CHAR *Format, ...)
  3098. {
  3099. va_list Args;
  3100. CTELockHandle LockHandle;
  3101. CHAR Temp[MAX_MSG_LEN];
  3102. LONG numCharWritten;
  3103. va_start(Args, Format);
  3104. numCharWritten = _vsnprintf(Temp, MAX_MSG_LEN, Format, Args);
  3105. if (numCharWritten < 0)
  3106. {
  3107. return;
  3108. }
  3109. // Zero Terminate the string
  3110. //
  3111. Temp[numCharWritten] = '\0';
  3112. if (TdiLogOutput & LOG_OUTPUT_DEBUGGER)
  3113. {
  3114. DbgPrint(Temp);
  3115. }
  3116. if (TdiLogOutput & LOG_OUTPUT_BUFFER)
  3117. {
  3118. CTEGetLock(&DbgLock, &LockHandle);
  3119. RtlZeroMemory(DbgMsgs[Last], MAX_MSG_LEN);
  3120. strcpy(DbgMsgs[Last], Temp);
  3121. Last++;
  3122. if (Last == LOG_MSG_CNT)
  3123. Last = 0;
  3124. if (First == Last) {
  3125. First++;
  3126. if (First == LOG_MSG_CNT)
  3127. First = 0;
  3128. }
  3129. CTEFreeLock(&DbgLock, LockHandle);
  3130. }
  3131. va_end(Args);
  3132. }
  3133. #endif