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.

1463 lines
41 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1991 Nokia Data Systems AB
  4. Module Name:
  5. dlcdrvr.c
  6. Abstract:
  7. This module contains code which implements the NT DLC driver API
  8. using the generic data link module.
  9. Contents:
  10. DriverEntry
  11. CreateAdapterFileContext
  12. CleanupAdapterFileContext
  13. DlcDriverUnload
  14. CloseAdapterFileContext
  15. DlcKillFileContext
  16. DlcDeviceIoControl
  17. DlcCompleteIoRequest
  18. Author:
  19. Antti Saarenheimo 8-Jul-1991
  20. Environment:
  21. Kernel mode
  22. Revision History:
  23. --*/
  24. #define INCLUDE_IO_BUFFER_SIZE_TABLE // includes the io buffer sizes
  25. #include <dlc.h>
  26. #include "dlcreg.h"
  27. #include "dbgmsg.h"
  28. #define DEFINE_DLC_DIAGNOSTICS
  29. #include "dlcdebug.h"
  30. /*++
  31. The queueing of asynchronous commands (21 Oct. 1991)
  32. ----------------------------------------------------
  33. DLC driver uses basically three different methods to queue and
  34. complete its asyncronous commands:
  35. 1. Using LLC request handle
  36. In this case the LLC driver takes care of the command queueing.
  37. This method is used by:
  38. - all transmit commands
  39. - all close commands
  40. - dlc connect
  41. - dlc disconnect
  42. 2. DLC (READ / RECEIVE) Command queue (FIFO)
  43. The read and receive commands are saved to the command completion
  44. queue, that is is circular single enty link list.
  45. The events are handled by the oldest pending command.
  46. These commands also check the event queue and the command
  47. is queued only if there are no pending events.
  48. 3. Timer queue
  49. Timer queue is a null terminated single entry link list.
  50. They are sorted by the relative expiration time. The timer
  51. tick completes all timer commands having the same expiration
  52. time. The expiration times are relative to all previous
  53. commands. For example, timer commands having expiration times 1, 2 and 3
  54. would all have 1 tick count in the queue. Thus the timer tick
  55. needs to increment only one tick from the beginning of the list
  56. and complete all timer commands having zero expiration time.
  57. When command is cancelled, its tick count must be added
  58. to the next element in the queue.
  59. --*/
  60. /*++
  61. New stuff in Feb-20-1992
  62. (reason: with a free build (because it is so fast) I run out of
  63. non-paged pool and several problems did arise in DLC driver:
  64. commands were sometimes lost, DLC.RESET did never complete and
  65. the adapter close
  66. The recovery rules when no non-paged memory is available:
  67. 1. The adapter close (or file context close by handle) must work always =>
  68. the adapter close packet must be in the file context.
  69. 2. The commands must allocate all resources needed to complete the
  70. command before they return a pending status (transmit!), if that
  71. cannot be done then the command must fail immediately.
  72. 3. The received data must not be acknowledged before all resources
  73. have been allocated to receive it.
  74. 4. Probablem: we may lose an important link state change indication if we
  75. cannot allocate a packet for it. For example, the application may
  76. not know, that the link is in the local busy state. The dlc status events
  77. of quite many link stations (255) may also very soon eat all non-paged
  78. pool, if they are not read by client. A static event packet would
  79. prevent that.
  80. A solution: a static event indication packet
  81. in the dlc object, connect and disconnect confirmation would be handled
  82. as now (they are indicated in the command completion entry).
  83. The indication status would be reset, when it is read from the command
  84. queue. The same event indication may have several flags.
  85. (Do first 1, 2, 3 and 4, make the test even more stressing for non-paged
  86. pool and test then what happens. Then we may fix the bug in the buffer
  87. pool shrinkin and implement dynamic packet pools).
  88. The long term solutions:
  89. Dynamic memory management in dlc! The current dlc memory management
  90. is very fast and the top memory consumption is minimal (without the
  91. default 33% overhead of binary buddy algorithm), but it never release
  92. the resources, that it has once allocated.
  93. 1. The packet pools should release the extra memory when they are not
  94. needed any more, implementation: each memory block allocated for
  95. the packet pool has a reference count, that memory block is deallocated
  96. when the reference count is zero. This cleanup could be done once in
  97. a second. The algorithm scans the free list of packets, removes the
  98. packet from the free list, if the reference count of free packets
  99. is the same as the total packet count on a memory block.
  100. The memory blocks can be relesed in the next loop while the block itself
  101. is disconnected from the single entry list of all memory blocks in
  102. the packet pool.
  103. 2. The buffer pool memory management should also be able to shrink the
  104. number of locked pages (there must be a bug in the current implementation)
  105. AND also to free all MDLs and extra packets, when the buffer pool pages
  106. are unlocked.
  107. 3. Data link driver should not allocated any memory resources (except
  108. packet pools to send its own frames). The objects should be created
  109. by in the dlc driver => all extra resources are released when
  110. a dlc driver is released (actually not a big deal, because dynamic
  111. packet pool management fixes the problem with the link stations).
  112. --*/
  113. // Local IOCTL dispatcher table:
  114. // ***************************************************
  115. // THE ORDER OF THESE FUNCTIONS MUST BE THE SAME AS
  116. // THE IOCTL COMMAND CODES IN NTDDDLC.H
  117. // ***************************************************
  118. static PFDLC_COMMAND_HANDLER DispatchTable[IOCTL_DLC_LAST_COMMAND] = {
  119. DlcReadRequest,
  120. DlcReceiveRequest,
  121. DlcTransmit,
  122. DlcBufferFree,
  123. DlcBufferGet,
  124. DlcBufferCreate,
  125. DirSetExceptionFlags,
  126. DlcCloseStation, // DLC.CLOSE.STATION
  127. DlcConnectStation,
  128. DlcFlowControl,
  129. DlcOpenLinkStation,
  130. DlcReset,
  131. DlcReadCancel,
  132. DlcReceiveCancel,
  133. DlcQueryInformation,
  134. DlcSetInformation,
  135. DirTimerCancel,
  136. DirTimerCancelGroup,
  137. DirTimerSet,
  138. DlcOpenSap,
  139. DlcCloseStation, // DLC.CLOSE.SAP
  140. DirOpenDirect,
  141. DlcCloseStation, // DIR.CLOSE.DIRECT
  142. DirOpenAdapter,
  143. DirCloseAdapter,
  144. DlcReallocate,
  145. DlcReadRequest,
  146. DlcReceiveRequest,
  147. DlcTransmit,
  148. DlcCompleteCommand
  149. };
  150. USHORT aSpecialOutputBuffers[3] = {
  151. sizeof(LLC_READ_OUTPUT_PARMS),
  152. sizeof(PVOID), // pFirstBuffer
  153. sizeof(UCHAR) // TransmitFrameStatus
  154. };
  155. NDIS_SPIN_LOCK DlcDriverLock;
  156. #ifdef LOCK_CHECK
  157. LONG DlcDriverLockLevel = 0;
  158. ULONG __line = 0;
  159. PCHAR __file = NULL;
  160. LONG __last = 1;
  161. HANDLE __process = (HANDLE)0;
  162. HANDLE __thread = (HANDLE)0;
  163. #endif
  164. #if LLC_DBG
  165. extern PVOID pAdapters;
  166. ULONG AllocatedNonPagedPool = 0;
  167. ULONG LockedPageCount = 0;
  168. ULONG AllocatedMdlCount = 0;
  169. ULONG AllocatedPackets = 0;
  170. ULONG cExAllocatePoolFailed = 0;
  171. ULONG FailedMemoryLockings = 0;
  172. NDIS_SPIN_LOCK MemCheckLock;
  173. ULONG cFramesReceived = 0;
  174. ULONG cFramesIndicated = 0;
  175. ULONG cFramesReleased = 0;
  176. ULONG cLockedXmitBuffers = 0;
  177. ULONG cUnlockedXmitBuffers = 0;
  178. #endif
  179. //UINT InputIndex = 0;
  180. //LLC_SM_TRACE aLast[LLC_INPUT_TABLE_SIZE];
  181. #if DBG & DLC_TRACE_ENABLED
  182. UINT LlcTraceIndex = 0;
  183. UCHAR LlcTraceTable[LLC_TRACE_TABLE_SIZE];
  184. #endif // DBG & DLC_TRACE_ENABLED
  185. //
  186. // prototypes
  187. //
  188. VOID
  189. LinkFileContext(
  190. IN PDLC_FILE_CONTEXT pFileContext
  191. );
  192. PDLC_FILE_CONTEXT
  193. UnlinkFileContext(
  194. IN PDLC_FILE_CONTEXT pFileContext
  195. );
  196. //
  197. // global data
  198. //
  199. BOOLEAN MemoryLockFailed = FALSE; // this limits unneceasary memory locks
  200. KSPIN_LOCK DlcSpinLock; // syncnhronize the final cleanup
  201. PDEVICE_OBJECT ThisDeviceContext; // required for unloading driver
  202. //
  203. // we now maintain a singly-linked list of FILE_CONTEXTs for debug and retail
  204. // versions
  205. //
  206. SINGLE_LIST_ENTRY FileContexts = {NULL};
  207. KSPIN_LOCK FileContextsLock;
  208. KIRQL PreviousIrql;
  209. #if DBG
  210. BOOLEAN Prolix;
  211. MEMORY_USAGE DriverMemoryUsage;
  212. MEMORY_USAGE DriverStringUsage; // how much string does it take to hang a DLC driver?
  213. #endif
  214. //
  215. // external data
  216. //
  217. //
  218. // functions
  219. //
  220. NTSTATUS
  221. DriverEntry(
  222. IN PDRIVER_OBJECT pDriverObject,
  223. IN PUNICODE_STRING RegistryPath
  224. )
  225. /*++
  226. Routine Description:
  227. This function is called when the I/O subsystem loads the DLC driver
  228. This routine performs the initialization of NT DLC API driver.
  229. Eventually this should be called after the first reference to
  230. DLC driver.
  231. Arguments:
  232. pDriverObject - Pointer to driver object created by the system
  233. RegistryPath - The name of DLC's node in the registry
  234. Return Value:
  235. The function value is the final status from the initialization operation.
  236. --*/
  237. {
  238. NTSTATUS Status;
  239. PDEVICE_OBJECT pDeviceObject;
  240. UNICODE_STRING DriverName;
  241. ASSUME_IRQL(PASSIVE_LEVEL);
  242. #if DBG
  243. if (Prolix) {
  244. DbgPrint("DLC.DriverEntry\n");
  245. }
  246. KeInitializeSpinLock(&DriverMemoryUsage.SpinLock);
  247. KeInitializeSpinLock(&DriverStringUsage.SpinLock);
  248. InitializeMemoryPackage();
  249. #endif
  250. KeInitializeSpinLock(&FileContextsLock);
  251. //
  252. // load any initialization-time parameters from the registry
  253. //
  254. DlcRegistryInitialization(RegistryPath);
  255. LoadDlcConfiguration();
  256. //
  257. // LLC init makes ourselves known to the NDIS wrapper,
  258. // but we don't yet bind to any NDIS driver (don't know even the name)
  259. //
  260. Status = LlcInitialize();
  261. if (Status != STATUS_SUCCESS) {
  262. return STATUS_UNSUCCESSFUL;
  263. }
  264. //
  265. // Create the DLC device object. For now, we simply create \Device\Dlc
  266. // using a Unicode string. In the future we may need to load an ACL
  267. //
  268. RtlInitUnicodeString(&DriverName, DD_DLC_DEVICE_NAME);
  269. //
  270. // Create the device object for DLC driver, we don't have any
  271. // device specific data, because DLC needs only one device context.
  272. // Thus it can just use statics and globals.
  273. //
  274. Status = IoCreateDevice(pDriverObject,
  275. 0,
  276. &DriverName,
  277. FILE_DEVICE_DLC,
  278. FILE_DEVICE_SECURE_OPEN,
  279. FALSE,
  280. &pDeviceObject
  281. );
  282. if (!NT_SUCCESS(Status)) {
  283. return Status;
  284. } else {
  285. //
  286. // need to keep a pointer to device context for IoDeleteDevice
  287. //
  288. ThisDeviceContext = pDeviceObject;
  289. }
  290. //
  291. // DLC driver never calls other device drivers: 1 I/O stack in IRP is enough
  292. //
  293. pDeviceObject->StackSize = 1;
  294. pDeviceObject->Flags |= DO_DIRECT_IO;
  295. KeInitializeSpinLock(&DlcSpinLock);
  296. NdisAllocateSpinLock(&DlcDriverLock);
  297. //
  298. // Initialize the driver object with this driver's entry points.
  299. //
  300. pDriverObject->MajorFunction[IRP_MJ_CREATE] = CreateAdapterFileContext;
  301. pDriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseAdapterFileContext;
  302. pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = CleanupAdapterFileContext;
  303. pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DlcDeviceIoControl;
  304. pDriverObject->DriverUnload = DlcDriverUnload;
  305. return STATUS_SUCCESS;
  306. }
  307. NTSTATUS
  308. CreateAdapterFileContext(
  309. IN PDEVICE_OBJECT pDeviceObject,
  310. IN PIRP pIrp
  311. )
  312. /*++
  313. Routine Description:
  314. This function is called when a handle to the DLC driver is opened (via
  315. NtCreateFile)
  316. The Create function creates file context for a DLC application.
  317. A DLC application needs at least one file context for each
  318. network adapter it is using. The DLC file contexts may share
  319. the same buffer pool, but otherwise they are totally isolated
  320. from each other.
  321. Arguments:
  322. DeviceObject - Pointer to the device object for this driver
  323. Irp - Pointer to the request packet representing the I/O request
  324. Return Value:
  325. The function value is the status of the operation.
  326. --*/
  327. {
  328. NTSTATUS Status = STATUS_SUCCESS;
  329. PDLC_FILE_CONTEXT pFileContext;
  330. PIO_STACK_LOCATION pIrpSp;
  331. UNREFERENCED_PARAMETER(pDeviceObject);
  332. ASSUME_IRQL(PASSIVE_LEVEL);
  333. #if LLC_DBG == 2
  334. PrintMemStatus();
  335. #endif
  336. pIrp->IoStatus.Status = STATUS_SUCCESS;
  337. pIrp->IoStatus.Information = 0;
  338. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  339. pFileContext = (PDLC_FILE_CONTEXT)ALLOCATE_ZEROMEMORY_DRIVER(sizeof(DLC_FILE_CONTEXT));
  340. if (pFileContext == NULL) {
  341. Status = STATUS_INSUFFICIENT_RESOURCES;
  342. goto ErrorExit2;
  343. }
  344. // #126745: Enqueue after initialization
  345. /* //
  346. // add this file context to our global list of opened file contexts
  347. //
  348. LinkFileContext(pFileContext); */
  349. #if DBG
  350. //
  351. // record who owns this memory usage and add it to our global list of
  352. // memory usages
  353. //
  354. pFileContext->MemoryUsage.Owner = (PVOID)pFileContext;
  355. pFileContext->MemoryUsage.OwnerObjectId = FileContextObject;
  356. LinkMemoryUsage(&pFileContext->MemoryUsage);
  357. #endif
  358. pIrpSp->FileObject->FsContext = pFileContext;
  359. pFileContext->FileObject = pIrpSp->FileObject;
  360. InitializeListHead(&pFileContext->EventQueue);
  361. InitializeListHead(&pFileContext->CommandQueue);
  362. InitializeListHead(&pFileContext->ReceiveQueue);
  363. InitializeListHead(&pFileContext->FlowControlQueue);
  364. //
  365. // create pool of command/event packets
  366. //
  367. pFileContext->hPacketPool = CREATE_PACKET_POOL_FILE(DlcPacketPoolObject,
  368. sizeof(DLC_PACKET),
  369. 8
  370. );
  371. if (pFileContext->hPacketPool == NULL) {
  372. Status = STATUS_INSUFFICIENT_RESOURCES;
  373. goto ErrorExit1;
  374. }
  375. //
  376. // create pool of DLC-level SAP/LINK/DIRECT objects
  377. //
  378. pFileContext->hLinkStationPool = CREATE_PACKET_POOL_FILE(DlcLinkPoolObject,
  379. sizeof(DLC_OBJECT),
  380. 4
  381. );
  382. if (pFileContext->hLinkStationPool == NULL) {
  383. Status = STATUS_INSUFFICIENT_RESOURCES;
  384. goto ErrorExit1;
  385. }
  386. //
  387. // add this file context to our global list of opened file contexts
  388. //
  389. LinkFileContext(pFileContext);
  390. //
  391. // set the file context reference count to 1 - this file context is ALIVE!
  392. //
  393. ReferenceFileContext(pFileContext);
  394. //
  395. // the call to open a handle to the driver may have succeeded, but we don't
  396. // yet have an open adapter context
  397. //
  398. pFileContext->State = DLC_FILE_CONTEXT_CLOSED;
  399. ALLOCATE_SPIN_LOCK(&pFileContext->SpinLock);
  400. KeInitializeEvent(&pFileContext->CleanupEvent, SynchronizationEvent, FALSE);
  401. ErrorExit1:
  402. if (Status != STATUS_SUCCESS) {
  403. DELETE_PACKET_POOL_FILE(&pFileContext->hLinkStationPool);
  404. DELETE_PACKET_POOL_FILE(&pFileContext->hPacketPool);
  405. CHECK_MEMORY_RETURNED_FILE();
  406. // UnlinkFileContext(pFileContext);
  407. #if DBG
  408. // UnlinkMemoryUsage(&pFileContext->MemoryUsage);
  409. #endif
  410. FREE_MEMORY_DRIVER(pFileContext);
  411. }
  412. ErrorExit2:
  413. pIrp->IoStatus.Status = Status;
  414. DlcCompleteIoRequest(pIrp, FALSE);
  415. return Status;
  416. }
  417. NTSTATUS
  418. CleanupAdapterFileContext(
  419. IN PDEVICE_OBJECT pDeviceObject,
  420. IN PIRP pIrp
  421. )
  422. /*++
  423. Routine Description:
  424. This function is called when the last reference to an open file handle is
  425. removed. This is an opportunity, given us by the I/O subsystem, to ensure
  426. that all pending I/O requests for the file object being closed have been
  427. completed
  428. The routine checks, that the file context is really closed.
  429. Otherwise it executes a panic closing of all resources in
  430. the same way as in the DirCloseAdapter call.
  431. It happens when an application makes process exit without
  432. calling the DirCloseAdapter.
  433. Arguments:
  434. DeviceObject - Pointer to the device object for this driver
  435. Irp - Pointer to the request packet representing the I/O request
  436. Return Value:
  437. The function value is the status of the operation.
  438. --*/
  439. {
  440. PIO_STACK_LOCATION pIrpSp;
  441. PDLC_FILE_CONTEXT pFileContext;
  442. NTSTATUS Status = STATUS_SUCCESS;
  443. UNREFERENCED_PARAMETER(pDeviceObject);
  444. DIAG_FUNCTION("CleanupAdapterFileContext");
  445. #if DBG
  446. if (Prolix) {
  447. DbgPrint("CleanupAdapterFileContext\n");
  448. }
  449. #endif
  450. pIrp->IoStatus.Status = STATUS_SUCCESS;
  451. pIrp->IoStatus.Information = 0;
  452. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  453. pFileContext = pIrpSp->FileObject->FsContext;
  454. //
  455. // We may have a pending close or Initialize operation going on
  456. //
  457. ACQUIRE_DRIVER_LOCK();
  458. ENTER_DLC(pFileContext);
  459. KeResetEvent(&pFileContext->CleanupEvent);
  460. if (pFileContext->State == DLC_FILE_CONTEXT_OPEN) {
  461. //
  462. // as for Ioctl processing, add 2 to the file context reference count
  463. // The combination of the dereference below, the completion of the
  464. // close adapter call and the processing of a close IRP will cause the
  465. // file context to be destroyed
  466. //
  467. ReferenceFileContextByTwo(pFileContext);
  468. Status = DirCloseAdapter(pIrp,
  469. pFileContext,
  470. NULL,
  471. 0,
  472. 0
  473. );
  474. #if LLC_DBG
  475. if (Status != STATUS_PENDING) {
  476. DbgBreakPoint();
  477. }
  478. #endif
  479. //
  480. // We always return a pending status from DirCloseAdapter
  481. //
  482. MY_ASSERT(Status == STATUS_PENDING);
  483. DereferenceFileContext(pFileContext);
  484. }
  485. //
  486. // Remove the original DLC_FILE_CONTEXT reference.
  487. //
  488. DereferenceFileContext(pFileContext);
  489. LEAVE_DLC(pFileContext);
  490. RELEASE_DRIVER_LOCK();
  491. //
  492. // Wait for all references to the DLC_FILE_CONTEXT to be removed. When
  493. // the last reference is removed, DlcKillFileContext is called which will
  494. // clean up most of the file context's resources and then set the event.
  495. // CloseAdapterFileContext/IRP_MJ_CLOSE will free the actual memory
  496. // for the file context.
  497. //
  498. KeWaitForSingleObject(
  499. &pFileContext->CleanupEvent,
  500. UserRequest,
  501. KernelMode,
  502. FALSE,
  503. NULL);
  504. DlcCompleteIoRequest(pIrp, FALSE);
  505. return Status;
  506. }
  507. VOID
  508. DlcDriverUnload(
  509. IN PDRIVER_OBJECT pDeviceObject
  510. )
  511. /*++
  512. Routine Description:
  513. This functions is called when a called is made to the I/O subsystem to
  514. remove the DLC driver
  515. Arguments:
  516. DeviceObject - Pointer to the device object for this driver.
  517. Return Value:
  518. The function value is the status of the operation.
  519. --*/
  520. {
  521. UNREFERENCED_PARAMETER(pDeviceObject);
  522. ASSUME_IRQL(PASSIVE_LEVEL);
  523. DEBUGMSG(DBG_INIT,
  524. (TEXT("DlcDriverUnload(%#x)\n"), pDeviceObject));
  525. LlcTerminate();
  526. DlcRegistryTermination();
  527. CHECK_MEMORY_RETURNED_DRIVER();
  528. CHECK_STRING_RETURNED_DRIVER();
  529. CHECK_DRIVER_MEMORY_USAGE(TRUE);
  530. NdisFreeSpinLock(&DlcDriverLock);
  531. //
  532. // now tell I/O subsystem that this device context is no longer current
  533. //
  534. IoDeleteDevice(ThisDeviceContext);
  535. }
  536. NTSTATUS
  537. CloseAdapterFileContext(
  538. IN PDEVICE_OBJECT pDeviceObject,
  539. IN PIRP pIrp
  540. )
  541. /*++
  542. Routine Description:
  543. This routine is called when the file object reference count is zero. The file
  544. object is really being deleted by the I/O subsystem. The file context had
  545. better be closed by now (should have been cleared out by Cleanup)
  546. Arguments:
  547. DeviceObject - Pointer to the device object for this driver
  548. Irp - Pointer to the request packet representing the I/O request
  549. Return Value:
  550. The function value is the status of the operation.
  551. --*/
  552. {
  553. PIO_STACK_LOCATION pIrpSp;
  554. PDLC_FILE_CONTEXT pFileContext;
  555. UNREFERENCED_PARAMETER(pDeviceObject);
  556. DIAG_FUNCTION("CloseAdapterFileContext");
  557. #if DBG
  558. if (Prolix) {
  559. DbgPrint("CloseAdapterFileContext\n");
  560. }
  561. #endif
  562. pIrp->IoStatus.Status = STATUS_SUCCESS;
  563. pIrp->IoStatus.Information = 0;
  564. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  565. pFileContext = pIrpSp->FileObject->FsContext;
  566. //
  567. // The original reference was removed in CleanupAdapterFileContext and
  568. // blocked until all references were removed and the file context
  569. // resources cleaned up, except for the following.
  570. //
  571. ASSERT(pFileContext->ReferenceCount == 0);
  572. ASSERT(UnlinkFileContext(pFileContext) == NULL);
  573. pIrpSp->FileObject->FsContext = NULL;
  574. DEALLOCATE_SPIN_LOCK(&pFileContext->SpinLock);
  575. FREE_MEMORY_DRIVER(pFileContext);
  576. //
  577. // complete the Close IRP
  578. //
  579. DlcCompleteIoRequest(pIrp, FALSE);
  580. #if DBG
  581. if (Prolix) {
  582. CHECK_DRIVER_MEMORY_USAGE(FALSE);
  583. }
  584. #endif
  585. return STATUS_SUCCESS;
  586. }
  587. VOID
  588. DlcKillFileContext(
  589. IN PDLC_FILE_CONTEXT pFileContext
  590. )
  591. /*++
  592. Routine Description:
  593. Called when the reference count on a file context structure is decremented
  594. to zero. Frees all memory owned by the file context and removes it from the
  595. file context list.
  596. After this function, no references to the file context structure can be made!
  597. Arguments:
  598. pFileContext - pointer to DLC file context structure to kill
  599. Return Value:
  600. None.
  601. --*/
  602. {
  603. KIRQL irql;
  604. PVOID pBindingContext;
  605. ASSUME_IRQL(DISPATCH_LEVEL);
  606. // Shouldn't need lock since only called when reference count is 0.
  607. // ENTER_DLC(pFileContext);
  608. //
  609. // delete all events on the file context event list before we delete the
  610. // packet pool
  611. //
  612. PurgeDlcEventQueue(pFileContext);
  613. PurgeDlcFlowControlQueue(pFileContext);
  614. DELETE_PACKET_POOL_FILE(&pFileContext->hPacketPool);
  615. DELETE_PACKET_POOL_FILE(&pFileContext->hLinkStationPool);
  616. // LEAVE_DLC(pFileContext);
  617. pBindingContext = pFileContext->pBindingContext;
  618. //
  619. // Finally, close the NDIS adapter. we have already disabled all
  620. // indications from it
  621. //
  622. if (pBindingContext) {
  623. //
  624. // RLF 04/26/94
  625. //
  626. // We need to call LlcDisableAdapter here to terminate the DLC timer
  627. // if it is not already terminated. Else we can end up with the timer
  628. // still in the adapter's tick list (if there are other bindings to
  629. // the adapter), and sooner or later that will cause an access
  630. // violation, followed very shortly thereafter by a blue screen
  631. //
  632. LlcDisableAdapter(pBindingContext);
  633. LlcCloseAdapter(pBindingContext, TRUE);
  634. }
  635. CHECK_MEMORY_RETURNED_FILE();
  636. UnlinkFileContext(pFileContext);
  637. #if DBG
  638. UnlinkMemoryUsage(&pFileContext->MemoryUsage);
  639. #endif
  640. KeSetEvent(&pFileContext->CleanupEvent, 0, FALSE);
  641. #if LLC_DBG
  642. if ((LockedPageCount != 0
  643. || AllocatedMdlCount != 0
  644. || AllocatedNonPagedPool != 0)
  645. && pAdapters == NULL) {
  646. DbgPrint("DLC.CloseAdapterFileContext: Error: Resources not released\n");
  647. //PrintMemStatus();
  648. DbgBreakPoint();
  649. }
  650. FailedMemoryLockings = 0;
  651. #endif
  652. }
  653. NTSTATUS
  654. DlcDeviceIoControl(
  655. IN PDEVICE_OBJECT pDeviceContext,
  656. IN PIRP pIrp
  657. )
  658. /*++
  659. Routine Description:
  660. This routine dispatches DLC requests to different handlers based
  661. on the minor IOCTL function code in the IRP's current stack location.
  662. In addition to cracking the minor function code, this routine also
  663. reaches into the IRP and passes the packetized parameters stored there
  664. as parameters to the various DLC request handlers so that they are
  665. not IRP-dependent.
  666. DlcDeviceControl and LlcReceiveIndication are the most time critical
  667. procedures in DLC. This code has been optimized for the asynchronous
  668. command (read and transmit)
  669. Arguments:
  670. pDeviceContext - Pointer to the device object for this driver (unused)
  671. pIrp - Pointer to the request packet representing the I/O request
  672. Return Value:
  673. NTSTATUS
  674. Success - STATUS_SUCCESS
  675. The I/O request has been successfully completed
  676. STATUS_PENDING
  677. The I/O request has been submitted and will be completed
  678. asynchronously
  679. Failure - DLC_STATUS_XXX
  680. LLC_STATUS_XXX
  681. The I/O request has been completed, but an error occurred
  682. --*/
  683. {
  684. USHORT TmpIndex;
  685. PDLC_FILE_CONTEXT pFileContext; // FsContext in FILE_OBJECT.
  686. PIO_STACK_LOCATION pIrpSp;
  687. ULONG ioControlCode;
  688. UNREFERENCED_PARAMETER(pDeviceContext);
  689. ASSUME_IRQL(PASSIVE_LEVEL);
  690. //
  691. // Make sure status information is consistent every time
  692. //
  693. pIrp->IoStatus.Status = STATUS_SUCCESS;
  694. //
  695. // Get a pointer to the current stack location in the IRP. This is where
  696. // the function codes and parameters are stored.
  697. //
  698. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  699. //
  700. // Branch to the appropriate request handler, but do first
  701. // preliminary checking of the input and output buffers,
  702. // the size of the request block is performed here so that it is known
  703. // in the handlers that the minimum input parameters are readable. It
  704. // is *not* determined here whether variable length input fields are
  705. // passed correctly; this is a check which must be made within each routine.
  706. //
  707. ioControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
  708. // Check the complete IoControl Code
  709. switch (ioControlCode) {
  710. case IOCTL_DLC_READ:
  711. case IOCTL_DLC_RECEIVE:
  712. case IOCTL_DLC_TRANSMIT:
  713. case IOCTL_DLC_BUFFER_FREE:
  714. case IOCTL_DLC_BUFFER_GET:
  715. case IOCTL_DLC_BUFFER_CREATE:
  716. case IOCTL_DLC_SET_EXCEPTION_FLAGS:
  717. case IOCTL_DLC_CLOSE_STATION:
  718. case IOCTL_DLC_CONNECT_STATION:
  719. case IOCTL_DLC_FLOW_CONTROL:
  720. case IOCTL_DLC_OPEN_STATION:
  721. case IOCTL_DLC_RESET:
  722. case IOCTL_DLC_READ_CANCEL:
  723. case IOCTL_DLC_RECEIVE_CANCEL:
  724. case IOCTL_DLC_QUERY_INFORMATION:
  725. case IOCTL_DLC_SET_INFORMATION:
  726. case IOCTL_DLC_TIMER_CANCEL:
  727. case IOCTL_DLC_TIMER_CANCEL_GROUP:
  728. case IOCTL_DLC_TIMER_SET:
  729. case IOCTL_DLC_OPEN_SAP:
  730. case IOCTL_DLC_CLOSE_SAP:
  731. case IOCTL_DLC_OPEN_DIRECT:
  732. case IOCTL_DLC_CLOSE_DIRECT:
  733. case IOCTL_DLC_OPEN_ADAPTER:
  734. case IOCTL_DLC_CLOSE_ADAPTER:
  735. case IOCTL_DLC_REALLOCTE_STATION:
  736. case IOCTL_DLC_READ2:
  737. case IOCTL_DLC_RECEIVE2:
  738. case IOCTL_DLC_TRANSMIT2:
  739. case IOCTL_DLC_COMPLETE_COMMAND:
  740. case IOCTL_DLC_TRACE_INITIALIZE:
  741. TmpIndex = (((USHORT)ioControlCode) >> 2) & 0x0fff;
  742. break;
  743. default:
  744. TmpIndex = IOCTL_DLC_LAST_COMMAND;
  745. }
  746. // TmpIndex = (((USHORT)ioControlCode) >> 2) & 0x0fff;
  747. if (TmpIndex >= IOCTL_DLC_LAST_COMMAND) {
  748. pIrp->IoStatus.Information = 0;
  749. // DlcCompleteIoRequest(pIrp, FALSE);
  750. // Don't call DlcCompleteIoRequest, it tries to free MDLs we haven't yet allocated
  751. // Instead of putting some more checks in DlcCompleteIoRequest, complete request here itself
  752. pIrp->IoStatus.Status = DLC_STATUS_INVALID_COMMAND;
  753. SetIrpCancelRoutine(pIrp, FALSE);
  754. IoCompleteRequest(pIrp, (CCHAR)IO_NETWORK_INCREMENT);
  755. return DLC_STATUS_INVALID_COMMAND;
  756. }
  757. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength
  758. < (ULONG)aDlcIoBuffers[TmpIndex].InputBufferSize
  759. ||
  760. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength
  761. < (ULONG)aDlcIoBuffers[TmpIndex].OutputBufferSize) {
  762. //
  763. // This error code should never be returned to user
  764. // If this happpens, then there is something wrong with ACSLAN
  765. //
  766. pIrp->IoStatus.Information = 0;
  767. // DlcCompleteIoRequest(pIrp, FALSE);
  768. // Don't call DlcCompleteIoRequest, it tries to free MDLs we haven't yet allocated
  769. // Instead of putting some more checks in DlcCompleteIoRequest, complete request here itself
  770. pIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  771. SetIrpCancelRoutine(pIrp, FALSE);
  772. IoCompleteRequest(pIrp, (CCHAR)IO_NETWORK_INCREMENT);
  773. return STATUS_BUFFER_TOO_SMALL;
  774. }
  775. //
  776. // Save the length of the actual output buffer to Information field.
  777. // This number of bytes will be copied back to user buffer.
  778. //
  779. pIrp->IoStatus.Information = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  780. //
  781. // there are 3 cases of asynchronous commands where we need to lock extra
  782. // user memory for returned information. This goes in the parameter table
  783. // which can be anywhere in user memory (ie not near the CCB):
  784. //
  785. // TRANSMIT
  786. // - TRANSMIT_FS - a single byte!
  787. //
  788. // RECEIVE
  789. // - FIRST_BUFFER - a DWORD - pointer to the first received frame
  790. //
  791. // READ
  792. // - the entire parameter table needs to be locked. Virtually all
  793. // the fields are output. Still, this is only a max of 30 bytes
  794. //
  795. if (TmpIndex <= IOCTL_DLC_TRANSMIT_INDEX) {
  796. PVOID pDestination;
  797. PNT_DLC_PARMS pDlcParms;
  798. pDlcParms = (PNT_DLC_PARMS)pIrp->AssociatedIrp.SystemBuffer;
  799. //
  800. // Get the pointer of output parameters in user memory.
  801. // Note that we are not accessing anything in user address space.
  802. //
  803. switch (TmpIndex) {
  804. case IOCTL_DLC_READ_INDEX:
  805. pDestination = &pDlcParms->Async.Ccb.u.pParameterTable->Read.uchEvent;
  806. break;
  807. case IOCTL_DLC_RECEIVE_INDEX:
  808. pDestination = &pDlcParms->Async.Ccb.u.pParameterTable->Receive.pFirstBuffer;
  809. break;
  810. case IOCTL_DLC_TRANSMIT_INDEX:
  811. pDestination = &pDlcParms->Async.Ccb.u.pParameterTable->Transmit.uchTransmitFs;
  812. break;
  813. }
  814. //
  815. // allocate another MDL for the 1, 4, or 30 byte parameter table and lock
  816. // the page(s!)
  817. //
  818. pDlcParms->Async.Ccb.u.pMdl = AllocateProbeAndLockMdl(
  819. pDestination,
  820. aSpecialOutputBuffers[TmpIndex]
  821. );
  822. if (pDlcParms->Async.Ccb.u.pMdl == NULL) {
  823. pIrp->IoStatus.Status = DLC_STATUS_MEMORY_LOCK_FAILED;
  824. DlcCompleteIoRequest(pIrp, FALSE);
  825. return DLC_STATUS_MEMORY_LOCK_FAILED;
  826. }
  827. }
  828. pFileContext = (PDLC_FILE_CONTEXT)pIrpSp->FileObject->FsContext;
  829. ACQUIRE_DRIVER_LOCK();
  830. ENTER_DLC(pFileContext);
  831. //
  832. // We must leave immediately, if the reference counter is zero
  833. // or if we have a pending close or Initialize operation going on.
  834. // (This is not 100% safe, if app would create a file context,
  835. // open adapter, close adapter and immediately would close it again
  836. // when the previous command is pending, but that cannot be happen
  837. // with dlcapi.dll)
  838. //
  839. if ((pFileContext->ReferenceCount == 0)
  840. || ((pFileContext->State != DLC_FILE_CONTEXT_OPEN)
  841. && (TmpIndex != IOCTL_DLC_OPEN_ADAPTER_INDEX))) {
  842. LEAVE_DLC(pFileContext);
  843. RELEASE_DRIVER_LOCK();
  844. pIrp->IoStatus.Status = LLC_STATUS_ADAPTER_CLOSED;
  845. DlcCompleteIoRequest(pIrp, FALSE);
  846. return LLC_STATUS_ADAPTER_CLOSED;
  847. } else {
  848. NTSTATUS Status;
  849. DLC_TRACE('F');
  850. //
  851. // set the default IRP cancel routine. We are not going to handle
  852. // transmit cases now
  853. //
  854. //SetIrpCancelRoutine(pIrp,
  855. // (BOOLEAN)
  856. // !( (ioControlCode == IOCTL_DLC_TRANSMIT)
  857. // || (ioControlCode == IOCTL_DLC_TRANSMIT2) )
  858. // );
  859. //
  860. // and set the irp I/O status to pending
  861. //
  862. IoMarkIrpPending(pIrp);
  863. //
  864. // The reason why we add 2 here is that during the processing of the
  865. // current IRP we may complete the request, causing us to decrement the
  866. // reference counter on the file context. If we just incremented by 1
  867. // here, the decrement could cause a pending close IRP to be allowed to
  868. // delete the file context while we are still using it
  869. //
  870. ReferenceFileContextByTwo(pFileContext);
  871. //
  872. // Irp and IrpSp are used just as in NBF
  873. //
  874. Status = DispatchTable[TmpIndex](
  875. pIrp,
  876. pFileContext,
  877. (PNT_DLC_PARMS)pIrp->AssociatedIrp.SystemBuffer,
  878. pIrpSp->Parameters.DeviceIoControl.InputBufferLength,
  879. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength
  880. );
  881. //
  882. // ensure the function returned with the correct IRQL
  883. //
  884. ASSUME_IRQL(DISPATCH_LEVEL);
  885. //
  886. // the following error codes are valid:
  887. //
  888. // STATUS_PENDING
  889. // The request has been accepted
  890. // The driver will complete the request asynchronously
  891. // The output CCB should contain 0xFF in its status field (unless
  892. // already completed)
  893. //
  894. // STATUS_SUCCESS
  895. // The request has successfully completed synchronously
  896. // The output CCB should contain 0x00 in its status field
  897. //
  898. // 0x6001 - 0x6069
  899. // 0x6080 - 0x6081
  900. // 0x60A1 - 0x60A3
  901. // 0x60C0 - 0x60CB
  902. // 0x60FF
  903. // The request has failed with a DLC-specific error
  904. // The error code is converted to a DLC status code (-0x6000) and
  905. // the output CCB status field is set to the DLC status code
  906. // No asynchronous completion will be taken for this request
  907. //
  908. if (Status != STATUS_PENDING) {
  909. DLC_TRACE('G');
  910. pIrpSp->Control &= ~SL_PENDING_RETURNED;
  911. if (Status != STATUS_SUCCESS) {
  912. PNT_DLC_PARMS pDlcParms = (PNT_DLC_PARMS)pIrp->AssociatedIrp.SystemBuffer;
  913. if (Status >= DLC_STATUS_ERROR_BASE && Status < DLC_STATUS_MAX_ERROR) {
  914. Status -= DLC_STATUS_ERROR_BASE;
  915. }
  916. //
  917. // RLF 04/20/94
  918. //
  919. // make sure the CCB has the correct value written to it on
  920. // output if we're not returning pending status
  921. //
  922. pDlcParms->Async.Ccb.uchDlcStatus = (UCHAR)Status;
  923. //
  924. // the CCB request has failed. Make sure the pNext field is reset
  925. //
  926. if ((pIrpSp->Parameters.DeviceIoControl.IoControlCode & 3) == METHOD_OUT_DIRECT) {
  927. //
  928. // the CCB address may actually be unaligned DOS CCB1
  929. //
  930. LLC_CCB UNALIGNED * pCcb;
  931. pCcb = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
  932. if (pCcb) {
  933. pCcb->pNext = NULL;
  934. }
  935. // Failure case. Don't override previous failure status.
  936. // It is likely STATUS_INSUFFICIENT_RESOURCES.
  937. } else {
  938. pDlcParms->Async.Ccb.pCcbAddress = NULL;
  939. }
  940. }
  941. if (ioControlCode != IOCTL_DLC_RESET) {
  942. //
  943. // DLC.RESET returns an immediate status and does not complete
  944. // asynchronously
  945. //
  946. DereferenceFileContextByTwo(pFileContext);
  947. } else {
  948. //
  949. // everything else that returns a non-pending status completes
  950. // asynchronously, which also causes the other reference count
  951. // to be removed
  952. //
  953. DereferenceFileContext(pFileContext);
  954. }
  955. LEAVE_DLC(pFileContext);
  956. RELEASE_DRIVER_LOCK();
  957. //
  958. // RLF 06/07/93
  959. //
  960. // if the request is DLC.RESET, the IRP will have already been
  961. // completed if we're here, so don't complete it again (else we'll
  962. // bugcheck)
  963. //
  964. if (ioControlCode != IOCTL_DLC_RESET) {
  965. DlcCompleteIoRequest(pIrp, FALSE);
  966. }
  967. return Status;
  968. } else {
  969. DLC_TRACE('H');
  970. //
  971. // Reallocate the buffer pool size, if a threshold has been exceeded
  972. //
  973. if (BufferPoolCheckThresholds(pFileContext->hBufferPool)) {
  974. ReferenceBufferPool(pFileContext);
  975. LEAVE_DLC(pFileContext);
  976. #if DBG
  977. BufferPoolExpand(pFileContext, (PDLC_BUFFER_POOL)pFileContext->hBufferPool);
  978. #else
  979. BufferPoolExpand((PDLC_BUFFER_POOL)pFileContext->hBufferPool);
  980. #endif
  981. ENTER_DLC(pFileContext);
  982. DereferenceBufferPool(pFileContext);
  983. }
  984. LEAVE_DLC(pFileContext);
  985. //
  986. // if this dereference causes the count to go to 0, the file context
  987. // will be destroyed. Implicitly we must be closing the adapter and
  988. // have received a close IRP for this to happen
  989. //
  990. DereferenceFileContext(pFileContext);
  991. RELEASE_DRIVER_LOCK();
  992. return STATUS_PENDING;
  993. }
  994. }
  995. }
  996. VOID
  997. DlcCompleteIoRequest(
  998. IN PIRP pIrp,
  999. IN BOOLEAN InCancel
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. This routine completes the given DLC IRP
  1004. Arguments:
  1005. pIrp - Pointer to the request packet representing the I/O request.
  1006. InCancel - TRUE if called on Irp cancel path
  1007. Return Value:
  1008. None
  1009. --*/
  1010. {
  1011. //
  1012. // we are about to complete this IRP - remove the cancel routine. The check
  1013. // stops us spinning forever if this function is called from within an IRP
  1014. // cancellation
  1015. //
  1016. if (!InCancel) {
  1017. SetIrpCancelRoutine(pIrp, FALSE);
  1018. }
  1019. //
  1020. // unlock and free any MDLs we allocated
  1021. //
  1022. if (IoGetCurrentIrpStackLocation(pIrp)->MajorFunction == IRP_MJ_DEVICE_CONTROL
  1023. && IoGetCurrentIrpStackLocation(pIrp)->Parameters.DeviceIoControl.IoControlCode <= IOCTL_DLC_TRANSMIT) {
  1024. //
  1025. // We enter here only if something has gone wrong in the main
  1026. // function of an async operation => the status field and
  1027. // next pointer will be updated synchronously.
  1028. // On the other hand, all other async functions having no output
  1029. // parameters except CCB status and next pointer are upated
  1030. // by the normal code path. They should just copy
  1031. // back the pending status and next pointer pointing to CCB itself.
  1032. // That should not affect anything, because the DLL will update
  1033. // those fields, when we return synchronous status
  1034. //
  1035. PNT_DLC_PARMS pDlcParms = (PNT_DLC_PARMS)pIrp->AssociatedIrp.SystemBuffer;
  1036. if (pDlcParms->Async.Ccb.u.pMdl != NULL) {
  1037. UnlockAndFreeMdl(pDlcParms->Async.Ccb.u.pMdl);
  1038. }
  1039. }
  1040. IoCompleteRequest(pIrp, (CCHAR)IO_NETWORK_INCREMENT);
  1041. }
  1042. VOID
  1043. LinkFileContext(
  1044. IN PDLC_FILE_CONTEXT pFileContext
  1045. )
  1046. {
  1047. KeAcquireSpinLock(&FileContextsLock, &PreviousIrql);
  1048. PushEntryList(&FileContexts, &pFileContext->List);
  1049. KeReleaseSpinLock(&FileContextsLock, PreviousIrql);
  1050. }
  1051. PDLC_FILE_CONTEXT
  1052. UnlinkFileContext(
  1053. IN PDLC_FILE_CONTEXT pFileContext
  1054. )
  1055. {
  1056. PSINGLE_LIST_ENTRY p, prev = (PSINGLE_LIST_ENTRY)&FileContexts;
  1057. KeAcquireSpinLock(&FileContextsLock, &PreviousIrql);
  1058. for (p = FileContexts.Next; p && p != (PSINGLE_LIST_ENTRY)pFileContext; ) {
  1059. prev = p;
  1060. p = p->Next;
  1061. }
  1062. if (p) {
  1063. prev->Next = p->Next;
  1064. // } else {
  1065. //
  1066. //#if DBG
  1067. // DbgPrint("DLC.UnlinkFileContext: Error: FILE_CONTEXT @%08X not on list??\n",
  1068. // pFileContext
  1069. // );
  1070. //#endif
  1071. //
  1072. }
  1073. KeReleaseSpinLock(&FileContextsLock, PreviousIrql);
  1074. return (PDLC_FILE_CONTEXT)p;
  1075. }