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.

825 lines
28 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. ioctl.c
  5. Abstract:
  6. This is the main file for handling DevIOCtl calls for AsyncMAC.
  7. This driver conforms to the NDIS 3.0 interface.
  8. Author:
  9. Thomas J. Dimitri (TommyD) 08-May-1992
  10. Environment:
  11. Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
  12. Revision History:
  13. --*/
  14. #include "asyncall.h"
  15. #ifdef NDIS_NT
  16. #include <ntiologc.h>
  17. #endif
  18. #if DBG
  19. #define __FILE_SIG__ 'tcoi'
  20. #endif
  21. // asyncmac.c will define the global parameters.
  22. VOID
  23. AsyncSendLineUp(
  24. PASYNC_INFO pInfo
  25. )
  26. {
  27. PASYNC_ADAPTER pAdapter = pInfo->Adapter;
  28. NDIS_MAC_LINE_UP MacLineUp;
  29. //
  30. // divide the baud by 100 because NDIS wants it in 100s of bits per sec
  31. //
  32. MacLineUp.LinkSpeed = pInfo->LinkSpeed / 100;
  33. MacLineUp.Quality = pInfo->QualOfConnect;
  34. MacLineUp.SendWindow = ASYNC_WINDOW_SIZE;
  35. MacLineUp.ConnectionWrapperID = pInfo;
  36. MacLineUp.NdisLinkHandle = pInfo;
  37. MacLineUp.NdisLinkContext = pInfo->NdisLinkContext;
  38. //
  39. // Tell the transport above (or really RasHub) that the connection
  40. // is now up. We have a new link speed, frame size, quality of service
  41. //
  42. NdisMIndicateStatus(pAdapter->MiniportHandle,
  43. NDIS_STATUS_WAN_LINE_UP, // General Status.
  44. &MacLineUp, // (baud rate in 100 bps).
  45. sizeof(NDIS_MAC_LINE_UP));
  46. //
  47. // Get the next binding (in case of multiple bindings like BloodHound)
  48. //
  49. pInfo->NdisLinkContext = MacLineUp.NdisLinkContext;
  50. }
  51. NTSTATUS
  52. AsyncIOCtlRequest(
  53. IN PIRP pIrp,
  54. IN PIO_STACK_LOCATION pIrpSp
  55. )
  56. /*++
  57. Routine Description:
  58. This routine takes an irp and checks to see if the IOCtl
  59. is a valid one. If so, it performs the IOCtl and returns
  60. any errors in the process.
  61. Return Value:
  62. The function value is the final status of the IOCtl.
  63. --*/
  64. {
  65. NTSTATUS status;
  66. ULONG funcCode;
  67. PVOID pBufOut;
  68. ULONG InBufLength, OutBufLength;
  69. NDIS_HANDLE hNdisEndPoint;
  70. PASYMAC_CLOSE pCloseStruct;
  71. PASYMAC_OPEN pOpenStruct;
  72. PASYMAC_DCDCHANGE pDCDStruct;
  73. PASYNC_ADAPTER Adapter;
  74. LARGE_INTEGER li ;
  75. //
  76. // Initialize locals.
  77. //
  78. status = STATUS_SUCCESS;
  79. //
  80. // Initialize the I/O Status block
  81. //
  82. InBufLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
  83. OutBufLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  84. funcCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
  85. //
  86. // Validate the function code
  87. //
  88. #ifdef MY_DEVICE_OBJECT
  89. if ( (funcCode >> 16) != FILE_DEVICE_ASYMAC ) {
  90. return STATUS_INVALID_PARAMETER;
  91. }
  92. #else
  93. if ( (funcCode >> 16) != FILE_DEVICE_NETWORK ) {
  94. return STATUS_INVALID_PARAMETER;
  95. }
  96. #endif
  97. //
  98. // Get a quick ptr to the IN/OUT SystemBuffer
  99. //
  100. pBufOut = pIrp->AssociatedIrp.SystemBuffer;
  101. switch ( funcCode ) {
  102. case IOCTL_ASYMAC_OPEN:
  103. DbgTracef(0,("AsyncIOCtlRequest: IOCTL_ASYMAC_OPEN.\n"));
  104. pIrp->IoStatus.Information = sizeof(ASYMAC_OPEN);
  105. if (InBufLength >= sizeof(ASYMAC_OPEN) &&
  106. OutBufLength >= sizeof(ASYMAC_OPEN)) {
  107. pOpenStruct = pBufOut;
  108. } else {
  109. status = STATUS_INFO_LENGTH_MISMATCH;
  110. }
  111. break;
  112. case IOCTL_ASYMAC_CLOSE:
  113. DbgTracef(0,("AsyncIOCtlRequest: IOCTL_ASYMAC_CLOSE\n"));
  114. if ( InBufLength >= sizeof(ASYMAC_CLOSE) ) {
  115. pCloseStruct = pBufOut;
  116. } else {
  117. status = STATUS_INFO_LENGTH_MISMATCH;
  118. }
  119. break;
  120. case IOCTL_ASYMAC_TRACE:
  121. #if DBG
  122. DbgPrint("AsyncIOCtlRequest: IOCTL_ASYMAC_TRACE.\n");
  123. if ( InBufLength >= sizeof(TraceLevel) ) {
  124. CHAR *pTraceLevel=pBufOut;
  125. TraceLevel=*pTraceLevel;
  126. } else {
  127. status = STATUS_INFO_LENGTH_MISMATCH;
  128. }
  129. #endif
  130. return status;
  131. break;
  132. case IOCTL_ASYMAC_DCDCHANGE:
  133. DbgTracef(0,("AsyncIOCtlRequest: IOCTL_ASYMAC_DCDCHANGE.\n"));
  134. if ( InBufLength >= sizeof(ASYMAC_DCDCHANGE) ) {
  135. pDCDStruct = pBufOut;
  136. } else {
  137. status = STATUS_INFO_LENGTH_MISMATCH;
  138. }
  139. break;
  140. default:
  141. status = STATUS_INVALID_DEVICE_REQUEST;
  142. }
  143. //
  144. // Check if we already have an error (like STATUS_INFO_LENGTH_MISMATCH).
  145. //
  146. if ( status != STATUS_SUCCESS ) {
  147. return status;
  148. }
  149. //
  150. // Since most of IOCTL structs are similar
  151. // we get the Adapter and hNdisEndPoint here using
  152. // the StatsStruct (we could several of them)
  153. //
  154. pOpenStruct = pBufOut;
  155. hNdisEndPoint = pOpenStruct->hNdisEndpoint;
  156. //
  157. // No error yet, let's go ahead and grab the global lock...
  158. //
  159. if ((Adapter = GlobalAdapter) == NULL ) {
  160. return ASYNC_ERROR_NO_ADAPTER;
  161. }
  162. // there's a race condition right here that I am
  163. // not bothering to get rid of because it would
  164. // require the removal of this adapter in between
  165. // here (which is, for all intensive purposes, impossible).
  166. // Hmm... now that we have the lock we can do stuff
  167. NdisAcquireSpinLock(&Adapter->Lock);
  168. // Here we do the real work for the function call
  169. switch ( funcCode ) {
  170. case IOCTL_ASYMAC_OPEN:
  171. {
  172. PASYNC_INFO pNewInfo = NULL;
  173. USHORT i;
  174. PDEVICE_OBJECT deviceObject;
  175. PFILE_OBJECT fileObject;
  176. OBJECT_HANDLE_INFORMATION handleInformation;
  177. //
  178. // Get a new AsyncInfo
  179. //
  180. pNewInfo = (PASYNC_INFO)
  181. ExAllocateFromNPagedLookasideList(&AsyncInfoList);
  182. //
  183. // Check if we could not find an open port
  184. //
  185. if ( pNewInfo == NULL ) {
  186. NdisReleaseSpinLock(&Adapter->Lock);
  187. return ASYNC_ERROR_NO_PORT_AVAILABLE;
  188. }
  189. RtlZeroMemory(pNewInfo, sizeof(ASYNC_INFO));
  190. pNewInfo->Adapter = Adapter;
  191. status =
  192. AsyncGetFrameFromPool(pNewInfo, &pNewInfo->AsyncFrame);
  193. if (status != NDIS_STATUS_SUCCESS) {
  194. ExFreeToNPagedLookasideList(&AsyncInfoList, pNewInfo);
  195. NdisReleaseSpinLock(&Adapter->Lock);
  196. return ASYNC_ERROR_NO_PORT_AVAILABLE;
  197. }
  198. KeInitializeEvent(&pNewInfo->DetectEvent,
  199. SynchronizationEvent,
  200. TRUE);
  201. KeInitializeEvent(&pNewInfo->AsyncEvent,
  202. SynchronizationEvent,
  203. TRUE);
  204. // increment the reference count (don't kill this adapter)
  205. InterlockedIncrement(&Adapter->RefCount);
  206. //
  207. // Initialize the refcount on the new asyncinfo block.
  208. //
  209. pNewInfo->RefCount++;
  210. #if DBG
  211. InitializeListHead(&pNewInfo->lePendingRequests);
  212. {
  213. PENDING_REQUEST *_Request = ExAllocatePoolWithTag(NonPagedPool,
  214. sizeof(PENDING_REQUEST),
  215. 'nepA');
  216. if(NULL != _Request)
  217. {
  218. _Request->pvContext = pNewInfo;
  219. _Request->Sig = __FILE_SIG__;
  220. _Request->lineNum = __LINE__;
  221. InsertTailList(&pNewInfo->lePendingRequests, &_Request->le);
  222. } \
  223. }
  224. #endif
  225. pNewInfo->Flags |= ASYNC_FLAG_ASYNCMAC_OPEN;
  226. //
  227. // Set signalled state of event to not-signalled.
  228. //
  229. KeClearEvent(&pNewInfo->AsyncEvent);
  230. // release spin lock so we can do some real work.
  231. NdisReleaseSpinLock(&Adapter->Lock);
  232. //
  233. // Reference the file object so the target device can be found and
  234. // the access rights mask can be used in the following checks for
  235. // callers in user mode. Note that if the handle does not refer to
  236. // a file object, then it will fail.
  237. //
  238. status = ObReferenceObjectByHandle(pOpenStruct->FileHandle,
  239. FILE_READ_DATA | FILE_WRITE_DATA,
  240. *IoFileObjectType,
  241. UserMode,
  242. (PVOID) &fileObject,
  243. &handleInformation);
  244. if (!NT_SUCCESS(status)) {
  245. pNewInfo->PortState = PORT_CLOSED;
  246. NdisAcquireSpinLock(&Adapter->Lock);
  247. // RemoveEntryList(&pNewInfo->Linkage);
  248. ExFreeToNPagedLookasideList(&Adapter->AsyncFrameList,
  249. pNewInfo->AsyncFrame);
  250. NdisReleaseSpinLock(&Adapter->Lock);
  251. ExFreeToNPagedLookasideList(&AsyncInfoList,
  252. pNewInfo);
  253. return ASYNC_ERROR_NO_PORT_AVAILABLE;
  254. }
  255. //
  256. // Init the portinfo block
  257. //
  258. InitializeListHead(&pNewInfo->DDCDQueue);
  259. // Ok, we've gotten this far. We have a port.
  260. // Own port, and check params...
  261. // Nothing can be done to the port until it comes
  262. // out of the PORT_OPENING state.
  263. pNewInfo->PortState = PORT_OPENING;
  264. NdisAllocateSpinLock(&pNewInfo->Lock);
  265. //
  266. // Get the address of the target device object. Note that this was already
  267. // done for the no intermediate buffering case, but is done here again to
  268. // speed up the turbo write path.
  269. //
  270. deviceObject = IoGetRelatedDeviceObject(fileObject);
  271. ObReferenceObject(deviceObject);
  272. // ok, we have a VALID handle of *something*
  273. // we do NOT assume that the handle is anything
  274. // in particular except a device which accepts
  275. // non-buffered IO (no MDLs) Reads and Writes
  276. // set new info...
  277. pNewInfo->Handle = pOpenStruct->FileHandle;
  278. //
  279. // Tuck away link speed for line up
  280. // and timeouts
  281. //
  282. pNewInfo->LinkSpeed = pOpenStruct->LinkSpeed;
  283. //
  284. // Return endpoint to RASMAN
  285. //
  286. pOpenStruct->hNdisEndpoint =
  287. pNewInfo->hNdisEndPoint = pNewInfo;
  288. // Get parameters set from Registry and return our capabilities
  289. pNewInfo->QualOfConnect = pOpenStruct->QualOfConnect;
  290. pNewInfo->PortState = PORT_FRAMING;
  291. pNewInfo->FileObject = fileObject;
  292. pNewInfo->DeviceObject = deviceObject;
  293. pNewInfo->NdisLinkContext = NULL;
  294. //
  295. // Initialize the NDIS_WAN_GET_LINK_INFO structure.
  296. //
  297. pNewInfo->GetLinkInfo.MaxSendFrameSize = DEFAULT_PPP_MAX_FRAME_SIZE;
  298. pNewInfo->GetLinkInfo.MaxRecvFrameSize = DEFAULT_PPP_MAX_FRAME_SIZE;
  299. pNewInfo->GetLinkInfo.HeaderPadding = DEFAULT_PPP_MAX_FRAME_SIZE;
  300. pNewInfo->GetLinkInfo.TailPadding = 4;
  301. pNewInfo->GetLinkInfo.SendFramingBits = PPP_FRAMING;
  302. pNewInfo->GetLinkInfo.RecvFramingBits = PPP_FRAMING;
  303. pNewInfo->GetLinkInfo.SendCompressionBits = 0;
  304. pNewInfo->GetLinkInfo.RecvCompressionBits = 0;
  305. pNewInfo->GetLinkInfo.SendACCM = (ULONG) -1;
  306. pNewInfo->GetLinkInfo.RecvACCM = (ULONG) -1;
  307. //
  308. // Initialize the Extended ACCM information so that we always
  309. // escape 0x7D and 0x7E and we never escape 0x5E
  310. //
  311. pNewInfo->ExtendedACCM[0] = (ULONG) -1;
  312. pNewInfo->ExtendedACCM[3] = (ULONG) 0x60000000;
  313. ASYNC_ZERO_MEMORY(&(pNewInfo->SerialStats), sizeof(SERIAL_STATS));
  314. NdisAcquireSpinLock(&Adapter->Lock);
  315. InsertHeadList(&Adapter->ActivePorts, &pNewInfo->Linkage);
  316. NdisReleaseSpinLock(&Adapter->Lock);
  317. //
  318. // Send a line up to the WAN wrapper.
  319. //
  320. AsyncSendLineUp(pNewInfo);
  321. //
  322. // We send a special IRP to the serial driver to set it in RAS friendly mode
  323. // where it will not complete write requests until the packet has been transmitted
  324. // on the wire. This is mostly important in case of intelligent controllers.
  325. //
  326. pNewInfo->WaitMaskToUse =
  327. (SERIAL_EV_RXFLAG | SERIAL_EV_RLSD | SERIAL_EV_DSR |
  328. SERIAL_EV_RX80FULL | SERIAL_EV_ERR) ;
  329. {
  330. NTSTATUS retStatus;
  331. PASYNC_IO_CTX AsyncIoCtx;
  332. PIRP irp;
  333. irp =
  334. IoAllocateIrp(pNewInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
  335. if (irp != NULL) {
  336. AsyncIoCtx = AsyncAllocateIoCtx(TRUE, pNewInfo);
  337. if (AsyncIoCtx == NULL) {
  338. IoFreeIrp(irp);
  339. irp = NULL;
  340. }
  341. }
  342. if (irp != NULL) {
  343. #define IOCTL_SERIAL_PRIVATE_RAS CTL_CODE(FILE_DEVICE_SERIAL_PORT,4000,METHOD_BUFFERED,FILE_ANY_ACCESS)
  344. InitSerialIrp(irp,
  345. pNewInfo,
  346. IOCTL_SERIAL_PRIVATE_RAS,
  347. sizeof(ULONG));
  348. AsyncIoCtx->WriteBufferingEnabled =
  349. Adapter->WriteBufferingEnabled;
  350. irp->AssociatedIrp.SystemBuffer=
  351. &AsyncIoCtx->WriteBufferingEnabled;
  352. IoSetCompletionRoutine(irp, // irp to use
  353. SerialIoSyncCompletionRoutine, // routine to call when irp is done
  354. AsyncIoCtx, // context to pass routine
  355. TRUE, // call on success
  356. TRUE, // call on error
  357. TRUE); // call on cancel
  358. // Now simply invoke the driver at its dispatch entry with the IRP.
  359. //
  360. KeClearEvent(&AsyncIoCtx->Event);
  361. retStatus = IoCallDriver(pNewInfo->DeviceObject, irp);
  362. if (retStatus == STATUS_PENDING) {
  363. KeWaitForSingleObject(&AsyncIoCtx->Event,
  364. Executive,
  365. KernelMode,
  366. FALSE,
  367. NULL);
  368. retStatus = AsyncIoCtx->IoStatus.Status;
  369. }
  370. IoFreeIrp(irp);
  371. AsyncFreeIoCtx(AsyncIoCtx);
  372. if (retStatus == STATUS_SUCCESS) {
  373. //
  374. // this means that the driver below is DIGI. we should disable setting of the EV_ERR
  375. // flags in this case.
  376. //
  377. pNewInfo->WaitMaskToUse &= ~SERIAL_EV_ERR;
  378. }
  379. }
  380. }
  381. //
  382. // Start the detect framing out with a 6 byte read to get the header
  383. //
  384. pNewInfo->BytesWanted=6;
  385. pNewInfo->BytesRead=0;
  386. //
  387. // Start reading.
  388. //
  389. AsyncStartReads(pNewInfo);
  390. if (NdisInterlockedIncrement(&glConnectionCount) == 1) {
  391. ObReferenceObject(AsyncDeviceObject);
  392. }
  393. break;
  394. }
  395. case IOCTL_ASYMAC_TRACE:
  396. NdisReleaseSpinLock(&Adapter->Lock);
  397. status = STATUS_SUCCESS;
  398. break;
  399. case IOCTL_ASYMAC_CLOSE:
  400. case IOCTL_ASYMAC_DCDCHANGE:
  401. {
  402. PASYNC_INFO pNewInfo; // ptr to open port if found
  403. USHORT i;
  404. PLIST_ENTRY pListEntry;
  405. BOOLEAN Valid = FALSE;
  406. switch (funcCode) {
  407. case IOCTL_ASYMAC_CLOSE:
  408. {
  409. NDIS_MAC_LINE_DOWN AsyncLineDown;
  410. pNewInfo = (PASYNC_INFO)pCloseStruct->hNdisEndpoint;
  411. // Verify that the pointer is a valid ASYNC_INFO
  412. for (pListEntry=Adapter->ActivePorts.Flink;
  413. pListEntry!=&Adapter->ActivePorts;
  414. pListEntry=pListEntry->Flink)
  415. {
  416. if (&pNewInfo->Linkage==pListEntry)
  417. {
  418. Valid = TRUE;
  419. break;
  420. }
  421. }
  422. if (!Valid) {
  423. status=ASYNC_ERROR_PORT_NOT_FOUND;
  424. break;
  425. }
  426. // release spin lock so we can do some real work.
  427. NdisReleaseSpinLock(&Adapter->Lock);
  428. NdisAcquireSpinLock(&pNewInfo->Lock);
  429. // ASSERT(pNewInfo->PortState == PORT_FRAMING);
  430. if(pNewInfo->PortState != PORT_FRAMING)
  431. {
  432. KdPrint(("AsyncIOCtlRequest: IOCTL_ASYMAC_CLOSE."));
  433. KdPrint(("PortState = %d != PORT_FRAMING\n", pNewInfo->PortState));
  434. NdisReleaseSpinLock(&pNewInfo->Lock);
  435. return ASYNC_ERROR_PORT_BAD_STATE;
  436. // break;
  437. }
  438. AsyncLineDown.NdisLinkContext = pNewInfo->NdisLinkContext;
  439. // Signal that port is closing.
  440. pNewInfo->PortState = PORT_CLOSING;
  441. //Set MUTEX to wait on
  442. KeInitializeEvent(&pNewInfo->ClosingEvent, // Event
  443. SynchronizationEvent, // Event type
  444. (BOOLEAN)FALSE); // Not signalled state
  445. NdisReleaseSpinLock(&pNewInfo->Lock);
  446. //
  447. // If we have an outstanding Detect worker
  448. // wait for it to complete!
  449. //
  450. KeWaitForSingleObject(&pNewInfo->DetectEvent,
  451. UserRequest,
  452. KernelMode,
  453. FALSE,
  454. NULL);
  455. //
  456. // now we must send down an IRP do cancel
  457. // any request pending in the serial driver
  458. //
  459. CancelSerialRequests(pNewInfo);
  460. //
  461. // Also, cancel any outstanding DDCD irps
  462. //
  463. AsyncCancelAllQueued(&pNewInfo->DDCDQueue);
  464. // Synchronize closing with the read irp
  465. li.QuadPart = Int32x32To64(10000, -10000); // wait for 10 secs
  466. if (KeWaitForSingleObject (&pNewInfo->ClosingEvent,// PVOID Object,
  467. UserRequest, // KWAIT_REASON WaitReason,
  468. KernelMode, // KPROCESSOR_MODE WaitMode,
  469. (BOOLEAN)FALSE, // BOOLEAN Alertable,
  470. &li) == STATUS_TIMEOUT) {
  471. // If the wait fails cause another flush
  472. //
  473. NTSTATUS retStatus;
  474. PIRP irp;
  475. PASYNC_IO_CTX AsyncIoCtx;
  476. irp=
  477. IoAllocateIrp(pNewInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
  478. if (irp == NULL)
  479. goto DEREF ;
  480. AsyncIoCtx = AsyncAllocateIoCtx(TRUE, pNewInfo);
  481. if (AsyncIoCtx == NULL) {
  482. IoFreeIrp(irp);
  483. goto DEREF;
  484. }
  485. InitSerialIrp(irp,
  486. pNewInfo,
  487. IOCTL_SERIAL_PURGE,
  488. sizeof(ULONG));
  489. // kill all read and write threads.
  490. AsyncIoCtx->SerialPurge =
  491. SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT;
  492. irp->AssociatedIrp.SystemBuffer=
  493. &AsyncIoCtx->SerialPurge;
  494. IoSetCompletionRoutine(irp, // irp to use
  495. SerialIoSyncCompletionRoutine, // routine to call when irp is done
  496. AsyncIoCtx, // context to pass routine
  497. TRUE, // call on success
  498. TRUE, // call on error
  499. TRUE); // call on cancel
  500. // Now simply invoke the driver at its dispatch entry with the IRP.
  501. //
  502. KeClearEvent(&AsyncIoCtx->Event);
  503. retStatus = IoCallDriver(pNewInfo->DeviceObject, irp);
  504. if (retStatus == STATUS_PENDING) {
  505. KeWaitForSingleObject(&AsyncIoCtx->Event,
  506. Executive,
  507. KernelMode,
  508. FALSE,
  509. NULL);
  510. retStatus = AsyncIoCtx->IoStatus.Status;
  511. }
  512. IoFreeIrp(irp);
  513. AsyncFreeIoCtx(AsyncIoCtx);
  514. // if we do hit this code - wait for some time to let
  515. // the read complete
  516. //
  517. KeDelayExecutionThread (KernelMode, FALSE, &li) ;
  518. }
  519. //
  520. // Get rid of our reference to the serial port
  521. //
  522. DEREF:
  523. ObDereferenceObject(pNewInfo->DeviceObject);
  524. ObDereferenceObject(pNewInfo->FileObject);
  525. NdisMIndicateStatus(Adapter->MiniportHandle,
  526. NDIS_STATUS_WAN_LINE_DOWN, // General Status
  527. &AsyncLineDown, // Specific Status
  528. sizeof(NDIS_MAC_LINE_DOWN));
  529. pNewInfo->Flags &= ~(ASYNC_FLAG_ASYNCMAC_OPEN);
  530. //
  531. // Deref the ref applied in IOCTL_ASYNCMAC_OPEN
  532. //
  533. DEREF_ASYNCINFO(pNewInfo, pNewInfo);
  534. //
  535. // Wait for ref on pNewInfo to go to 0
  536. //
  537. KeWaitForSingleObject(&pNewInfo->AsyncEvent,
  538. UserRequest,
  539. KernelMode,
  540. FALSE,
  541. NULL);
  542. // reacquire spin lock
  543. NdisAcquireSpinLock(&Adapter->Lock);
  544. RemoveEntryList(&pNewInfo->Linkage);
  545. // decrement the reference count because we're done.
  546. InterlockedDecrement(&Adapter->RefCount);
  547. pNewInfo->PortState = PORT_CLOSED;
  548. NdisFreeSpinLock(&pNewInfo->Lock);
  549. ExFreeToNPagedLookasideList(&Adapter->AsyncFrameList,
  550. pNewInfo->AsyncFrame);
  551. ExFreeToNPagedLookasideList(&AsyncInfoList,
  552. pNewInfo);
  553. if (NdisInterlockedDecrement(&glConnectionCount) == 0) {
  554. ObDereferenceObject(AsyncDeviceObject);
  555. }
  556. break; // get out of case statement
  557. }
  558. case IOCTL_ASYMAC_DCDCHANGE:
  559. pNewInfo = (PASYNC_INFO)pDCDStruct->hNdisEndpoint;
  560. // Verify that the pointer is a valid ASYNC_INFO
  561. for (pListEntry=Adapter->ActivePorts.Flink;
  562. pListEntry!=&Adapter->ActivePorts;
  563. pListEntry=pListEntry->Flink)
  564. {
  565. if (&pNewInfo->Linkage==pListEntry)
  566. {
  567. Valid = TRUE;
  568. break;
  569. }
  570. }
  571. //
  572. // If the port is already closed, we WILL complain
  573. //
  574. if (!Valid || pNewInfo->PortState == PORT_CLOSED) {
  575. status=ASYNC_ERROR_PORT_NOT_FOUND;
  576. break;
  577. }
  578. //
  579. // If any irps are pending, cancel all of them
  580. // Only one irp can be outstanding at a time.
  581. //
  582. AsyncCancelAllQueued(&pNewInfo->DDCDQueue);
  583. DbgTracef(0, ("ASYNC: Queueing up DDCD IRP\n"));
  584. AsyncQueueIrp(&pNewInfo->DDCDQueue, pIrp);
  585. //
  586. // we'll have to wait for the SERIAL driver
  587. // to flip DCD or DSR
  588. //
  589. status=STATUS_PENDING;
  590. break;
  591. } // end switch
  592. NdisReleaseSpinLock(&Adapter->Lock);
  593. return(status);
  594. }
  595. break;
  596. } // end switch
  597. return status;
  598. }