Leaked source code of windows server 2003
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.

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