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.

1917 lines
46 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. api.c
  5. Abstract:
  6. Exported routines to transports for automatic connection
  7. management.
  8. Author:
  9. Anthony Discolo (adiscolo) 17-Apr-1995
  10. Environment:
  11. Kernel Mode
  12. Revision History:
  13. --*/
  14. #include <ntddk.h>
  15. //#include <ntifs.h>
  16. #include <cxport.h>
  17. #include <tdi.h>
  18. #include <tdikrnl.h>
  19. #include <tdistat.h>
  20. #include <tdiinfo.h>
  21. #include <acd.h>
  22. #include "acdapi.h"
  23. #include "acddefs.h"
  24. #include "request.h"
  25. #include "mem.h"
  26. #include "debug.h"
  27. PACD_DISABLED_ADDRESSES pDisabledAddressesG;
  28. //
  29. // Driver enabled mode. The automatic
  30. // connection system service sets
  31. // this depending on whether a user
  32. // has logged in, and whether there's
  33. // general network connectivity.
  34. //
  35. BOOLEAN fAcdEnabledG;
  36. //
  37. // Spin lock for this module.
  38. //
  39. KSPIN_LOCK AcdSpinLockG;
  40. //
  41. // Event signaled when the AcdNotificationRequestThread
  42. // thread has a notification to process.
  43. //
  44. KEVENT AcdRequestThreadEventG;
  45. //
  46. // This is a list of one irp representing
  47. // a user-space process waiting to create a
  48. // new network connection given an address.
  49. //
  50. LIST_ENTRY AcdNotificationQueueG;
  51. //
  52. // This is a list of ACD_CONNECTION blocks representing
  53. // requests from transports about unsuccessful connection
  54. // attempts. There may be multiple ACD_COMPLETION block
  55. // linked onto the same ACD_CONNECTION, grouped by
  56. // address.
  57. //
  58. LIST_ENTRY AcdConnectionQueueG;
  59. //
  60. // This is a list of ACD_COMPLETION blocks representing
  61. // other requests from transports.
  62. //
  63. LIST_ENTRY AcdCompletionQueueG;
  64. //
  65. // The list of drivers that have binded
  66. // with us.
  67. //
  68. LIST_ENTRY AcdDriverListG;
  69. //
  70. // Count of outstanding irps - we need to maintain this
  71. // to limit the number of outstanding requests to acd
  72. // ow there is a potential of running out of non-paged
  73. // pool memory.
  74. //
  75. LONG lOutstandingRequestsG = 0;
  76. // ULONG count = 0;
  77. #define MAX_ACD_REQUESTS 100
  78. //
  79. // BOOLEAN that enables autoconnect notifications
  80. // from redir/CSC.
  81. //
  82. extern BOOLEAN fAcdEnableRedirNotifs;
  83. //
  84. // Statistics
  85. //
  86. typedef struct _ACD_STATS {
  87. ULONG ulConnects; // connection attempts
  88. ULONG ulCancels; // connection cancels
  89. } ACD_STATS;
  90. ACD_STATS AcdStatsG[ACD_ADDR_MAX];
  91. //
  92. // Forward declarations
  93. //
  94. VOID
  95. AcdPrintAddress(
  96. IN PACD_ADDR pAddr
  97. );
  98. VOID
  99. ClearRequests(
  100. IN KIRQL irql
  101. );
  102. //
  103. // External variables
  104. //
  105. extern ULONG ulAcdOpenCountG;
  106. VOID
  107. SetDriverMode(
  108. IN BOOLEAN fEnable
  109. )
  110. /*++
  111. DESCRIPTION
  112. Set the global driver mode value, and inform
  113. all bound transports of the change.
  114. Note: this call assumes AcdSpinLockG is already
  115. acquired.
  116. ARGUMENTS
  117. fEnable: the new driver mode value
  118. RETURN VALUE
  119. None.
  120. --*/
  121. {
  122. KIRQL dirql;
  123. PLIST_ENTRY pEntry;
  124. PACD_DRIVER pDriver;
  125. //
  126. // Set the new global driver mode value.
  127. //
  128. fAcdEnabledG = fEnable;
  129. //
  130. // Inform all the drivers that have binded
  131. // with us of the new enable mode.
  132. //
  133. for (pEntry = AcdDriverListG.Flink;
  134. pEntry != &AcdDriverListG;
  135. pEntry = pEntry->Flink)
  136. {
  137. pDriver = CONTAINING_RECORD(pEntry, ACD_DRIVER, ListEntry);
  138. KeAcquireSpinLock(&pDriver->SpinLock, &dirql);
  139. pDriver->fEnabled = fEnable;
  140. KeReleaseSpinLock(&pDriver->SpinLock, dirql);
  141. }
  142. } // SetDriverMode
  143. NTSTATUS
  144. AcdEnable(
  145. IN PIRP pIrp,
  146. IN PIO_STACK_LOCATION pIrpSp
  147. )
  148. /*++
  149. DESCRIPTION
  150. Set the enable mode for the driver. This determines
  151. which notifications it will pass up to the automatic
  152. connection system service.
  153. ARGUMENTS
  154. pIrp: a pointer to the irp to be enqueued.
  155. pIrpSp: a pointer to the current irp stack.
  156. RETURN VALUE
  157. STATUS_BUFFER_TOO_SMALL: the supplied user buffer is too small to hold
  158. an ACD_ENABLE_MODE value.
  159. STATUS_SUCCESS: if the enabled bit was set successfully.
  160. --*/
  161. {
  162. KIRQL irql;
  163. BOOLEAN fEnable;
  164. //
  165. // Verify the input buffer is sufficient to hold
  166. // a BOOLEAN structure.
  167. //
  168. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
  169. sizeof (BOOLEAN))
  170. {
  171. return STATUS_BUFFER_TOO_SMALL;
  172. }
  173. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  174. fEnable = *(BOOLEAN *)pIrp->AssociatedIrp.SystemBuffer;
  175. SetDriverMode(fEnable);
  176. //
  177. // Clear all pending requests if
  178. // we are disabling the driver.
  179. //
  180. if (!fEnable)
  181. {
  182. ClearRequests(irql);
  183. if(pDisabledAddressesG->ulNumAddresses > 1)
  184. {
  185. PLIST_ENTRY pEntry;
  186. PACD_DISABLED_ADDRESS pDisabledAddress;
  187. while(pDisabledAddressesG->ulNumAddresses > 1)
  188. {
  189. pEntry = pDisabledAddressesG->ListEntry.Flink;
  190. RemoveEntryList(
  191. pDisabledAddressesG->ListEntry.Flink);
  192. pDisabledAddress =
  193. CONTAINING_RECORD(pEntry, ACD_DISABLED_ADDRESS, ListEntry);
  194. FREE_MEMORY(pDisabledAddress);
  195. pDisabledAddressesG->ulNumAddresses -= 1;
  196. }
  197. }
  198. }
  199. KeReleaseSpinLock(&AcdSpinLockG, irql);
  200. return STATUS_SUCCESS;
  201. } // AcdEnable
  202. VOID
  203. CancelNotification(
  204. IN PDEVICE_OBJECT pDeviceObject,
  205. IN PIRP pIrp
  206. )
  207. /*++
  208. DESCRIPTION
  209. Generic cancel routine for irps on the AcdNotificationQueueG.
  210. ARGUMENTS
  211. pDeviceObject: unused
  212. pIrp: pointer to the irp to be cancelled.
  213. RETURN VALUE
  214. None.
  215. --*/
  216. {
  217. KIRQL irql;
  218. UNREFERENCED_PARAMETER(pDeviceObject);
  219. //
  220. // Mark this irp as cancelled.
  221. //
  222. pIrp->IoStatus.Status = STATUS_CANCELLED;
  223. pIrp->IoStatus.Information = 0;
  224. //
  225. // Remove it from our list.
  226. //
  227. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  228. RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
  229. KeReleaseSpinLock(&AcdSpinLockG, irql);
  230. //
  231. // Release the spinlock Io Subsystem acquired.
  232. //
  233. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  234. //
  235. // Complete the request.
  236. //
  237. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  238. } // CancelNotification
  239. VOID
  240. AcdCancelNotifications()
  241. /*++
  242. DESCRIPTION
  243. Cancel all irps on the AcdNotification queue. Although
  244. technically more than one user address space can be waiting
  245. for these notifications, we allow only one at this time.
  246. ARGUMENTS
  247. None.
  248. RETURN VALUE
  249. None.
  250. --*/
  251. {
  252. KIRQL irql;
  253. PLIST_ENTRY pHead;
  254. PIRP pIrp;
  255. PIO_STACK_LOCATION pIrpSp;
  256. //
  257. // Complete all the irps in the list.
  258. //
  259. while ((pHead = ExInterlockedRemoveHeadList(
  260. &AcdNotificationQueueG,
  261. &AcdSpinLockG)) != NULL)
  262. {
  263. pIrp = CONTAINING_RECORD(pHead, IRP, Tail.Overlay.ListEntry);
  264. //
  265. // Mark this irp as cancelled.
  266. //
  267. pIrp->IoStatus.Status = STATUS_CANCELLED;
  268. pIrp->IoStatus.Information = 0;
  269. //
  270. // Complete the irp.
  271. //
  272. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  273. }
  274. } // AcdCancelNotifications
  275. NTSTATUS
  276. AcdWaitForNotification(
  277. IN PIRP pIrp,
  278. IN PIO_STACK_LOCATION pIrpSp
  279. )
  280. /*++
  281. DESCRIPTION
  282. Enqueue an connection notification irp. This is done
  283. done by the automatic connection system service.
  284. ARGUMENTS
  285. pIrp: a pointer to the irp to be enqueued.
  286. pIrpSp: a pointer to the current irp stack.
  287. RETURN VALUE
  288. STATUS_BUFFER_TOO_SMALL: the supplied user buffer is too small to hold
  289. an ACD_NOTIFICATION structure.
  290. STATUS_PENDING: if the ioctl was successfully enqueued
  291. STATUS_SUCCESS: if there is a notification already available
  292. --*/
  293. {
  294. KIRQL irql, irql2;
  295. PLIST_ENTRY pHead;
  296. PACD_COMPLETION pCompletion;
  297. PACD_NOTIFICATION pNotification;
  298. PEPROCESS pProcess;
  299. //
  300. // Verify the output buffer is sufficient to hold
  301. // an ACD_NOTIFICATION structure - note that this
  302. // should only be called from rasuato service which
  303. // is a 64 bit process on win64. This should never
  304. // be called from a 32 bit process so no thunking is
  305. // done.
  306. //
  307. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  308. sizeof (ACD_NOTIFICATION))
  309. {
  310. return STATUS_BUFFER_TOO_SMALL;
  311. }
  312. IoAcquireCancelSpinLock(&irql);
  313. KeAcquireSpinLock(&AcdSpinLockG, &irql2);
  314. //
  315. // There is no notification available.
  316. // Mark the irp as pending and wait for one.
  317. //
  318. pIrp->IoStatus.Status = STATUS_PENDING;
  319. IoMarkIrpPending(pIrp);
  320. //
  321. // Set the irp's cancel routine.
  322. //
  323. IoSetCancelRoutine(pIrp, CancelNotification);
  324. //
  325. // Append the irp at the end of the
  326. // connection notification list.
  327. //
  328. InsertTailList(&AcdNotificationQueueG, &pIrp->Tail.Overlay.ListEntry);
  329. //
  330. // Signal the request thread there is
  331. // work to do.
  332. //
  333. KeSetEvent(&AcdRequestThreadEventG, 0, FALSE);
  334. KeReleaseSpinLock(&AcdSpinLockG, irql2);
  335. IoReleaseCancelSpinLock(irql);
  336. return STATUS_PENDING;
  337. } // AcdWaitForNotification
  338. BOOLEAN
  339. EqualAddress(
  340. IN PACD_ADDR p1,
  341. IN PACD_ADDR p2
  342. )
  343. {
  344. ULONG i;
  345. if (p1->fType != p2->fType)
  346. return FALSE;
  347. switch (p1->fType) {
  348. case ACD_ADDR_IP:
  349. return (p1->ulIpaddr == p2->ulIpaddr);
  350. case ACD_ADDR_IPX:
  351. return (BOOLEAN)RtlEqualMemory(
  352. &p1->cNode,
  353. &p2->cNode,
  354. ACD_ADDR_IPX_LEN);
  355. case ACD_ADDR_NB:
  356. IF_ACDDBG(ACD_DEBUG_CONNECTION) {
  357. AcdPrint((
  358. "EqualAddress: NB: (%15s,%15s) result=%d\n",
  359. p1->cNetbios,
  360. p2->cNetbios,
  361. RtlEqualMemory(&p1->cNetbios, &p2->cNetbios, ACD_ADDR_NB_LEN - 1)));
  362. }
  363. return (BOOLEAN)RtlEqualMemory(
  364. &p1->cNetbios,
  365. &p2->cNetbios,
  366. ACD_ADDR_NB_LEN - 1);
  367. case ACD_ADDR_INET:
  368. for (i = 0; i < ACD_ADDR_INET_LEN; i++) {
  369. if (p1->szInet[i] != p2->szInet[i])
  370. return FALSE;
  371. if (p1->szInet[i] == '\0' || p2->szInet[i] == '\0')
  372. break;
  373. }
  374. return TRUE;
  375. default:
  376. ASSERT(FALSE);
  377. break;
  378. }
  379. return FALSE;
  380. } // EqualAddress
  381. PACD_CONNECTION
  382. FindConnection(
  383. IN PACD_ADDR pAddr
  384. )
  385. /*++
  386. DESCRIPTION
  387. Search for a connection block with the specified
  388. address.
  389. ARGUMENTS
  390. pAddr: a pointer to the target ACD_ADDR
  391. RETURN VALUE
  392. A PACD_CONNECTION with the specified address, if found;
  393. otherwise NULL.
  394. --*/
  395. {
  396. PLIST_ENTRY pEntry;
  397. PACD_CONNECTION pConnection;
  398. PACD_COMPLETION pCompletion;
  399. for (pEntry = AcdConnectionQueueG.Flink;
  400. pEntry != &AcdConnectionQueueG;
  401. pEntry = pEntry->Flink)
  402. {
  403. pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);
  404. pCompletion = CONTAINING_RECORD(pConnection->CompletionList.Flink, ACD_COMPLETION, ListEntry);
  405. if (EqualAddress(pAddr, &pCompletion->notif.addr))
  406. return pConnection;
  407. }
  408. return NULL;
  409. } // FindConnection
  410. NTSTATUS
  411. AcdConnectionInProgress(
  412. IN PIRP pIrp,
  413. IN PIO_STACK_LOCATION pIrpSp
  414. )
  415. /*++
  416. DESCRIPTION
  417. Refresh the progress indicator for the connection
  418. attempt. If the progress indicator is not updated
  419. by the user
  420. ARGUMENTS
  421. pIrp: a pointer to the irp to be enqueued.
  422. pIrpSp: a pointer to the current irp stack.
  423. RETURN VALUE
  424. STATUS_INVALID_CONNECTION: if there is no connection
  425. attempt in progress.
  426. STATUS_SUCCESS
  427. --*/
  428. {
  429. KIRQL irql;
  430. PACD_STATUS pStatus;
  431. PACD_CONNECTION pConnection;
  432. //
  433. // Verify the input buffer is sufficient to hold
  434. // a BOOLEAN structure.
  435. //
  436. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
  437. sizeof (ACD_STATUS))
  438. {
  439. return STATUS_BUFFER_TOO_SMALL;
  440. }
  441. //
  442. // Get the success code from the
  443. // connection attempt and pass it
  444. // to the completion routine.
  445. //
  446. pStatus = (PACD_STATUS)pIrp->AssociatedIrp.SystemBuffer;
  447. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  448. pConnection = FindConnection(&pStatus->addr);
  449. if (pConnection != NULL)
  450. pConnection->fProgressPing = TRUE;
  451. KeReleaseSpinLock(&AcdSpinLockG, irql);
  452. return (pConnection != NULL) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  453. } // AcdConnectionInProgress
  454. BOOLEAN
  455. AddCompletionToConnection(
  456. IN PACD_COMPLETION pCompletion
  457. )
  458. {
  459. PACD_CONNECTION pConnection;
  460. pConnection = FindConnection(&pCompletion->notif.addr);
  461. //
  462. // If the connection already exists, then add
  463. // the completion request to its list.
  464. //
  465. if (pConnection != NULL) {
  466. InsertTailList(&pConnection->CompletionList, &pCompletion->ListEntry);
  467. return TRUE;
  468. }
  469. //
  470. // This is a connection to a new address.
  471. // Create the connection block, enqueue it,
  472. // and start the connection timer.
  473. //
  474. ALLOCATE_CONNECTION(pConnection);
  475. if (pConnection == NULL) {
  476. // DbgPrint("AddCompletionToConnection: ExAllocatePool failed\n");
  477. return FALSE;
  478. }
  479. pConnection->fNotif = FALSE;
  480. pConnection->fProgressPing = FALSE;
  481. pConnection->fCompleting = FALSE;
  482. pConnection->ulTimerCalls = 0;
  483. pConnection->ulMissedPings = 0;
  484. InitializeListHead(&pConnection->CompletionList);
  485. InsertHeadList(&pConnection->CompletionList, &pCompletion->ListEntry);
  486. InsertTailList(&AcdConnectionQueueG, &pConnection->ListEntry);
  487. return TRUE;
  488. } // AddCompletionToConnection
  489. BOOLEAN
  490. AddCompletionBlock(
  491. IN ULONG ulDriverId,
  492. IN PACD_ADDR pAddr,
  493. IN ULONG ulFlags,
  494. IN PACD_ADAPTER pAdapter,
  495. IN ACD_CONNECT_CALLBACK pProc,
  496. IN USHORT nArgs,
  497. IN PVOID *pArgs
  498. )
  499. /*++
  500. DESCRIPTION
  501. Create a block that represents an outstanding
  502. transport request waiting for an automatic
  503. connection. Link this block into the global
  504. list of outstanding transport requests.
  505. ARGUMENTS
  506. ulDriverId: a unique value for the transport driver
  507. pAddr: the network address of the connection
  508. ulFlags: connection flags
  509. pAdapter: pointer to adapter identifier
  510. pProc: a completion callback procedure
  511. nArgs: the number of parameters passed in pArgs
  512. pArgs: the parameters to pProc
  513. RETURN VALUE
  514. TRUE if successful, FALSE otherwise
  515. --*/
  516. {
  517. PACD_COMPLETION pCompletion;
  518. ULONG i;
  519. if(lOutstandingRequestsG >= MAX_ACD_REQUESTS)
  520. {
  521. /*
  522. if(0 == (count % 5))
  523. {
  524. count += 1;
  525. }
  526. */
  527. return FALSE;
  528. }
  529. ALLOCATE_MEMORY(
  530. sizeof (ACD_COMPLETION) + ((nArgs - 1) * sizeof (PVOID)),
  531. pCompletion);
  532. if (pCompletion == NULL) {
  533. // DbgPrint("AcdAddCompletionBlock: ExAllocatePool failed\n");
  534. return FALSE;
  535. }
  536. //
  537. // Copy the arguments into the information block.
  538. //
  539. pCompletion->ulDriverId = ulDriverId;
  540. pCompletion->fCanceled = FALSE;
  541. pCompletion->fCompleted = FALSE;
  542. RtlCopyMemory(&pCompletion->notif.addr, pAddr, sizeof (ACD_ADDR));
  543. pCompletion->notif.Pid = PsGetCurrentProcessId();
  544. // DbgPrint("ACD: request by Process %lx\n",
  545. // pCompletion->notif.Pid);
  546. pCompletion->notif.ulFlags = ulFlags;
  547. if (pAdapter != NULL) {
  548. RtlCopyMemory(
  549. &pCompletion->notif.adapter,
  550. pAdapter,
  551. sizeof (ACD_ADAPTER));
  552. }
  553. else
  554. RtlZeroMemory(&pCompletion->notif.adapter, sizeof (ACD_ADAPTER));
  555. pCompletion->pProc = pProc;
  556. pCompletion->nArgs = nArgs;
  557. for (i = 0; i < nArgs; i++)
  558. pCompletion->pArgs[i] = pArgs[i];
  559. //
  560. // If this is a unsuccessful connection request,
  561. // then insert it onto the connection queue for
  562. // that address; Otherwise, insert it into the list
  563. // for all other requests.
  564. //
  565. if (ulFlags & ACD_NOTIFICATION_SUCCESS) {
  566. InsertTailList(&AcdCompletionQueueG, &pCompletion->ListEntry);
  567. }
  568. else {
  569. if (!AddCompletionToConnection(pCompletion)) {
  570. FREE_MEMORY(pCompletion);
  571. return FALSE;
  572. }
  573. }
  574. lOutstandingRequestsG++;
  575. //
  576. // Inform the request thread
  577. // there is new work to do.
  578. //
  579. KeSetEvent(&AcdRequestThreadEventG, 0, FALSE);
  580. return TRUE;
  581. } // AddCompletionBlock
  582. VOID
  583. AcdNewConnection(
  584. IN PACD_ADDR pAddr,
  585. IN PACD_ADAPTER pAdapter
  586. )
  587. {
  588. KIRQL irql;
  589. IF_ACDDBG(ACD_DEBUG_CONNECTION) {
  590. AcdPrint(("AcdNewConnection: "));
  591. AcdPrintAddress(pAddr);
  592. AcdPrint(("\n"));
  593. }
  594. //
  595. // If the driver is disabled, then fail
  596. // all requests.
  597. //
  598. if (!fAcdEnabledG) {
  599. IF_ACDDBG(ACD_DEBUG_CONNECTION) {
  600. AcdPrint(("AcdNewConnection: driver disabled\n"));
  601. }
  602. return;
  603. }
  604. //
  605. // Acquire our spin lock.
  606. //
  607. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  608. //
  609. // Allocate a new completion block.
  610. //
  611. AddCompletionBlock(
  612. 0,
  613. pAddr,
  614. ACD_NOTIFICATION_SUCCESS,
  615. pAdapter,
  616. NULL,
  617. 0,
  618. NULL);
  619. //
  620. // Release the spin lock.
  621. //
  622. KeReleaseSpinLock(&AcdSpinLockG, irql);
  623. } // AcdNewConnection
  624. BOOLEAN
  625. AcdStartConnection(
  626. IN ULONG ulDriverId,
  627. IN PACD_ADDR pAddr,
  628. IN ULONG ulFlags,
  629. IN ACD_CONNECT_CALLBACK pProc,
  630. IN USHORT nArgs,
  631. IN PVOID *pArgs
  632. )
  633. /*++
  634. DESCRIPTION
  635. Create a new connection completion block, and enqueue
  636. it on the list of network requests to be completed when
  637. a new network connection has been created.
  638. ARGUMENTS
  639. ulDriverId: a unique value for the transport driver
  640. pAddr: the address of the connection attempt
  641. ulFlags: connection flags
  642. pProc: the transport callback to be called when a new
  643. connection has been created.
  644. nArgs: the number of arguments to pProc.
  645. pArgs: a pointer to an array of pProc's parameters
  646. RETURN VALUE
  647. TRUE if successful, FALSE otherwise.
  648. --*/
  649. {
  650. BOOLEAN fSuccess = FALSE, fFound;
  651. KIRQL irql;
  652. ULONG ulAttributes = 0;
  653. PACD_COMPLETION pCompletion;
  654. PCHAR psz, pszOrg;
  655. ACD_ADDR szOrgAddr;
  656. IF_ACDDBG(ACD_DEBUG_CONNECTION) {
  657. AcdPrint(("AcdStartConnection: "));
  658. AcdPrintAddress(pAddr);
  659. AcdPrint((", ulFlags=0x%x\n", ulFlags));
  660. }
  661. //
  662. // If the driver is disabled, then fail
  663. // all requests.
  664. //
  665. if (!fAcdEnabledG) {
  666. IF_ACDDBG(ACD_DEBUG_CONNECTION) {
  667. AcdPrint(("AcdStartConnection: driver disabled\n"));
  668. }
  669. return FALSE;
  670. }
  671. //
  672. // Validate the address type.
  673. //
  674. if ((ULONG)pAddr->fType >= ACD_ADDR_MAX) {
  675. AcdPrint(("AcdStartConnection: bad address type (%d)\n", pAddr->fType));
  676. return FALSE;
  677. }
  678. //
  679. // Acquire our spin lock.
  680. //
  681. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  682. //
  683. // Update statistics.
  684. //
  685. AcdStatsG[pAddr->fType].ulConnects++;
  686. //
  687. // Allocate a new completion block.
  688. //
  689. fSuccess = AddCompletionBlock(
  690. ulDriverId,
  691. pAddr,
  692. ulFlags,
  693. NULL,
  694. pProc,
  695. nArgs,
  696. pArgs);
  697. //
  698. // Release the spin lock.
  699. //
  700. KeReleaseSpinLock(&AcdSpinLockG, irql);
  701. return fSuccess;
  702. } // AcdStartConnection
  703. BOOLEAN
  704. AcdCancelConnection(
  705. IN ULONG ulDriverId,
  706. IN PACD_ADDR pAddr,
  707. IN ACD_CANCEL_CALLBACK pProc,
  708. IN PVOID pArg
  709. )
  710. /*++
  711. DESCRIPTION
  712. Remove a previously enqueued connection information
  713. block from the list.
  714. ARGUMENTS
  715. ulDriverId: a unique value for the transport driver
  716. pAddr: the address of the connection attempt
  717. pProc: the enumerator procecdure
  718. pArg: the enumerator procedure argument
  719. RETURN VALUE
  720. None.
  721. --*/
  722. {
  723. BOOLEAN fCanceled = FALSE;
  724. KIRQL irql;
  725. PLIST_ENTRY pEntry;
  726. PACD_CONNECTION pConnection;
  727. PACD_COMPLETION pCompletion;
  728. IF_ACDDBG(ACD_DEBUG_CONNECTION) {
  729. AcdPrint(("AcdCancelConnection: ulDriverId=0x%x, "));
  730. AcdPrintAddress(pAddr);
  731. AcdPrint(("\n"));
  732. }
  733. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  734. //
  735. // Enumerate the list looking for
  736. // the information block with the
  737. // supplied parameters.
  738. //
  739. pConnection = FindConnection(pAddr);
  740. if (pConnection != NULL) {
  741. for (pEntry = pConnection->CompletionList.Flink;
  742. pEntry != &pConnection->CompletionList;
  743. pEntry = pEntry->Flink)
  744. {
  745. pCompletion = CONTAINING_RECORD(pEntry, ACD_COMPLETION, ListEntry);
  746. //
  747. // If we have a match, remove it from
  748. // the list and free the information block.
  749. //
  750. if (pCompletion->ulDriverId == ulDriverId &&
  751. !pCompletion->fCanceled &&
  752. !pCompletion->fCompleted)
  753. {
  754. IF_ACDDBG(ACD_DEBUG_CONNECTION) {
  755. AcdPrint((
  756. "AcdCancelConnection: pCompletion=0x%x\n",
  757. pCompletion));
  758. }
  759. if ((*pProc)(
  760. pArg,
  761. pCompletion->notif.ulFlags,
  762. pCompletion->pProc,
  763. pCompletion->nArgs,
  764. pCompletion->pArgs))
  765. {
  766. pCompletion->fCanceled = TRUE;
  767. fCanceled = TRUE;
  768. //
  769. // Update statistics.
  770. //
  771. AcdStatsG[pAddr->fType].ulCancels++;
  772. break;
  773. }
  774. }
  775. }
  776. }
  777. KeReleaseSpinLock(&AcdSpinLockG, irql);
  778. return fCanceled;
  779. } // AcdCancelConnection
  780. VOID
  781. ConnectAddressComplete(
  782. BOOLEAN fSuccess,
  783. PVOID *pArgs
  784. )
  785. {
  786. PIRP pIrp = pArgs[0];
  787. PIO_STACK_LOCATION pIrpSp = pArgs[1];
  788. KIRQL irql;
  789. //
  790. // Complete the request.
  791. //
  792. pIrp->IoStatus.Status = fSuccess ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  793. pIrp->IoStatus.Information = 0;
  794. IoAcquireCancelSpinLock(&irql);
  795. IoSetCancelRoutine(pIrp, NULL);
  796. IoReleaseCancelSpinLock(irql);
  797. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  798. } // ConnectAddressComplete
  799. BOOLEAN
  800. CancelConnectAddressCallback(
  801. IN PVOID pArg,
  802. IN ULONG ulFlags,
  803. IN ACD_CONNECT_CALLBACK pProc,
  804. IN USHORT nArgs,
  805. IN PVOID *pArgs
  806. )
  807. {
  808. return (nArgs == 2 && pArgs[0] == pArg);
  809. } // CancelConnectAddressCallback
  810. VOID
  811. CancelConnectAddress(
  812. PDEVICE_OBJECT pDevice,
  813. PIRP pIrp
  814. )
  815. {
  816. KIRQL irql;
  817. PACD_NOTIFICATION pNotification;
  818. ASSERT(pIrp->Cancel);
  819. //
  820. // Remove our outstanding request.
  821. //
  822. pNotification = (PACD_NOTIFICATION)pIrp->AssociatedIrp.SystemBuffer;
  823. //
  824. // If we can't find the request on the connection
  825. // list, then it has already been completed.
  826. //
  827. if (!AcdCancelConnection(
  828. 0,
  829. &pNotification->addr,
  830. CancelConnectAddressCallback,
  831. pIrp))
  832. {
  833. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  834. return;
  835. }
  836. //
  837. // Mark this irp as cancelled.
  838. //
  839. pIrp->IoStatus.Status = STATUS_CANCELLED;
  840. pIrp->IoStatus.Information = 0;
  841. IoSetCancelRoutine(pIrp, NULL);
  842. //
  843. // Release the spin lock the I/O system acquired.
  844. //
  845. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  846. //
  847. // Complete the I/O request.
  848. //
  849. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  850. } // CancelConnectAddress
  851. BOOLEAN
  852. FDisabledAddress(
  853. IN ACD_ADDR *pAddr
  854. )
  855. {
  856. BOOLEAN bRet = FALSE;
  857. KIRQL irql;
  858. PACD_DISABLED_ADDRESS pDisabledAddress;
  859. PLIST_ENTRY pEntry;
  860. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  861. if(!fAcdEnabledG)
  862. {
  863. KeReleaseSpinLock(&AcdSpinLockG, irql);
  864. return FALSE;
  865. }
  866. for (pEntry = pDisabledAddressesG->ListEntry.Flink;
  867. pEntry != &pDisabledAddressesG->ListEntry;
  868. pEntry = pEntry->Flink)
  869. {
  870. pDisabledAddress =
  871. CONTAINING_RECORD(pEntry, ACD_DISABLED_ADDRESS, ListEntry);
  872. if(pDisabledAddress->EnableAddress.fDisable &&
  873. RtlEqualMemory(
  874. pDisabledAddress->EnableAddress.addr.szInet,
  875. pAddr->szInet,
  876. ACD_ADDR_INET_LEN))
  877. {
  878. bRet = TRUE;
  879. }
  880. }
  881. KeReleaseSpinLock(&AcdSpinLockG, irql);
  882. //DbgPrint("FDisabledAddress: Address %s. Disabled=%d\n",
  883. // pAddr->szInet, bRet);
  884. return bRet;
  885. }
  886. NTSTATUS
  887. AcdConnectAddress(
  888. IN PIRP pIrp,
  889. IN PIO_STACK_LOCATION pIrpSp
  890. )
  891. /*++
  892. DESCRIPTION
  893. Manufacture a call to ourselves to simulate a transport
  894. requesting an automatic connection. This allows a user
  895. address space to initiate an automatic connection.
  896. ARGUMENTS
  897. pIrp: a pointer to the irp to be enqueued.
  898. pIrpSp: a pointer to the current irp stack.
  899. RETURN VALUE
  900. STATUS_BUFFER_TOO_SMALL: the supplied user buffer is too small to hold
  901. an ACD_NOTIFICATION structure.
  902. STATUS_UNSUCCESSFUL: an error occurred initiating the
  903. automatic connection.
  904. STATUS_PENDING: success
  905. --*/
  906. {
  907. NTSTATUS status = STATUS_UNSUCCESSFUL;
  908. KIRQL irql;
  909. PACD_NOTIFICATION pNotification;
  910. PVOID pArgs[2];
  911. ACD_ADDR *pAddr;
  912. ACD_ADAPTER *pAdapter;
  913. ULONG ulFlags;
  914. //
  915. // Verify the input buffer is sufficient to hold
  916. // an ACD_NOTIFICATION (_32) structure.
  917. //
  918. #if defined (_WIN64)
  919. ACD_NOTIFICATION_32 *pNotification32;
  920. if(IoIs32bitProcess(pIrp))
  921. {
  922. if(pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
  923. sizeof(ACD_NOTIFICATION_32))
  924. {
  925. return STATUS_BUFFER_TOO_SMALL;
  926. }
  927. }
  928. else
  929. #endif
  930. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
  931. sizeof (ACD_NOTIFICATION))
  932. {
  933. return STATUS_BUFFER_TOO_SMALL;
  934. }
  935. //
  936. // Doing the whole 32 bit stuff for correctness. The code will
  937. // work even if left alone i.e casting the systembuffer to
  938. // ACD_NOTIFICATION * [raos].
  939. //
  940. #if defined (_WIN64)
  941. if(IoIs32bitProcess(pIrp))
  942. {
  943. pNotification32 = (PACD_NOTIFICATION_32)
  944. pIrp->AssociatedIrp.SystemBuffer;
  945. pAddr = &pNotification32->addr;
  946. pAdapter = &pNotification32->adapter;
  947. ulFlags = pNotification32->ulFlags;
  948. }
  949. else
  950. #endif
  951. {
  952. pNotification = (PACD_NOTIFICATION)pIrp->AssociatedIrp.SystemBuffer;
  953. pAddr = &pNotification->addr;
  954. pAdapter = &pNotification->adapter;
  955. ulFlags = pNotification->ulFlags;
  956. }
  957. if(FDisabledAddress(pAddr))
  958. {
  959. //DbgPrint("AcdConnectAddress: returning because address is disabled\n");
  960. return status;
  961. }
  962. pArgs[0] = pIrp;
  963. pArgs[1] = pIrpSp;
  964. //
  965. // Start the connection.
  966. //
  967. IF_ACDDBG(ACD_DEBUG_CONNECTION) {
  968. AcdPrint(("AcdConnectAddress: "));
  969. AcdPrintAddress(pAddr);
  970. AcdPrint((", ulFlags=0x%x\n", ulFlags));
  971. }
  972. if (ulFlags & ACD_NOTIFICATION_SUCCESS) {
  973. AcdNewConnection(
  974. pAddr,
  975. pAdapter);
  976. status = STATUS_SUCCESS;
  977. }
  978. else {
  979. IoAcquireCancelSpinLock(&irql);
  980. if (AcdStartConnection(
  981. 0,
  982. pAddr,
  983. ulFlags,
  984. ConnectAddressComplete,
  985. 2,
  986. pArgs))
  987. {
  988. //
  989. // We enqueued the request successfully.
  990. // Mark the irp as pending.
  991. //
  992. IoSetCancelRoutine(pIrp, CancelConnectAddress);
  993. IoMarkIrpPending(pIrp);
  994. status = STATUS_PENDING;
  995. }
  996. IoReleaseCancelSpinLock(irql);
  997. }
  998. return status;
  999. } // AcdConnectAddress
  1000. NTSTATUS
  1001. AcdQueryState(
  1002. IN PIRP pIrp,
  1003. IN PIO_STACK_LOCATION pIrpSp
  1004. )
  1005. {
  1006. KIRQL irql;
  1007. if(pIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1008. sizeof(BOOLEAN))
  1009. {
  1010. return STATUS_BUFFER_TOO_SMALL;
  1011. }
  1012. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  1013. if(fAcdEnableRedirNotifs)
  1014. {
  1015. *(BOOLEAN *)pIrp->AssociatedIrp.SystemBuffer = fAcdEnabledG;
  1016. }
  1017. else
  1018. {
  1019. *(BOOLEAN *)pIrp->AssociatedIrp.SystemBuffer = FALSE;
  1020. }
  1021. pIrp->IoStatus.Information = sizeof(BOOLEAN);
  1022. KeReleaseSpinLock(&AcdSpinLockG, irql);
  1023. // KdPrint(("AcdQueryState: returned %d\n",
  1024. // *(BOOLEAN *)pIrp->AssociatedIrp.SystemBuffer));
  1025. return STATUS_SUCCESS;
  1026. }
  1027. VOID
  1028. AcdSignalCompletionCommon(
  1029. IN PACD_CONNECTION pConnection,
  1030. IN BOOLEAN fSuccess
  1031. )
  1032. {
  1033. KIRQL irql;
  1034. PLIST_ENTRY pEntry;
  1035. PACD_COMPLETION pCompletion;
  1036. BOOLEAN fFound;
  1037. IF_ACDDBG(ACD_DEBUG_CONNECTION) {
  1038. AcdPrint((
  1039. "AcdSignalCompletionCommon: pConnection=0x%x, fCompleting=%d\n",
  1040. pConnection,
  1041. pConnection->fCompleting));
  1042. }
  1043. again:
  1044. fFound = FALSE;
  1045. //
  1046. // Acquire our lock and look for
  1047. // the next uncompleted request.
  1048. //
  1049. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  1050. for (pEntry = pConnection->CompletionList.Flink;
  1051. pEntry != &pConnection->CompletionList;
  1052. pEntry = pEntry->Flink)
  1053. {
  1054. pCompletion = CONTAINING_RECORD(pEntry, ACD_COMPLETION, ListEntry);
  1055. IF_ACDDBG(ACD_DEBUG_CONNECTION) {
  1056. AcdPrint((
  1057. "AcdSignalCompletionCommon: pCompletion=0x%x, fCanceled=%d, fCompleted=%d\n",
  1058. pCompletion,
  1059. pCompletion->fCanceled,
  1060. pCompletion->fCompleted));
  1061. }
  1062. //
  1063. // Only complete this request if it
  1064. // hasn't already been completed
  1065. // or canceled.
  1066. //
  1067. if (!pCompletion->fCanceled && !pCompletion->fCompleted) {
  1068. pCompletion->fCompleted = TRUE;
  1069. fFound = TRUE;
  1070. break;
  1071. }
  1072. }
  1073. //
  1074. // If there are no more requests to
  1075. // complete then remove this connection
  1076. // from the connection list and free its
  1077. // memory.
  1078. //
  1079. if (!fFound) {
  1080. RemoveEntryList(&pConnection->ListEntry);
  1081. while (!IsListEmpty(&pConnection->CompletionList)) {
  1082. pEntry = RemoveHeadList(&pConnection->CompletionList);
  1083. pCompletion = CONTAINING_RECORD(pEntry, ACD_COMPLETION, ListEntry);
  1084. FREE_MEMORY(pCompletion);
  1085. lOutstandingRequestsG--;
  1086. }
  1087. FREE_CONNECTION(pConnection);
  1088. //
  1089. // Signal the request thread that
  1090. // the connection list has changed.
  1091. //
  1092. KeSetEvent(&AcdRequestThreadEventG, 0, FALSE);
  1093. }
  1094. //
  1095. // Release our lock.
  1096. //
  1097. KeReleaseSpinLock(&AcdSpinLockG, irql);
  1098. //
  1099. // If we found a request, then
  1100. // call its completion proc.
  1101. //
  1102. if (fFound) {
  1103. IF_ACDDBG(ACD_DEBUG_CONNECTION) {
  1104. AcdPrint(("AcdSignalCompletionCommon: pCompletion=0x%x, ", pCompletion));
  1105. AcdPrintAddress(&pCompletion->notif.addr);
  1106. AcdPrint(("\n"));
  1107. }
  1108. (*pCompletion->pProc)(fSuccess, pCompletion->pArgs);
  1109. //
  1110. // Look for another request.
  1111. //
  1112. goto again;
  1113. }
  1114. } // AcdSignalCompletionCommon
  1115. NTSTATUS
  1116. AcdSignalCompletion(
  1117. IN PIRP pIrp,
  1118. IN PIO_STACK_LOCATION pIrpSp
  1119. )
  1120. /*++
  1121. DESCRIPTION
  1122. For each thread waiting on the AcdCompletionQueueG,
  1123. call the transport-dependent callback to retry the
  1124. connection attempt and complete the irp.
  1125. ARGUMENTS
  1126. pIrp: unused
  1127. pIrpSp: unused
  1128. RETURN VALUE
  1129. STATUS_SUCCESS
  1130. --*/
  1131. {
  1132. KIRQL irql;
  1133. PACD_STATUS pStatus;
  1134. PACD_CONNECTION pConnection;
  1135. BOOLEAN fFound = FALSE;
  1136. //
  1137. // Verify the input buffer is sufficient to hold
  1138. // a BOOLEAN structure.
  1139. //
  1140. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1141. sizeof (ACD_STATUS))
  1142. {
  1143. return STATUS_BUFFER_TOO_SMALL;
  1144. }
  1145. //
  1146. // Get the success code from the
  1147. // connection attempt and pass it
  1148. // to the completion routine.
  1149. //
  1150. pStatus = (PACD_STATUS)pIrp->AssociatedIrp.SystemBuffer;
  1151. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  1152. pConnection = FindConnection(&pStatus->addr);
  1153. if (pConnection != NULL && !pConnection->fCompleting) {
  1154. //
  1155. // Set the completion-in-progress flag so
  1156. // this request cannot be timed-out after
  1157. // we release the spin lock.
  1158. //
  1159. pConnection->fCompleting = TRUE;
  1160. fFound = TRUE;
  1161. }
  1162. KeReleaseSpinLock(&AcdSpinLockG, irql);
  1163. //
  1164. // If we didn't find the connection block,
  1165. // or the completion was already in progress,
  1166. // then return an error.
  1167. //
  1168. if (!fFound)
  1169. return STATUS_UNSUCCESSFUL;
  1170. AcdSignalCompletionCommon(pConnection, pStatus->fSuccess);
  1171. return STATUS_SUCCESS;
  1172. } // AcdSignalCompletion
  1173. NTSTATUS
  1174. AcdpEnableAddress(PACD_ENABLE_ADDRESS pEnableAddress)
  1175. {
  1176. PLIST_ENTRY pEntry = NULL;
  1177. PACD_DISABLED_ADDRESS pDisabledAddress = NULL;
  1178. NTSTATUS status = STATUS_SUCCESS;
  1179. KIRQL irql;
  1180. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  1181. ASSERT(pDisabledAddressesG->ulNumAddresses >= 1);
  1182. if(pDisabledAddressesG->ulNumAddresses == 1)
  1183. {
  1184. pDisabledAddress =
  1185. CONTAINING_RECORD(pDisabledAddressesG->ListEntry.Flink,
  1186. ACD_DISABLED_ADDRESS, ListEntry);
  1187. RtlZeroMemory(&pDisabledAddress->EnableAddress,
  1188. sizeof(ACD_ENABLE_ADDRESS));
  1189. //DbgPrint("AcdEnableAddress: reenabling\n");
  1190. }
  1191. else if(pDisabledAddressesG->ulNumAddresses > 1)
  1192. {
  1193. for (pEntry = pDisabledAddressesG->ListEntry.Flink;
  1194. pEntry != &pDisabledAddressesG->ListEntry;
  1195. pEntry = pEntry->Flink)
  1196. {
  1197. pDisabledAddress =
  1198. CONTAINING_RECORD(pEntry, ACD_DISABLED_ADDRESS, ListEntry);
  1199. if(RtlEqualMemory(
  1200. pDisabledAddress->EnableAddress.addr.szInet,
  1201. pEnableAddress->addr.szInet,
  1202. ACD_ADDR_INET_LEN))
  1203. {
  1204. break;
  1205. }
  1206. }
  1207. if(pEntry != &pDisabledAddressesG->ListEntry)
  1208. {
  1209. //DbgPrint("AcdEnableAddress: removing %s (%p) from disabled list\n",
  1210. // pDisabledAddress->EnableAddress.addr.szInet,
  1211. // pDisabledAddress);
  1212. RemoveEntryList(pEntry);
  1213. pDisabledAddressesG->ulNumAddresses -= 1;
  1214. }
  1215. else
  1216. {
  1217. pEntry = NULL;
  1218. }
  1219. }
  1220. KeReleaseSpinLock(&AcdSpinLockG, irql);
  1221. if(pEntry != NULL)
  1222. {
  1223. FREE_MEMORY(pDisabledAddress);
  1224. }
  1225. return status;
  1226. }
  1227. NTSTATUS
  1228. AcdpDisableAddress(PACD_ENABLE_ADDRESS pEnableAddress)
  1229. {
  1230. PACD_DISABLED_ADDRESS pDisabledAddress;
  1231. NTSTATUS status = STATUS_SUCCESS;
  1232. KIRQL irql;
  1233. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  1234. ASSERT(pDisabledAddressesG->ulNumAddresses >= 1);
  1235. pDisabledAddress =
  1236. CONTAINING_RECORD(pDisabledAddressesG->ListEntry.Flink,
  1237. ACD_DISABLED_ADDRESS, ListEntry);
  1238. if(!pDisabledAddress->EnableAddress.fDisable)
  1239. {
  1240. RtlCopyMemory(&pDisabledAddress->EnableAddress,
  1241. pEnableAddress,
  1242. sizeof(ACD_ENABLE_ADDRESS));
  1243. KeReleaseSpinLock(&AcdSpinLockG, irql);
  1244. }
  1245. else if(pDisabledAddressesG->ulNumAddresses <
  1246. pDisabledAddressesG->ulMaxAddresses)
  1247. {
  1248. KeReleaseSpinLock(&AcdSpinLockG, irql);
  1249. ALLOCATE_MEMORY(sizeof(ACD_DISABLED_ADDRESS), pDisabledAddress);
  1250. if(pDisabledAddress != NULL)
  1251. {
  1252. RtlCopyMemory(&pDisabledAddress->EnableAddress,
  1253. pEnableAddress,
  1254. sizeof(ACD_ENABLE_ADDRESS));
  1255. //DbgPrint("AcdEnableAddress: Adding %p to list \n",
  1256. // pDisabledAddress) ;
  1257. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  1258. InsertTailList(&pDisabledAddressesG->ListEntry,
  1259. &pDisabledAddress->ListEntry);
  1260. pDisabledAddressesG->ulNumAddresses += 1;
  1261. KeReleaseSpinLock(&AcdSpinLockG, irql);
  1262. }
  1263. else
  1264. {
  1265. status = STATUS_INSUFFICIENT_RESOURCES;
  1266. }
  1267. }
  1268. //DbgPrint("AcdDisableAddress: Disabling %s, status=0x%x\n",
  1269. // pEnableAddress->addr.szInet, status);
  1270. return status;
  1271. }
  1272. NTSTATUS
  1273. AcdEnableAddress(
  1274. IN PIRP pIrp,
  1275. IN PIO_STACK_LOCATION pIrpSp
  1276. )
  1277. {
  1278. PACD_ENABLE_ADDRESS pEnableAddress;
  1279. KIRQL irql;
  1280. PACD_DISABLED_ADDRESS pDisabledAddress = NULL;
  1281. NTSTATUS Status = STATUS_SUCCESS;
  1282. if(pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1283. sizeof(ACD_ENABLE_ADDRESS))
  1284. {
  1285. return STATUS_BUFFER_TOO_SMALL;
  1286. }
  1287. if(!fAcdEnabledG)
  1288. {
  1289. return STATUS_UNSUCCESSFUL;
  1290. }
  1291. pEnableAddress = (PACD_ENABLE_ADDRESS)pIrp->AssociatedIrp.SystemBuffer;
  1292. if(pEnableAddress->fDisable)
  1293. {
  1294. Status = AcdpDisableAddress(pEnableAddress);
  1295. }
  1296. else
  1297. {
  1298. Status = AcdpEnableAddress(pEnableAddress);
  1299. }
  1300. //DbgPrint("AcdEnableAddress. status=0x%x\n", Status);
  1301. return Status;
  1302. }
  1303. VOID
  1304. ClearRequests(
  1305. IN KIRQL irql
  1306. )
  1307. /*++
  1308. DESCRIPTION
  1309. Complete all pending requests with failure status.
  1310. This call assumes the AcdSpinLockG is already held,
  1311. and it returns with it held.
  1312. ARGUMENTS
  1313. None.
  1314. RETURN VALUE
  1315. None.
  1316. --*/
  1317. {
  1318. PLIST_ENTRY pHead, pEntry;
  1319. PACD_COMPLETION pCompletion;
  1320. PACD_CONNECTION pConnection;
  1321. again:
  1322. //
  1323. // Complete all pending connections with
  1324. // an error.
  1325. //
  1326. for (pEntry = AcdConnectionQueueG.Flink;
  1327. pEntry != &AcdConnectionQueueG;
  1328. pEntry = pEntry->Flink)
  1329. {
  1330. pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);
  1331. if (!pConnection->fCompleting) {
  1332. pConnection->fCompleting = TRUE;
  1333. //
  1334. // We need to release our lock to
  1335. // complete the request.
  1336. //
  1337. KeReleaseSpinLock(&AcdSpinLockG, irql);
  1338. //
  1339. // Complete the request.
  1340. //
  1341. AcdSignalCompletionCommon(pConnection, FALSE);
  1342. //
  1343. // Check for more uncompleted requests.
  1344. //
  1345. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  1346. goto again;
  1347. }
  1348. }
  1349. //
  1350. // Clear out all other pending requests.
  1351. //
  1352. while (!IsListEmpty(&AcdCompletionQueueG)) {
  1353. pHead = RemoveHeadList(&AcdCompletionQueueG);
  1354. pCompletion = CONTAINING_RECORD(pHead, ACD_COMPLETION, ListEntry);
  1355. FREE_MEMORY(pCompletion);
  1356. lOutstandingRequestsG--;
  1357. }
  1358. } // ClearRequests
  1359. VOID
  1360. AcdReset()
  1361. /*++
  1362. DESCRIPTION
  1363. Complete all pending requests with failure status.
  1364. This is called when the reference count on the driver
  1365. object goes to zero, and prevents stale requests from
  1366. being presented to the system service if it is restarted
  1367. when there are pending completion requests.
  1368. ARGUMENTS
  1369. None.
  1370. RETURN VALUE
  1371. None.
  1372. --*/
  1373. {
  1374. KIRQL irql;
  1375. PLIST_ENTRY pHead, pEntry;
  1376. PACD_COMPLETION pCompletion;
  1377. PACD_CONNECTION pConnection;
  1378. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  1379. //
  1380. // Reset the notification mode to disabled.
  1381. //
  1382. SetDriverMode(FALSE);
  1383. //
  1384. // Complete all pending connections with
  1385. // an error.
  1386. //
  1387. ClearRequests(irql);
  1388. KeReleaseSpinLock(&AcdSpinLockG, irql);
  1389. } // AcdReset
  1390. NTSTATUS
  1391. AcdBind(
  1392. IN PIRP pIrp,
  1393. IN PIO_STACK_LOCATION pIrpSp
  1394. )
  1395. /*++
  1396. DESCRIPTION
  1397. Return the list of entry points to a client
  1398. transport driver.
  1399. ARGUMENTS
  1400. pIrp: a pointer to the irp to be enqueued.
  1401. pIrpSp: a pointer to the current irp stack.
  1402. RETURN VALUE
  1403. STATUS_BUFFER_TOO_SMALL if the supplied SystemBuffer is too
  1404. small. STATUS_SUCCESS otherwise.
  1405. --*/
  1406. {
  1407. NTSTATUS status;
  1408. PACD_DRIVER *ppDriver, pDriver;
  1409. KIRQL irql, dirql;
  1410. //
  1411. // Verify the input buffer a pointer to
  1412. // the driver's ACD_DRIVER structure.
  1413. //
  1414. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1415. sizeof (PACD_DRIVER))
  1416. {
  1417. return STATUS_BUFFER_TOO_SMALL;
  1418. }
  1419. ppDriver = (PACD_DRIVER *)pIrp->AssociatedIrp.SystemBuffer;
  1420. pDriver = *ppDriver;
  1421. #if DBG
  1422. //
  1423. // Selectively bind with some transports.
  1424. //
  1425. switch (pDriver->ulDriverId) {
  1426. case 'Nbf ':
  1427. break;
  1428. case 'Tcp ':
  1429. #ifdef notdef
  1430. DbgPrint("AcdBind: ignoring Tcp\n");
  1431. pDriver->fEnabled = FALSE;
  1432. pIrp->IoStatus.Information = 0;
  1433. return STATUS_SUCCESS;
  1434. #endif
  1435. break;
  1436. case 'Nbi ':
  1437. #ifdef notdef
  1438. DbgPrint("AcdBind: ignoring Nbi\n");
  1439. pDriver->fEnabled = FALSE;
  1440. pIrp->IoStatus.Information = 0;
  1441. return STATUS_SUCCESS;
  1442. #endif
  1443. break;
  1444. }
  1445. #endif
  1446. //
  1447. // Fill in the entry point structure.
  1448. //
  1449. pDriver->lpfnNewConnection = AcdNewConnection;
  1450. pDriver->lpfnStartConnection = AcdStartConnection;
  1451. pDriver->lpfnCancelConnection = AcdCancelConnection;
  1452. //
  1453. // Insert this block into our driver list.
  1454. //
  1455. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  1456. KeAcquireSpinLock(&pDriver->SpinLock, &dirql);
  1457. pDriver->fEnabled = fAcdEnabledG;
  1458. KeReleaseSpinLock(&pDriver->SpinLock, dirql);
  1459. InsertTailList(&AcdDriverListG, &pDriver->ListEntry);
  1460. KeReleaseSpinLock(&AcdSpinLockG, irql);
  1461. //
  1462. // No data should be copied back.
  1463. //
  1464. pIrp->IoStatus.Information = 0;
  1465. return STATUS_SUCCESS;
  1466. } // AcdBind
  1467. NTSTATUS
  1468. AcdUnbind(
  1469. IN PIRP pIrp,
  1470. IN PIO_STACK_LOCATION pIrpSp
  1471. )
  1472. /*++
  1473. DESCRIPTION
  1474. Unbind a client transport driver.
  1475. ARGUMENTS
  1476. pIrp: a pointer to the irp to be enqueued.
  1477. pIrpSp: a pointer to the current irp stack.
  1478. RETURN VALUE
  1479. STATUS_BUFFER_TOO_SMALL if the supplied SystemBuffer is too
  1480. small. STATUS_SUCCESS otherwise.
  1481. --*/
  1482. {
  1483. KIRQL irql, dirql;
  1484. PLIST_ENTRY pEntry, pEntry2;
  1485. PACD_DRIVER *ppDriver, pDriver;
  1486. PACD_CONNECTION pConnection;
  1487. PACD_COMPLETION pCompletion;
  1488. //
  1489. // Verify the input buffer a pointer to
  1490. // the driver's ACD_DRIVER structure.
  1491. //
  1492. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1493. sizeof (PACD_DRIVER))
  1494. {
  1495. return STATUS_BUFFER_TOO_SMALL;
  1496. }
  1497. ppDriver = (PACD_DRIVER *)pIrp->AssociatedIrp.SystemBuffer;
  1498. pDriver = *ppDriver;
  1499. KeAcquireSpinLock(&AcdSpinLockG, &irql);
  1500. //
  1501. // Enumerate the list looking for
  1502. // any connection request initiated by the
  1503. // specified driver.
  1504. //
  1505. for (pEntry = AcdConnectionQueueG.Flink;
  1506. pEntry != &AcdConnectionQueueG;
  1507. pEntry = pEntry->Flink)
  1508. {
  1509. pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);
  1510. for (pEntry2 = pConnection->CompletionList.Flink;
  1511. pEntry2 != &pConnection->CompletionList;
  1512. pEntry2 = pEntry2->Flink)
  1513. {
  1514. pCompletion = CONTAINING_RECORD(pEntry2, ACD_COMPLETION, ListEntry);
  1515. //
  1516. // If we have a match, cancel it.
  1517. //
  1518. if (pCompletion->ulDriverId == pDriver->ulDriverId)
  1519. pCompletion->fCanceled = TRUE;
  1520. }
  1521. }
  1522. //
  1523. // Set this driver's enable mode to ACD_ENABLE_NONE.
  1524. //
  1525. KeAcquireSpinLock(&pDriver->SpinLock, &dirql);
  1526. pDriver->fEnabled = FALSE;
  1527. KeReleaseSpinLock(&pDriver->SpinLock, dirql);
  1528. //
  1529. // Remove this driver from the list.
  1530. //
  1531. RemoveEntryList(&pDriver->ListEntry);
  1532. KeReleaseSpinLock(&AcdSpinLockG, irql);
  1533. //
  1534. // No data should be copied back.
  1535. //
  1536. pIrp->IoStatus.Information = 0;
  1537. return STATUS_SUCCESS;
  1538. } // AcdUnbind
  1539. VOID
  1540. AcdPrintAddress(
  1541. IN PACD_ADDR pAddr
  1542. )
  1543. {
  1544. #if DBG
  1545. PUCHAR puc;
  1546. switch (pAddr->fType) {
  1547. case ACD_ADDR_IP:
  1548. puc = (PUCHAR)&pAddr->ulIpaddr;
  1549. AcdPrint(("IP: %d.%d.%d.%d", puc[0], puc[1], puc[2], puc[3]));
  1550. break;
  1551. case ACD_ADDR_IPX:
  1552. AcdPrint((
  1553. "IPX: %02x:%02x:%02x:%02x:%02x:%02x",
  1554. pAddr->cNode[0],
  1555. pAddr->cNode[1],
  1556. pAddr->cNode[2],
  1557. pAddr->cNode[3],
  1558. pAddr->cNode[4],
  1559. pAddr->cNode[5]));
  1560. break;
  1561. case ACD_ADDR_NB:
  1562. AcdPrint(("NB: %15.15s", pAddr->cNetbios));
  1563. break;
  1564. case ACD_ADDR_INET:
  1565. AcdPrint(("INET: %s", pAddr->szInet));
  1566. break;
  1567. default:
  1568. AcdPrint(("UNKNOWN: ????"));
  1569. break;
  1570. }
  1571. #endif
  1572. } // AcdPrintAddress