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.

2383 lines
76 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1991 Nokia Data Systems AB
  4. Module Name:
  5. dlcopen.c
  6. Abstract:
  7. This module implements all open and close operations for DLC objects
  8. Contents:
  9. DlcOpenSap
  10. DirOpenDirect
  11. DlcOpenLinkStation
  12. InitializeLinkStation
  13. DlcCloseStation
  14. CloseAllStations
  15. CloseAnyStation
  16. CloseStation
  17. CompleteCloseStation
  18. CompleteCloseReset
  19. CleanUpEvents
  20. SearchReadCommandForClose
  21. CompleteLlcObjectClose
  22. DecrementCloseCounters
  23. CompleteDirectOutIrp
  24. Author:
  25. Antti Saarenheimo 29-Aug-1991
  26. Environment:
  27. Kernel mode
  28. Revision History:
  29. --*/
  30. #include <dlc.h>
  31. #include "dlcdebug.h"
  32. #include <smbgtpt.h>
  33. NTSTATUS
  34. DlcOpenSap(
  35. IN PIRP pIrp,
  36. IN PDLC_FILE_CONTEXT pFileContext,
  37. IN PNT_DLC_PARMS pDlcParms,
  38. IN ULONG InputBufferLength,
  39. IN ULONG OutputBufferLength
  40. )
  41. /*++
  42. Routine Description:
  43. Procedure implements DLC.OPEN.SAP function in DLC API.
  44. This implements DLC.OPEN.SAP.
  45. Arguments:
  46. pIrp - current io request packet
  47. pFileContext - DLC adapter context
  48. pDlcParms - the current parameter block
  49. InputBufferLength - the length of input parameters
  50. OutputBufferLength - not used
  51. Return Value:
  52. NTSTATUS:
  53. Success - STATUS_SUCCESS
  54. Failure - DLC_STATUS_NO_MEMORY
  55. --*/
  56. {
  57. PDLC_OBJECT pDlcObject;
  58. UINT SapIndex = (pDlcParms->DlcOpenSap.SapValue >> 1);
  59. UINT Status;
  60. USHORT XidHandlingOption;
  61. UNREFERENCED_PARAMETER(pIrp);
  62. UNREFERENCED_PARAMETER(InputBufferLength);
  63. UNREFERENCED_PARAMETER(OutputBufferLength);
  64. DIAG_FUNCTION("DlcOpenSap");
  65. //
  66. // The group saps do not have any open/close context in NT DLC,
  67. // but there is an group sap object on data link level.
  68. // The individual sap is registered to all its group saps
  69. // and llc level automatically routes all packets sent to
  70. // a group sap to all its registered members. The groups saps
  71. // are actually always open and they disappear automatically,
  72. // when there are no references to them any more.
  73. //
  74. if (!(pDlcParms->DlcOpenSap.OptionsPriority &
  75. (LLC_INDIVIDUAL_SAP | LLC_MEMBER_OF_GROUP_SAP | LLC_GROUP_SAP))) {
  76. //
  77. // Richard!!!!
  78. // IBM spec says, that one of those bits must be set, on the
  79. // other hand, Mike Allmond said, that IBM DLC accepts these
  80. // command. I don't belive it before a DOS application
  81. // tries to open dlc sap with all bits reset, then you
  82. // must accept it as a undocumented feature of IBM DLC.
  83. //
  84. return DLC_STATUS_INVALID_OPTION;
  85. } else if (!(pDlcParms->DlcOpenSap.OptionsPriority &
  86. (LLC_INDIVIDUAL_SAP | LLC_MEMBER_OF_GROUP_SAP))) {
  87. //
  88. // It was a group sap, they do not have an open context,
  89. // but their llc objects are created when they are referenced.
  90. //
  91. pDlcParms->DlcOpenSap.StationId = (USHORT)(((USHORT)pDlcParms->DlcOpenSap.SapValue << 8) | 0x0100);
  92. return STATUS_SUCCESS;
  93. }
  94. //
  95. // The lowest byte in sap value is undefine, we must reset
  96. // it to make it a valid individual DLC SAP number.
  97. //
  98. pDlcParms->DlcOpenSap.SapValue &= 0xfe;
  99. //
  100. // Check the double open, the slot must be empty
  101. //
  102. if (SapIndex == 0
  103. || SapIndex >= MAX_SAP_STATIONS
  104. || pFileContext->SapStationTable[SapIndex] != NULL) {
  105. return DLC_STATUS_INVALID_SAP_VALUE;
  106. }
  107. //
  108. // All DLC objects have the same size and they are allocated from
  109. // the packet pool (the normal binary buddy allocation has an average
  110. // 33% overhead).
  111. //
  112. pDlcObject = (PDLC_OBJECT)ALLOCATE_PACKET_DLC_OBJ(pFileContext->hLinkStationPool);
  113. if (pDlcObject) {
  114. pFileContext->SapStationTable[SapIndex] = pDlcObject;
  115. } else {
  116. return DLC_STATUS_NO_MEMORY;
  117. }
  118. //
  119. // We should do here some security checking using the security
  120. // descriptor of the current file context, but we do
  121. // not yet care about those things (nbf must implement
  122. // them first!)
  123. //
  124. pDlcObject->pFileContext = pFileContext;
  125. pDlcObject->Type = DLC_SAP_OBJECT;
  126. pDlcParms->DlcOpenSap.StationId = pDlcObject->StationId = (USHORT)pDlcParms->DlcOpenSap.SapValue << 8;
  127. pDlcObject->u.Sap.OptionsPriority = pDlcParms->DlcOpenSap.OptionsPriority;
  128. pDlcObject->u.Sap.DlcStatusFlag = pDlcParms->DlcOpenSap.DlcStatusFlag;
  129. pDlcObject->u.Sap.UserStatusValue = pDlcParms->DlcOpenSap.UserStatusValue;
  130. pDlcObject->u.Sap.MaxStationCount = pDlcParms->DlcOpenSap.StationCount;
  131. pDlcParms->DlcOpenSap.AvailableStations = pFileContext->LinkStationCount;
  132. XidHandlingOption = 0;
  133. if (!(pDlcObject->u.Sap.OptionsPriority & (UCHAR)XID_HANDLING_BIT)) {
  134. XidHandlingOption = LLC_HANDLE_XID_COMMANDS;
  135. }
  136. Status = LlcOpenSap(pFileContext->pBindingContext,
  137. pDlcObject,
  138. (UINT)pDlcParms->DlcOpenSap.SapValue,
  139. XidHandlingOption,
  140. &pDlcObject->hLlcObject
  141. );
  142. if (Status == STATUS_SUCCESS) {
  143. //
  144. // We will save the access priority bits with the other
  145. // link station parameters using LlcSetInformation.
  146. //
  147. pDlcParms->DlcOpenSap.LinkParameters.TokenRingAccessPriority = pDlcParms->DlcOpenSap.OptionsPriority & (UCHAR)0xE0;
  148. //
  149. // We know, that there will be no call backs from this
  150. // set information function => we don't need to release spin
  151. // locks.
  152. //
  153. LEAVE_DLC(pFileContext);
  154. Status = LlcSetInformation(pDlcObject->hLlcObject,
  155. DLC_INFO_CLASS_LINK_STATION,
  156. (PLLC_SET_INFO_BUFFER)&(pDlcParms->DlcOpenSap.LinkParameters),
  157. sizeof(DLC_LINK_PARAMETERS)
  158. );
  159. ENTER_DLC(pFileContext);
  160. }
  161. if (Status == STATUS_SUCCESS) {
  162. //
  163. // The global group SAP (0xFF) is opened for all sap
  164. // stations of dlc api.
  165. // BUG-BUG-BUG: How incompatible XID handling options are
  166. // handled in the case of the global group sap.
  167. //
  168. Status = LlcOpenSap(pFileContext->pBindingContext,
  169. pDlcObject,
  170. 0xff,
  171. LLC_HANDLE_XID_COMMANDS,
  172. &pDlcObject->u.Sap.GlobalGroupSapHandle
  173. );
  174. }
  175. if (Status == STATUS_SUCCESS) {
  176. //
  177. // Each SAP station 'allocates' a fixed number link stations.
  178. // This compatibility feature was implemented, because
  179. // some dlc apps might assume to be have only a fixed number
  180. // of link stations. We can't do the check earlier, because
  181. // another DlcOpenSap command would have been able to allocate
  182. // the link stations before this moment.
  183. //
  184. if (pDlcParms->DlcOpenSap.StationCount > pFileContext->LinkStationCount) {
  185. Status = DLC_STATUS_INADEQUATE_LINKS;
  186. } else {
  187. pFileContext->LinkStationCount -= pDlcObject->u.Sap.MaxStationCount;
  188. pDlcObject->State = DLC_OBJECT_OPEN;
  189. pFileContext->DlcObjectCount++;
  190. //
  191. // The flag and these reference counters keeps the llc object
  192. // alive, when we are working on it. We decerement
  193. // the llc object reference count when we don't have any more
  194. // synchronous commands going on. Zero llc reference count
  195. // on Dlc object dereferences the llc object.
  196. //
  197. pDlcObject->LlcObjectExists = TRUE;
  198. ReferenceLlcObject(pDlcObject);
  199. LlcReferenceObject(pDlcObject->hLlcObject);
  200. return STATUS_SUCCESS;
  201. }
  202. }
  203. //
  204. // error handling
  205. //
  206. pDlcParms->DlcOpenSap.AvailableStations = pFileContext->LinkStationCount;
  207. if (pDlcObject->hLlcObject != NULL) {
  208. pDlcObject->PendingLlcRequests++;
  209. LEAVE_DLC(pFileContext);
  210. LlcCloseStation(pDlcObject->hLlcObject, NULL);
  211. if (pDlcObject->u.Sap.GlobalGroupSapHandle != NULL) {
  212. LlcCloseStation(pDlcObject->u.Sap.GlobalGroupSapHandle, NULL);
  213. }
  214. ENTER_DLC(pFileContext);
  215. }
  216. #if LLC_DBG
  217. pDlcObject->pLinkStationList = NULL;
  218. #endif
  219. DEALLOCATE_PACKET_DLC_OBJ(pFileContext->hLinkStationPool, pDlcObject);
  220. pFileContext->SapStationTable[SapIndex] = NULL;
  221. return Status;
  222. }
  223. NTSTATUS
  224. DirOpenDirect(
  225. IN PIRP pIrp,
  226. IN PDLC_FILE_CONTEXT pFileContext,
  227. IN PNT_DLC_PARMS pDlcParms,
  228. IN ULONG InputBufferLength,
  229. IN ULONG OutputBufferLength
  230. )
  231. /*++
  232. Routine Description:
  233. Procedure opens the only direct station for a process specific adapter
  234. context. This implements DIR.OPEN.STATION.
  235. Arguments:
  236. pIrp - current io request packet
  237. pFileContext - DLC adapter context
  238. pDlcParms - the current parameter block
  239. InputBufferLength - the length of input parameters
  240. OutputBufferLength - the length of output parameters
  241. Return Value:
  242. NTSTATUS:
  243. STATUS_SUCCESS
  244. DLC_STATUS_NO_MEMORY
  245. DLC_STATUS_DIRECT_STATIONS_NOT_AVAILABLE
  246. --*/
  247. {
  248. PDLC_OBJECT pDlcObject;
  249. UINT Status;
  250. UNREFERENCED_PARAMETER(pIrp);
  251. UNREFERENCED_PARAMETER(InputBufferLength);
  252. UNREFERENCED_PARAMETER(OutputBufferLength);
  253. //
  254. // Check the double open, the slot must be empty
  255. //
  256. if (pFileContext->SapStationTable[0] != NULL) {
  257. return DLC_STATUS_DIRECT_STATIONS_NOT_AVAILABLE;
  258. }
  259. //
  260. // All DLC objects are allocated from the same size
  261. // optimized pool (the std binary buddy has ave. 33% overhead).
  262. //
  263. pDlcObject = pFileContext->SapStationTable[0] = (PDLC_OBJECT)ALLOCATE_PACKET_DLC_OBJ(pFileContext->hLinkStationPool);
  264. if (pDlcObject == NULL) {
  265. return DLC_STATUS_NO_MEMORY;
  266. }
  267. //
  268. // We should do here some security checking, but we do
  269. // not care about those things now (nbf must implement
  270. // them first!)
  271. //
  272. pDlcObject->pFileContext = pFileContext;
  273. pDlcObject->Type = DLC_DIRECT_OBJECT;
  274. pDlcObject->StationId = 0;
  275. pDlcObject->State = DLC_OBJECT_OPEN;
  276. LEAVE_DLC(pFileContext);
  277. if (pDlcParms->DirOpenDirect.usEthernetType > 1500) {
  278. //
  279. // Open a dix station to receive the defined frames
  280. //
  281. Status = LlcOpenDixStation(pFileContext->pBindingContext,
  282. (PVOID)pDlcObject,
  283. pDlcParms->DirOpenDirect.usEthernetType,
  284. &pDlcObject->hLlcObject
  285. );
  286. pDlcObject->u.Direct.ProtocolTypeMask = pDlcParms->DirOpenDirect.ulProtocolTypeMask;
  287. pDlcObject->u.Direct.ProtocolTypeMatch = pDlcParms->DirOpenDirect.ulProtocolTypeMatch;
  288. pDlcObject->u.Direct.ProtocolTypeOffset = pDlcParms->DirOpenDirect.usProtocolTypeOffset;
  289. } else {
  290. //
  291. // Open a dix station to receive the defined frames
  292. //
  293. Status = LlcOpenDirectStation(pFileContext->pBindingContext,
  294. (PVOID)pDlcObject,
  295. 0,
  296. &pDlcObject->hLlcObject
  297. );
  298. }
  299. ENTER_DLC(pFileContext);
  300. if (Status == STATUS_SUCCESS) {
  301. //
  302. // The flag and these reference counters keeps the llc object
  303. // alive, when we are working on it. We decerement
  304. // the llc object reference count when we don't have any more
  305. // synchronous commands going on. Zero llc reference count
  306. // on Dlc object dereferences the llc object.
  307. //
  308. pDlcObject->LlcObjectExists = TRUE;
  309. ReferenceLlcObject(pDlcObject);
  310. LlcReferenceObject(pDlcObject->hLlcObject);
  311. //
  312. // We will receive ALL mac frame types if any of the
  313. // mac bits has been set in the open options.
  314. //
  315. if (pDlcParms->DirOpenDirect.usOpenOptions & LLC_DIRECT_OPTIONS_ALL_MACS) {
  316. pDlcObject->u.Direct.OpenOptions = (USHORT)(-1);
  317. } else {
  318. pDlcObject->u.Direct.OpenOptions = (USHORT)~DLC_RCV_MAC_FRAMES;
  319. }
  320. pFileContext->DlcObjectCount++;
  321. } else {
  322. pFileContext->SapStationTable[0] = NULL;
  323. #if LLC_DBG
  324. pDlcObject->pLinkStationList = NULL;
  325. #endif
  326. DEALLOCATE_PACKET_DLC_OBJ(pFileContext->hLinkStationPool, pDlcObject);
  327. }
  328. return Status;
  329. }
  330. NTSTATUS
  331. DlcOpenLinkStation(
  332. IN PIRP pIrp,
  333. IN PDLC_FILE_CONTEXT pFileContext,
  334. IN PNT_DLC_PARMS pDlcParms,
  335. IN ULONG InputBufferLength,
  336. IN ULONG OutputBufferLength
  337. )
  338. /*++
  339. Routine Description:
  340. Procedure opens a new link station. DlcConnect is still needed to
  341. create the actual connection to the remote node.
  342. This implements DLC.OPEN.STATION
  343. Arguments:
  344. pIrp - current io request packet
  345. pFileContext - DLC adapter context
  346. pDlcParms - the current parameter block
  347. InputBufferLength - the length of input parameters
  348. Return Value:
  349. NTSTATUS:
  350. STATUS_SUCCESS
  351. DLC_STATUS_NO_MEMORY
  352. DLC_STATUS_INADEQUATE_LINKS
  353. --*/
  354. {
  355. NTSTATUS Status;
  356. PDLC_OBJECT pDlcObject;
  357. UNREFERENCED_PARAMETER(pIrp);
  358. UNREFERENCED_PARAMETER(InputBufferLength);
  359. UNREFERENCED_PARAMETER(OutputBufferLength);
  360. //
  361. // The local SAP must not be the NULL SAP or a group SAP!
  362. //
  363. if ((pDlcParms->DlcOpenStation.LinkStationId & 0x100) != 0
  364. || pDlcParms->DlcOpenStation.LinkStationId == 0) {
  365. return DLC_STATUS_INVALID_SAP_VALUE;
  366. }
  367. //
  368. // This must be a SAP station!
  369. //
  370. Status = GetSapStation(pFileContext,
  371. pDlcParms->DlcOpenStation.LinkStationId,
  372. &pDlcObject
  373. );
  374. if (Status == STATUS_SUCCESS) {
  375. //
  376. // Check the remote destination address, the broadcast bit
  377. // must not be set in that address. The remote SAP must not
  378. // either be a group or nul SAP
  379. //
  380. if ((pDlcParms->DlcOpenStation.aRemoteNodeAddress[0] & 0x80) != 0
  381. || pDlcParms->DlcOpenStation.RemoteSap == 0
  382. || (pDlcParms->DlcOpenStation.RemoteSap & 1) != 0) {
  383. return DLC_STATUS_INVALID_REMOTE_ADDRESS;
  384. }
  385. Status = InitializeLinkStation(pFileContext,
  386. pDlcObject,
  387. pDlcParms,
  388. NULL, // this is a local connect, no LLC link handle
  389. &pDlcObject
  390. );
  391. //
  392. // Set also the link station parameters, all nul
  393. // parameters are discarded by the data link.
  394. //
  395. if (Status == STATUS_SUCCESS) {
  396. LlcSetInformation(
  397. pDlcObject->hLlcObject,
  398. DLC_INFO_CLASS_LINK_STATION,
  399. (PLLC_SET_INFO_BUFFER)&pDlcParms->DlcOpenStation.LinkParameters,
  400. sizeof(DLC_LINK_PARAMETERS)
  401. );
  402. }
  403. }
  404. return Status;
  405. }
  406. NTSTATUS
  407. InitializeLinkStation(
  408. IN PDLC_FILE_CONTEXT pFileContext,
  409. IN PDLC_OBJECT pSap,
  410. IN PNT_DLC_PARMS pDlcParms OPTIONAL,
  411. IN PVOID LlcLinkHandle OPTIONAL,
  412. OUT PDLC_OBJECT *ppLinkStation
  413. )
  414. /*++
  415. Routine Description:
  416. This procedure allocates and initializes the link station.
  417. Arguments:
  418. pFileContext - DLC adapter context
  419. pSap - Sap object of the new link station
  420. pDlcParms - the current parameter block
  421. LlcHandle - Handle
  422. ppLinkStation - the new created link station
  423. Return Value:
  424. NTSTATUS:
  425. Success - STATUS_SUCCESS
  426. Failure - DLC_STATUS_NO_MEMORY
  427. DLC_STATUS_INADEQUATE_LINKS
  428. --*/
  429. {
  430. NTSTATUS Status;
  431. PDLC_OBJECT pLinkStation;
  432. UINT LinkIndex;
  433. //
  434. // There is allocated a limited number link stations for
  435. // this SAP, check if there is available link stations
  436. //
  437. if (pSap->u.Sap.LinkStationCount >= pSap->u.Sap.MaxStationCount) {
  438. return DLC_STATUS_INADEQUATE_LINKS;
  439. }
  440. //
  441. // Search the first free link station id
  442. //
  443. for (LinkIndex = 0;
  444. LinkIndex < MAX_LINK_STATIONS
  445. && pFileContext->LinkStationTable[LinkIndex] != NULL;
  446. LinkIndex++) {
  447. ; // NOP
  448. }
  449. //#ifdef DEBUG_CHK
  450. // //
  451. // // Link counters are out of sync ????
  452. // //
  453. // if (LinkIndex == MAX_LINK_STATIONS)
  454. // {
  455. // DEBUG_ERROR("DLC: Linkstation counters are out of sync!");
  456. // return DLC_STATUS_INADEQUATE_LINKS;
  457. // }
  458. //#endif
  459. //
  460. // Allocate the link station and initialize the station id field
  461. //
  462. pLinkStation = ALLOCATE_PACKET_DLC_OBJ(pFileContext->hLinkStationPool);
  463. if (pLinkStation == NULL) {
  464. return DLC_STATUS_NO_MEMORY;
  465. }
  466. //
  467. // Each link station has a preallocated event packet to receive
  468. // all DLC Status indications from the data link. There can
  469. // be several status indications set in the same status word.
  470. // The status is reset when its read from the event queue.
  471. //
  472. pLinkStation->u.Link.pStatusEvent = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
  473. if (pLinkStation->u.Link.pStatusEvent == NULL) {
  474. #if LLC_DBG
  475. pLinkStation->pLinkStationList = NULL;
  476. #endif
  477. DEALLOCATE_PACKET_DLC_OBJ(pFileContext->hLinkStationPool, pLinkStation);
  478. return DLC_STATUS_NO_MEMORY;
  479. }
  480. *ppLinkStation = pLinkStation;
  481. pFileContext->LinkStationTable[LinkIndex] = pLinkStation;
  482. pLinkStation->StationId = pSap->StationId | (USHORT)(LinkIndex + 1);
  483. pLinkStation->Type = DLC_LINK_OBJECT;
  484. pLinkStation->State = DLC_OBJECT_OPEN;
  485. pLinkStation->pFileContext = pFileContext;
  486. pSap->u.Sap.LinkStationCount++;
  487. //
  488. // Check if this is local or remote connection request, the remote
  489. // connection requests have already created an LLC link object
  490. //
  491. if (LlcLinkHandle == NULL) {
  492. //
  493. // local connection request
  494. //
  495. Status = LlcOpenLinkStation(pSap->hLlcObject, // SAP handle!
  496. pDlcParms->DlcOpenStation.RemoteSap,
  497. pDlcParms->DlcOpenStation.aRemoteNodeAddress,
  498. NULL,
  499. pLinkStation,
  500. &pLinkStation->hLlcObject
  501. );
  502. if (Status != STATUS_SUCCESS) {
  503. //
  504. // It didn't work for some reason, we are probably out of memory.
  505. // Free the slot in the link station table.
  506. //
  507. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pLinkStation->u.Link.pStatusEvent);
  508. #if LLC_DBG
  509. pLinkStation->pLinkStationList = NULL;
  510. #endif
  511. DEALLOCATE_PACKET_DLC_OBJ(pFileContext->hLinkStationPool, pLinkStation);
  512. pFileContext->LinkStationTable[LinkIndex] = NULL;
  513. pSap->u.Sap.LinkStationCount--;
  514. return Status;
  515. }
  516. pDlcParms->DlcOpenStation.LinkStationId = pLinkStation->StationId;
  517. } else {
  518. //
  519. // remote connection request
  520. //
  521. pLinkStation->hLlcObject = LlcLinkHandle;
  522. //
  523. // We must give the upper protocol handle to the link station,
  524. // otherwise the system bug checks, when the link is closed
  525. // before it is connected.
  526. //
  527. LlcBindLinkStation(LlcLinkHandle, pLinkStation);
  528. }
  529. //
  530. // The flag and these reference counters keeps the LLC object
  531. // alive, when we are working on it. We decerement
  532. // the LLC object reference count when we don't have any more
  533. // synchronous commands going on. Zero LLC reference count
  534. // on DLC object dereferences the LLC object
  535. //
  536. pLinkStation->LlcObjectExists = TRUE;
  537. ReferenceLlcObject(pLinkStation);
  538. LlcReferenceObject(pLinkStation->hLlcObject);
  539. //
  540. // Link this link station to the link list of all
  541. // link stations belonging to this sap (!?)
  542. //
  543. pFileContext->DlcObjectCount++;
  544. pLinkStation->u.Link.pSap = pSap;
  545. pLinkStation->pLinkStationList = pSap->pLinkStationList;
  546. pSap->pLinkStationList = pLinkStation;
  547. return STATUS_SUCCESS;
  548. }
  549. NTSTATUS
  550. DlcCloseStation(
  551. IN PIRP pIrp,
  552. IN PDLC_FILE_CONTEXT pFileContext,
  553. IN PNT_DLC_PARMS pDlcParms,
  554. IN ULONG InputBufferLength,
  555. IN ULONG OutputBufferLength
  556. )
  557. /*++
  558. Routine Description:
  559. Procedure closes a link, SAP or direct station. This implements
  560. DLC.CLOSE.STATION, DLC.CLOSE.SAP and DIR.CLOSE.DIRECT
  561. Arguments:
  562. pIrp - current io request packet
  563. pFileContext - DLC adapter context
  564. pDlcParms - the current parameter block
  565. InputBufferLength - the length of input parameters
  566. Return Value:
  567. NTSTATUS:
  568. Success - STATUS_SUCCESS
  569. STATUS_PENDING
  570. Failure - DLC_STATUS_NO_MEMORY
  571. --*/
  572. {
  573. PDLC_OBJECT pDlcObject;
  574. NTSTATUS Status;
  575. PDLC_CLOSE_WAIT_INFO pClosingInfo;
  576. UNREFERENCED_PARAMETER(InputBufferLength);
  577. UNREFERENCED_PARAMETER(OutputBufferLength);
  578. DIAG_FUNCTION("DlcCloseStation");
  579. //
  580. // It's OK to close any group sap id (we don't test them, because
  581. // those objects exists only in llc driver. The full implementation
  582. // of group saps would make this driver just too complicated)
  583. //
  584. if (pDlcParms->Async.Ccb.u.dlc.usStationId & 0x0100) {
  585. CompleteDirectOutIrp(pIrp, STATUS_SUCCESS, NULL);
  586. CompleteAsyncCommand(pFileContext, STATUS_SUCCESS, pIrp, NULL, FALSE);
  587. return STATUS_PENDING;
  588. }
  589. //
  590. // Procedure checks the sap and link station ids and
  591. // returns the requested link station.
  592. // The error status indicates a wrong sap or station id.
  593. //
  594. Status = GetStation(pFileContext,
  595. pDlcParms->Async.Ccb.u.dlc.usStationId,
  596. &pDlcObject
  597. );
  598. if (Status != STATUS_SUCCESS) {
  599. return Status;
  600. }
  601. //
  602. // Sap station cannot be closed until its all link stations
  603. // have been closed.
  604. //
  605. if ((pDlcObject->Type == DLC_SAP_OBJECT)
  606. && (pDlcObject->u.Sap.LinkStationCount != 0)) {
  607. return DLC_STATUS_LINK_STATIONS_OPEN;
  608. }
  609. pClosingInfo = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
  610. if (pClosingInfo == NULL) {
  611. return DLC_STATUS_NO_MEMORY;
  612. }
  613. pClosingInfo->pIrp = pIrp;
  614. pClosingInfo->CloseCounter = 0;
  615. pClosingInfo->Event = DLC_COMMAND_COMPLETION;
  616. pClosingInfo->CancelStatus = DLC_STATUS_CANCELLED_BY_USER;
  617. pClosingInfo->CancelReceive = TRUE;
  618. if (pDlcParms->Async.Ccb.CommandCompletionFlag != 0) {
  619. pClosingInfo->ChainCommands = TRUE;
  620. SearchReadCommandForClose(pFileContext,
  621. pClosingInfo,
  622. pDlcParms->Async.Ccb.pCcbAddress,
  623. pDlcParms->Async.Ccb.CommandCompletionFlag,
  624. pDlcObject->StationId,
  625. (USHORT)DLC_STATION_MASK_SPECIFIC
  626. );
  627. }
  628. CloseAnyStation(pDlcObject, pClosingInfo, FALSE);
  629. return STATUS_PENDING;
  630. }
  631. /*++
  632. Design notes about the dlc close commands
  633. -----------------------------------------
  634. All close operation must wait until the pending NDIS transmits
  635. have been completed. Thus they are asynchronous commands.
  636. The close commands of a DLC object will also return all
  637. CCBs of the pending commands and the received frames not yet read
  638. with the read command. The normal non-urgent close commands must
  639. wait also the queued DLC transmit to complete.
  640. There are three functions closing the dlc stations:
  641. - DlcCloseObject
  642. - DlcReset (sap and its link stations or all link stations)
  643. - DirCloseAdapter (almost same as reset, except marks the file object closed,
  644. the actual file close disconnects the NDIS adapter.
  645. All higher level functions allocates close completion data structure,
  646. that is used to complete the command, when there are no pending
  647. transmits in the associated stations.
  648. The lower level functions
  649. CloseAllStations - closes all open sap stations and the only direct station
  650. CloseAnyStation - initializes the close of any station,
  651. for a sap station it also calls recursively the
  652. link stations.
  653. CloseStation - closes the object immediately or waits
  654. until transmits have been completed and then
  655. does the same thing again.
  656. About the simultaneous reset and close commands
  657. -------------------------------------------------
  658. There are some very difficult problems with the
  659. simultaneous reset and close commands: each command
  660. must wait until all dlc objects associated with the command
  661. has been closed before the command itself cab be completed.
  662. It is completely legal to make first close for a station, then
  663. reset the sap of the same station (before the close completes) and
  664. then reset all sap stations (before the sap reset completes).
  665. On the other hand a dlc object can be linked only to one
  666. close/reset command and in this case all three commands should wait
  667. the completion of the same link station.
  668. //Solution 1 (a bad one):
  669. //There can be any number aof simultaneous close commands, because it
  670. //can be done to a dlc object only if it has no open substations.
  671. //There must be no other pending reset or close commands when a reset
  672. //command is executed, because some of its substations may already
  673. //be closing and they cannot be linked to the reset command.
  674. //
  675. //=>
  676. //We have a global close/reset command counter and a link list for the
  677. //pending reset commands. A close command can be given in any time
  678. //(even during a reset command, because all stations associated with
  679. //a reset are already closed and cannot be closed again).
  680. //A reset can be executed only if the global close/reset is zero.
  681. //The pending resets are queued. The close command completion
  682. //routines executes the first reset command from the queue, if the
  683. //!! Reset command must immediately mark all associated stations
  684. // closed to prevent any further use of those commands.
  685. Solution 2 (the final solution):
  686. -------------------------------
  687. The sequential and simultaneous close and reset commands can be given
  688. only to the dlc object being higher (or same) level than the destination
  689. of the previous command (close link, reset sap, reset all saps, close adapter)
  690. => close/reset events can be linked in the dlc objects (simultaneous
  691. close commands creates a split tree).
  692. The counters in all close/reset events are decremented and possibly
  693. executed when the dlc object is closed (when all transmits have been
  694. completed and the link stations disconnected).
  695. //
  696. // IBM has implemented the different close commands in this way:
  697. //
  698. // 1. DIR.CLOSE.DIRECT
  699. // - Undefined, I will do the same as with DLC.CLOSE.X commands
  700. // 2. DLC.CLOSE.SAP, DLC.CLOSE.STATION
  701. // - receive ccb linked to next ccb field without completion flag,
  702. // the receive command is completed normally, only return code
  703. // is set.
  704. // - all terminated commands linked after the receive ccb if
  705. // completion flag was defined and command itself read by
  706. // READ from the compeltion list.
  707. // The terminated commands (except receive) are completed normally.
  708. // 3. DLC.RESET
  709. // - The terminated pending CCBs are linked only if command completion
  710. // flag was defined.
  711. // 4. DIR.CLOSE.ADAPTER, DIR.INITIALIZE
  712. // - the terminated CCBs linked to the next ccb field of the command.
  713. // The command itself can be read with read command, if defined.
  714. //
  715. // (and now we do the same (12-FEB-1992))
  716. Note: all close functions returns VOID, because they can never fail.
  717. A hanging close command hangs up the process or event the whole system.
  718. We have a problem: the llc adapter may be closed, while there are
  719. still active LLC command packets pending in the NDIS queues => the
  720. NDIS adapter close must wait (sleep and loop) until its all objects
  721. have been deleted.
  722. --*/
  723. BOOLEAN
  724. CloseAllStations(
  725. IN PDLC_FILE_CONTEXT pFileContext,
  726. IN PIRP pIrp OPTIONAL,
  727. IN ULONG Event,
  728. IN PFCLOSE_COMPLETE pfCloseComplete OPTIONAL,
  729. IN PNT_DLC_PARMS pDlcParms OPTIONAL,
  730. IN PDLC_CLOSE_WAIT_INFO pClosingInfo
  731. )
  732. /*++
  733. Routine Description:
  734. This routine initializes closing all DLC stations. The command is
  735. asynchronously completed when all pending transmits have been sent
  736. and the link stations have been disconnected
  737. Arguments:
  738. pFileContext - process specific device context
  739. pIrp - the i.o request packet of the related command
  740. Event - event flag used to search a matching read for this command
  741. pfCloseComplete - completion appendage used when the DLC driver (or its
  742. process context) is closed.
  743. pDlcParms - DLC parameters from original system call
  744. pClosingInfo - pointer to DLC_CLOSE_WAIT_INFO structure
  745. Return Value:
  746. None - this must succeed always!
  747. --*/
  748. {
  749. PDLC_PACKET pPacket;
  750. USHORT i;
  751. USHORT FirstSap;
  752. BOOLEAN DoImmediateClose;
  753. NT_DLC_CCB AsyncCcb;
  754. ASSUME_IRQL(DISPATCH_LEVEL);
  755. if (pDlcParms == NULL) {
  756. //
  757. // Adapter Close always returns a pending status!
  758. // It completes the io- request by itself.
  759. //
  760. pDlcParms = (PNT_DLC_PARMS)&AsyncCcb;
  761. LlcZeroMem(&AsyncCcb, sizeof(AsyncCcb));
  762. }
  763. pClosingInfo->pIrp = pIrp;
  764. pClosingInfo->CloseCounter = 1; // keep object alive during sync path
  765. pClosingInfo->Event = Event;
  766. pClosingInfo->pfCloseComplete = pfCloseComplete;
  767. pClosingInfo->CancelStatus = (ULONG)DLC_STATUS_CANCELLED_BY_SYSTEM_ACTION;
  768. //
  769. // We zero the memory by default:
  770. // pClosingInfo->pCcbLink = NULL
  771. // pClosingInfo->pReadCommand = NULL
  772. //
  773. //
  774. // DLC.RESET must not close the direct station.
  775. // This flag is false for DLC.RESET but set for DIR.CLOSE.ADAPTER etc.
  776. //
  777. if (pDlcParms->Async.Ccb.uchDlcCommand == LLC_DLC_RESET) {
  778. FirstSap = 1; // don't delete the direct station
  779. DoImmediateClose = FALSE;
  780. pClosingInfo->CancelStatus = DLC_STATUS_CANCELLED_BY_USER;
  781. } else {
  782. FirstSap = 0; // if DIR.CLOSE.ADAPTER, can close everything
  783. DoImmediateClose = TRUE;
  784. pClosingInfo->ClosingAdapter = TRUE;
  785. }
  786. //
  787. // Chain the cancelled CCBs to the adapter close command or to a closing
  788. // event, if this is a global close command for adapter or a normal close
  789. // command (dlc.close.xxx, dlc.reset, dir.close.station) with a command
  790. // completion flag
  791. //
  792. if (Event == LLC_CRITICAL_EXCEPTION || pDlcParms->Async.Ccb.CommandCompletionFlag != 0) {
  793. pClosingInfo->ChainCommands = TRUE;
  794. SearchReadCommandForClose(pFileContext,
  795. pClosingInfo,
  796. pDlcParms->Async.Ccb.pCcbAddress,
  797. pDlcParms->Async.Ccb.CommandCompletionFlag,
  798. 0,
  799. 0 // search commands for all station ids
  800. );
  801. }
  802. //
  803. // This flag has been set, when user has issued DIR.INITIALIZE command,
  804. // that makes the hard reset for NDIS
  805. //
  806. if (pDlcParms->Async.Ccb.uchDlcCommand == LLC_DIR_INITIALIZE) {
  807. //
  808. // We cannot stop to closing, if the memory allocation fails,
  809. // It's better just to close the adapter without hard reset
  810. // that to fail the whole DIR.INITIALIZE command.
  811. //
  812. pPacket = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
  813. if (pPacket != NULL) {
  814. pClosingInfo->CloseCounter++;
  815. pPacket->ResetPacket.pClosingInfo = pClosingInfo;
  816. //
  817. // The reset command cancels all pending transmit requests!
  818. // => the closing of the stations should be very fast
  819. //
  820. LEAVE_DLC(pFileContext);
  821. LlcNdisReset(pFileContext->pBindingContext, &pPacket->LlcPacket);
  822. ENTER_DLC(pFileContext);
  823. }
  824. }
  825. if (pFileContext->DlcObjectCount != 0) {
  826. for (i = FirstSap; i < MAX_SAP_STATIONS; i++) {
  827. if (pFileContext->SapStationTable[i] != NULL) {
  828. CloseAnyStation(pFileContext->SapStationTable[i],
  829. pClosingInfo,
  830. DoImmediateClose
  831. );
  832. }
  833. }
  834. }
  835. //
  836. // Complete close command, if this was the last reference
  837. // of the close information
  838. //
  839. return DecrementCloseCounters(pFileContext, pClosingInfo);
  840. }
  841. VOID
  842. CloseAnyStation(
  843. IN PDLC_OBJECT pDlcObject,
  844. IN PDLC_CLOSE_WAIT_INFO pClosingInfo,
  845. IN BOOLEAN DoImmediateClose
  846. )
  847. /*++
  848. Routine Description:
  849. Procedure closes any station, and in the case of sap station it
  850. also calls recursively sap's all link stations before
  851. it closes the actual sap station.
  852. Arguments:
  853. pDlcObject - DLC object
  854. pClosingInfo - the information needed for the close/reset command
  855. completion (optionally by DLC read).
  856. DoImmediateClose - flag set when the stations are closed immediately
  857. Return Value:
  858. None - this must succeed always!
  859. --*/
  860. {
  861. PDLC_FILE_CONTEXT pFileContext = pDlcObject->pFileContext;
  862. PDLC_CLOSE_WAIT_INFO pCurrentClosingInfo;
  863. UINT i;
  864. DIAG_FUNCTION("CloseAnyStation");
  865. //
  866. // first close all link stations on this SAP. This must be done before the
  867. // object can be marked as deleted
  868. //
  869. if (pDlcObject->Type == DLC_SAP_OBJECT) {
  870. BOOLEAN SapObjectIsBadFood = FALSE;
  871. //
  872. // Delete all link stations using the current sap station.
  873. //
  874. for (i = 0; i < MAX_LINK_STATIONS; i++) {
  875. if (pFileContext->LinkStationTable[i] != NULL
  876. && pFileContext->LinkStationTable[i]->u.Link.pSap == pDlcObject) {
  877. //
  878. // the SAP object will be deleted when its last link object has
  879. // been deleted
  880. //
  881. if (pDlcObject->State == DLC_OBJECT_CLOSING) {
  882. SapObjectIsBadFood = TRUE;
  883. }
  884. CloseAnyStation(pFileContext->LinkStationTable[i],
  885. pClosingInfo,
  886. DoImmediateClose
  887. );
  888. }
  889. }
  890. //
  891. // it is highly probable that the SAP object is already deleted. The
  892. // close info counter was also decremented because the current closing
  893. // info packet was linked behind the old close packet by link station
  894. // cleanup, then completed when the SAP was closed after its last link
  895. // station was deleted
  896. //
  897. if (SapObjectIsBadFood) {
  898. return;
  899. }
  900. }
  901. //
  902. // We must queue simultaneous close/reset commands
  903. //
  904. if (pDlcObject->State == DLC_OBJECT_OPEN) {
  905. pDlcObject->State = DLC_OBJECT_CLOSING;
  906. pDlcObject->pClosingInfo = pClosingInfo;
  907. //
  908. // The close command has been queued, increment the counter
  909. //
  910. pClosingInfo->CloseCounter++;
  911. } else {
  912. //
  913. // Queue all simultaneous close/reset commands to a spanning TREE
  914. //
  915. // The linked closing info packets creates a spanning tree.
  916. // The newest (and stronges) close command is always the
  917. // root node. Even stronger close command would combine
  918. // the separate spanning trees to one single tree.
  919. // The root commands are completed, when its all sub-stations
  920. // have been closed and older commands have been completed.
  921. //
  922. // It is possible to have simultaneously pending:
  923. // 1. Close link station (pending)
  924. // 2. Close sap station (pending)
  925. // 3. Reset sap station (pending)
  926. // 4. Reset all saps with single command (pending)
  927. // 5. Resetting NDIS adapter with DirInitialize
  928. // OR Closing adapter with DirCloseAdapter
  929. // OR close initiated by process exit
  930. //
  931. // The commands cannot be executed in the reverse order,
  932. // because the stronger command would have already closed
  933. // affected station(s) or adapter.
  934. //
  935. for (pCurrentClosingInfo = pDlcObject->pClosingInfo;
  936. pCurrentClosingInfo != pClosingInfo;
  937. pCurrentClosingInfo = pCurrentClosingInfo->pNext) {
  938. if (pCurrentClosingInfo->pNext == NULL) {
  939. pCurrentClosingInfo->pNext = pClosingInfo;
  940. //
  941. // We link this close packet to many other close commands,
  942. // => we must add the count of all pending closing stations
  943. // to the current packet
  944. // (fix 28-03-1992, bug check when process exit during a
  945. // pending dlc reset).
  946. // (Bug-bug: close counter is not correct, when the previous
  947. // close command is still in sync code path => dlc reset
  948. // must decrement the next pointers in the queue).
  949. //
  950. pClosingInfo->CloseCounter += pCurrentClosingInfo->CloseCounter;
  951. break;
  952. }
  953. }
  954. }
  955. CloseStation(pFileContext, pDlcObject, DoImmediateClose);
  956. }
  957. VOID
  958. CloseStation(
  959. IN PDLC_FILE_CONTEXT pFileContext,
  960. IN PDLC_OBJECT pDlcObject,
  961. IN BOOLEAN DoImmediateClose
  962. )
  963. /*++
  964. Routine Description:
  965. This procedure starts the asychronous close of any DLC station
  966. object. It creates an asynchronous command completion packet
  967. for the station and returns.
  968. Arguments:
  969. pFileContext -
  970. pDlcObject - DLC object
  971. DoImmediateClose - the flag is set when the LLC object must be closed
  972. immediately without waiting the pending transmits
  973. Return Value:
  974. None - this must succeed always!
  975. --*/
  976. {
  977. PLLC_PACKET pClosePacket;
  978. DIAG_FUNCTION("CloseStation");
  979. //
  980. // we must cancel all pending transmits immediately,
  981. // when the adapter is closed.
  982. //
  983. if ((pDlcObject->State == DLC_OBJECT_CLOSING
  984. && (DoImmediateClose || pDlcObject->PendingLlcRequests == 0)
  985. && !(pDlcObject->Type == DLC_SAP_OBJECT && pDlcObject->u.Sap.LinkStationCount != 0))
  986. ||
  987. //
  988. // This condition forces the link to close even if
  989. // there was a pending disconnect command (it may be
  990. // waiting the other side and that may take a quite a while).
  991. // Otherwise the exit of a DLC app may hung up to 5 - 60 seconds)
  992. //
  993. (DoImmediateClose
  994. && pDlcObject->hLlcObject != NULL
  995. && pDlcObject->Type == DLC_LINK_OBJECT)) {
  996. //
  997. // Llc objects can be closed in any phase of operation.
  998. // The close command will cancel all transmit commands
  999. // not yet queued to NDIS and returns an asynchronous
  1000. // completion status, when the pending NDIS commands
  1001. // have been completed. The CloseCompletion indication
  1002. // handler uses the same PendingLlcRequestser as
  1003. // with the normal pending transmit commands.
  1004. // The immediate close first closes the LLC object and then
  1005. // waits the pending transmits (=> waits only transmits
  1006. // queued on NDIS).
  1007. // A graceful close does it vice versa: it first waits
  1008. // pending transmits and then does the actual close.
  1009. //
  1010. ASSERT(pDlcObject->ClosePacketInUse == 0);
  1011. if (pDlcObject->ClosePacketInUse == 1) {
  1012. pClosePacket = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
  1013. if (pClosePacket == NULL) {
  1014. //
  1015. // We don't have enough memory to make a graceful closing,
  1016. // We must do it in a quick and dirty way.
  1017. // We cannoot either wait llc to acknowledge the
  1018. // close, because we don't have any close packet
  1019. //
  1020. DoImmediateClose = TRUE;
  1021. } else {
  1022. pDlcObject->PendingLlcRequests++;
  1023. }
  1024. } else {
  1025. pClosePacket = &pDlcObject->ClosePacket;
  1026. pDlcObject->ClosePacketInUse = 1;
  1027. pDlcObject->PendingLlcRequests++;
  1028. }
  1029. pDlcObject->State = DLC_OBJECT_CLOSED;
  1030. if (pDlcObject->Type == DLC_LINK_OBJECT && !DoImmediateClose) {
  1031. //
  1032. // LlcDisconnect completion routine will close the link
  1033. // station and call this routine again, when the
  1034. // link station routine completes.
  1035. // We must reference the LLC object before the operation,
  1036. // otherwise there is a very small time window, that allows
  1037. // LLC object to be deleted while the disconnect
  1038. // operation is going on (and crash the system).
  1039. // (I hate pointer based interfaces)
  1040. //
  1041. ReferenceLlcObject(pDlcObject);
  1042. LEAVE_DLC(pFileContext);
  1043. //
  1044. // Data link driver returns a synchronous status only if
  1045. // if cannot complete command asynchronously, because it
  1046. // doesn't have a handle to the DLC object (the link
  1047. // station has not yet been
  1048. //
  1049. LlcDisconnectStation(pDlcObject->hLlcObject, pClosePacket);
  1050. ENTER_DLC(pFileContext);
  1051. DereferenceLlcObject(pDlcObject);
  1052. } else {
  1053. //
  1054. // we must close the link station immediately, if we for
  1055. // some reason cannot disconnect it normally.
  1056. //
  1057. if (pDlcObject->LlcObjectExists == TRUE) {
  1058. pDlcObject->LlcObjectExists = FALSE;
  1059. LEAVE_DLC(pFileContext);
  1060. LlcCloseStation(pDlcObject->hLlcObject, pClosePacket);
  1061. ENTER_DLC(pFileContext);
  1062. DereferenceLlcObject(pDlcObject);
  1063. }
  1064. }
  1065. //
  1066. // We must be able to close the driver even in out of memory conditions.
  1067. // LLC driver won't acknowledge the close if we connot allocate a packet
  1068. // for it
  1069. //
  1070. if (pClosePacket == NULL) {
  1071. CompleteCloseStation(pFileContext, pDlcObject);
  1072. }
  1073. }
  1074. }
  1075. VOID
  1076. CompleteCloseStation(
  1077. IN PDLC_FILE_CONTEXT pFileContext,
  1078. IN PDLC_OBJECT pDlcObject
  1079. )
  1080. /*++
  1081. Routine Description:
  1082. Procedure completes the close operation for any station object.
  1083. It also completes all close commands, that have been waiting
  1084. the closing of this station (or this station as the last member
  1085. of a group).
  1086. Arguments:
  1087. pFileContext - identifies owner of object
  1088. pDlcObject - dlc object
  1089. Return Value:
  1090. None.
  1091. --*/
  1092. {
  1093. //
  1094. // We must keep the LLC object alive, as far as there is any
  1095. // pending (transmit) commands in LLC.
  1096. //
  1097. if (pDlcObject->PendingLlcRequests == 0) {
  1098. //
  1099. // The station may still be waiting its transmit (and receive)
  1100. // commands to complete. We must poll the close station.
  1101. // if the status is still just closing.
  1102. //
  1103. if (pDlcObject->State == DLC_OBJECT_CLOSING) {
  1104. CloseStation(pFileContext, pDlcObject, FALSE);
  1105. } else {
  1106. PDLC_OBJECT pSapObject = NULL;
  1107. PDLC_CLOSE_WAIT_INFO pClosingInfo;
  1108. DLC_TRACE('N');
  1109. //
  1110. // The object must have been deleted from the file
  1111. // context when we enable spin lock in the next time,
  1112. // because the object is not any more in a consistent
  1113. // state.
  1114. //
  1115. if (pDlcObject->Type == DLC_LINK_OBJECT) {
  1116. DLC_TRACE('c');
  1117. //
  1118. // Remove the link station from the link station
  1119. // link list of its sap and link station table
  1120. // of the file context.
  1121. //
  1122. RemoveFromLinkList((PVOID *)&(pDlcObject->u.Link.pSap->pLinkStationList),
  1123. pDlcObject
  1124. );
  1125. pFileContext->LinkStationTable[(pDlcObject->StationId & 0xff) - 1] = NULL;
  1126. //
  1127. // Data link events have always the next pointer
  1128. // non-null, when they are in the event queue.
  1129. // The cleanup routine will remove and deallocate
  1130. // the packet when it is in the event queue.
  1131. //
  1132. if (pDlcObject->u.Link.pStatusEvent->LlcPacket.pNext == NULL) {
  1133. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool,
  1134. pDlcObject->u.Link.pStatusEvent
  1135. );
  1136. }
  1137. //
  1138. // Remove the possible memory committed by this link
  1139. // station during a buffer busy state. Normally
  1140. // the committed space is zero.
  1141. //
  1142. if (pFileContext->hBufferPool != NULL) {
  1143. BufUncommitBuffers(pFileContext->hBufferPool,
  1144. pDlcObject->CommittedBufferSpace
  1145. );
  1146. }
  1147. //
  1148. // The sap station must wait until its all link stations
  1149. // have been closed.
  1150. // Otherwise we will corrupt memory!!!!!!!!!
  1151. // ((would have been very hard and uncommon bug: reset
  1152. // of one station migth have corrupted a new dlc object
  1153. // created simultaneusly))
  1154. //
  1155. pDlcObject->u.Link.pSap->u.Sap.LinkStationCount--;
  1156. if (pDlcObject->u.Link.pSap->u.Sap.LinkStationCount == 0
  1157. && pDlcObject->u.Link.pSap->State == DLC_OBJECT_CLOSING) {
  1158. pSapObject = pDlcObject->u.Link.pSap;
  1159. }
  1160. } else {
  1161. //
  1162. // SAP station must wait until its all link stations
  1163. // have been closed!
  1164. //
  1165. if (pDlcObject->Type == DLC_SAP_OBJECT) {
  1166. if (pDlcObject->u.Sap.LinkStationCount != 0) {
  1167. return;
  1168. }
  1169. DLC_TRACE('d');
  1170. //
  1171. // All link stations have now been deleted, we can return
  1172. // the sap's link stations back to the global pool.
  1173. // The group sap can be deleted also.
  1174. //
  1175. pFileContext->LinkStationCount += pDlcObject->u.Sap.MaxStationCount;
  1176. LEAVE_DLC(pFileContext);
  1177. LlcCloseStation(pDlcObject->u.Sap.GlobalGroupSapHandle, NULL);
  1178. ENTER_DLC(pFileContext);
  1179. //
  1180. // Delete all group saps defined for this sap station
  1181. //
  1182. SetupGroupSaps(pFileContext, pDlcObject, 0, NULL);
  1183. }
  1184. pFileContext->SapStationTable[pDlcObject->StationId >> 9] = NULL;
  1185. }
  1186. pFileContext->DlcObjectCount--;
  1187. //
  1188. // The first and most specific close command will get all
  1189. // received frames and the transmit chain of the deleted object.
  1190. //
  1191. CleanUpEvents(pFileContext, pDlcObject->pClosingInfo, pDlcObject);
  1192. //
  1193. // The parallel close/reset commands have been queued in a
  1194. // link list, We must decrement and notify all dlc objects
  1195. //
  1196. // DecrementCloseCounters(pFileContext, pDlcObject->pClosingInfo);
  1197. //
  1198. // It's best to deallocate event packet after the
  1199. // cleanup of the event queue
  1200. //
  1201. #if LLC_DBG
  1202. pDlcObject->pLinkStationList = NULL;
  1203. pDlcObject->State = DLC_OBJECT_INVALID_TYPE;
  1204. #endif
  1205. //
  1206. // RLF 08/17/94
  1207. //
  1208. // grab the pointer to the closing info structure before deallocating
  1209. // the DLC object
  1210. //
  1211. pClosingInfo = pDlcObject->pClosingInfo;
  1212. DEALLOCATE_PACKET_DLC_OBJ(pFileContext->hLinkStationPool, pDlcObject);
  1213. //
  1214. // the close completion of the last link station closes
  1215. // also the sap object of that link station, if the
  1216. // sap closing was waiting to closing of the link station
  1217. //
  1218. if (pSapObject != NULL) {
  1219. CloseStation(pFileContext, pSapObject, TRUE);
  1220. //
  1221. // TRUE: must be at least
  1222. // DLC.RESET
  1223. //
  1224. }
  1225. //
  1226. // RLF 08/17/94
  1227. //
  1228. // Moved this call to DecrementCloseCounters from its previous
  1229. // place above. Once again, we find that things are happening out
  1230. // of sequence: this time, if we decrement the close counters,
  1231. // causing them to go to zero before we have freed the DLC object
  1232. // then the file context structure and its buffer pools are
  1233. // deallocated. But the DLC object was allocated from the now
  1234. // deleted pool, meaning sooner or later we corrupt non-paged pool
  1235. //
  1236. //
  1237. // The parallel close/reset commands have been queued in a
  1238. // link list, We must decrement and notify all dlc objects
  1239. //
  1240. DecrementCloseCounters(pFileContext, pClosingInfo);
  1241. }
  1242. }
  1243. }
  1244. VOID
  1245. CompleteCloseReset(
  1246. IN PDLC_FILE_CONTEXT pFileContext,
  1247. IN PDLC_CLOSE_WAIT_INFO pClosingInfo
  1248. )
  1249. /*++
  1250. Routine Description:
  1251. The primitive builds a completion event for the close/reset
  1252. of a dlc object. The close/reset may have been initiated by
  1253. DlcReset, DirCloseAdapter, DirInitialize or because the NDIS
  1254. driver is closing (eg. Unbind command).
  1255. In the last case pClosingInfo->pIrp is NULL, because there
  1256. is no command related to the event.
  1257. The only (major) difference from the IBM OS/2 DLC is, that
  1258. the first_buffer_addr parameter is not supported, because it
  1259. is meaningless with he NT buffer management.
  1260. The buffer pool is managed by dlc, not by the application.
  1261. Arguments:
  1262. FileContext - the process specific device context
  1263. pClosingInfo - all information needed for close or reset command completion
  1264. pDlcObject - the closed or deleted object
  1265. Return Value:
  1266. None.
  1267. --*/
  1268. {
  1269. BOOLEAN completeRead = FALSE;
  1270. BOOLEAN deallocatePacket = FALSE;
  1271. BOOLEAN derefFileContext = FALSE;
  1272. //
  1273. // Now we can cancel and chain all commands, that are still left,
  1274. // if we are really closing this adapter context
  1275. // (there should be no events any more, because the were deleted
  1276. // with their owner objects).
  1277. //
  1278. if (pClosingInfo->ClosingAdapter) {
  1279. for (;;) {
  1280. NTSTATUS Status;
  1281. Status = AbortCommand(
  1282. pFileContext,
  1283. DLC_IGNORE_STATION_ID, // station id may be anything
  1284. DLC_STATION_MASK_ALL, // mask for all station ids!
  1285. DLC_MATCH_ANY_COMMAND, // mask for all commands
  1286. &pClosingInfo->pCcbLink, // link them to here
  1287. pClosingInfo->CancelStatus, // cancel with this status
  1288. FALSE // Don't suppress completion
  1289. );
  1290. if (Status != STATUS_SUCCESS) {
  1291. break;
  1292. }
  1293. pClosingInfo->CcbCount++;
  1294. }
  1295. }
  1296. //
  1297. // The receive command must be linked to the first CCB immediately
  1298. // after the actual cancelling command.
  1299. //
  1300. if (pClosingInfo->pRcvCommand != NULL) {
  1301. CancelDlcCommand(pFileContext,
  1302. pClosingInfo->pRcvCommand,
  1303. &pClosingInfo->pCcbLink,
  1304. pClosingInfo->CancelStatus,
  1305. TRUE // disable command completion for RECEIVE
  1306. );
  1307. pClosingInfo->CcbCount++;
  1308. }
  1309. //
  1310. // Should the completed commands to be saved as a completion event.
  1311. //
  1312. if (pClosingInfo->pCompletionInfo != NULL) {
  1313. PDLC_COMPLETION_EVENT_INFO pCompletionInfo;
  1314. pCompletionInfo = pClosingInfo->pCompletionInfo;
  1315. //
  1316. // search all receive data events destinated to the closed or
  1317. // reset station or stations. We must chain all those
  1318. // buffer to the single NULL terminated list
  1319. //
  1320. pCompletionInfo->CcbCount = (USHORT)(pClosingInfo->CcbCount + 1);
  1321. //
  1322. // Save the received frames to the completion information!
  1323. // NOTE: The received frames returned by DIR.CLOSE.ADAPTER
  1324. // cannot be released using the same adapter handle.
  1325. // They are released and unlocked if the closed adapter
  1326. // was the only user of the pool. Otherwise those frames
  1327. // must be unlocked using another adapter handle, that
  1328. // shares the same buffer pool.
  1329. // !!! Actually we should automatically free all receive
  1330. // buffers when an adapter is closed and do not to return
  1331. // them to application !!!
  1332. //
  1333. pCompletionInfo->pReceiveBuffers = pClosingInfo->pRcvFrames;
  1334. //
  1335. // Execute the old READ command or queue the command completion
  1336. // request to the command queue.
  1337. //
  1338. if (pClosingInfo->pReadCommand != NULL) {
  1339. //
  1340. // RLF 03/25/94
  1341. //
  1342. // See below
  1343. //
  1344. completeRead = TRUE;
  1345. /*
  1346. pClosingInfo->pReadCommand->Overlay.pfCompletionHandler(
  1347. pFileContext,
  1348. NULL,
  1349. pClosingInfo->pReadCommand->pIrp,
  1350. (UINT)pClosingInfo->Event,
  1351. pCompletionInfo,
  1352. 0
  1353. );
  1354. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pClosingInfo->pReadCommand);
  1355. */
  1356. } else {
  1357. //
  1358. // Queue the completion event, Note: we will return all
  1359. // CCBs linked to the issued close CCB in any way.
  1360. // It does not matter for eg. DirCloseAdapter, if there
  1361. // is an extra event queued. It will be deleted when
  1362. // the command completes and all memory resources are
  1363. // released.
  1364. //
  1365. MakeDlcEvent(pFileContext,
  1366. pClosingInfo->Event,
  1367. pCompletionInfo->StationId,
  1368. NULL,
  1369. pCompletionInfo,
  1370. 0,
  1371. pClosingInfo->FreeCompletionInfo
  1372. );
  1373. }
  1374. } else if (pFileContext->hBufferPool != NULL) {
  1375. //
  1376. // Free the received frames in the buffer pool, they are
  1377. // not saved to the command completion list.
  1378. //
  1379. BufferPoolDeallocateList(pFileContext->hBufferPool,
  1380. pClosingInfo->pRcvFrames
  1381. );
  1382. }
  1383. //
  1384. // DirCloseAdapter requires a special post routine, that will
  1385. // close the NDIS binding when all pending transmits have completed
  1386. // and the the requests have been cancelled.
  1387. // Note: the close adapter packet is not allocated from packet pool!
  1388. //
  1389. /*
  1390. //
  1391. // RLF 08/17/94
  1392. //
  1393. if (pClosingInfo->pfCloseComplete != NULL) {
  1394. pClosingInfo->pfCloseComplete(pFileContext,
  1395. pClosingInfo,
  1396. pClosingInfo->pCcbLink
  1397. );
  1398. } else {
  1399. */
  1400. if (pClosingInfo->pfCloseComplete == NULL) {
  1401. if (pClosingInfo->pIrp != NULL) {
  1402. CompleteDirectOutIrp(pClosingInfo->pIrp,
  1403. STATUS_SUCCESS,
  1404. pClosingInfo->pCcbLink
  1405. );
  1406. CompleteAsyncCommand(pFileContext,
  1407. STATUS_SUCCESS,
  1408. pClosingInfo->pIrp,
  1409. pClosingInfo->pCcbLink,
  1410. FALSE
  1411. );
  1412. }
  1413. #if LLC_DBG
  1414. pClosingInfo->pNext = NULL;
  1415. #endif
  1416. //
  1417. // RLF 03/25/94
  1418. //
  1419. // More asynchronicity with READs causing fatal errors in an application.
  1420. // This actual case was in HPMON:
  1421. //
  1422. // 1. application submits DLC.CLOSE.STATION
  1423. // 2. this routine puts DLC.CLOSE.STATION command in command complete
  1424. // list of READ parameter table. READ IRP is completed
  1425. // 3. app gets READ completion, sees DLC.CLOSE.STATION is complete
  1426. // and frees DLC.CLOSE.STATION CCB to heap: heap manager writes
  1427. // signature data over freed CCB
  1428. // 4. this routine completes original DLC.CLOSE.STATION IRP, writing
  1429. // 8 bytes over original CCB, now just part of heap
  1430. // 5. some time later, heap allocation request made. Heap manager
  1431. // finds the heap has been trashed and goes on strike
  1432. //
  1433. if (completeRead) {
  1434. pClosingInfo->pReadCommand->Overlay.pfCompletionHandler(
  1435. pFileContext,
  1436. NULL,
  1437. pClosingInfo->pReadCommand->pIrp,
  1438. (UINT)pClosingInfo->Event,
  1439. pClosingInfo->pCompletionInfo,
  1440. 0
  1441. );
  1442. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pClosingInfo->pReadCommand);
  1443. }
  1444. //
  1445. // RLF 08/17/94
  1446. //
  1447. // don't deallocate the packet now - we may need to use it if we call
  1448. // the close completion handler below
  1449. //
  1450. deallocatePacket = TRUE;
  1451. /*
  1452. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pClosingInfo);
  1453. */
  1454. }
  1455. //
  1456. // RLF 08/17/94
  1457. //
  1458. // Moved the DirCloseAdapter processing here to give the client chance to
  1459. // receive the event before we close the adapter and maybe kill the file
  1460. // context
  1461. //
  1462. if (pClosingInfo->pfCloseComplete) {
  1463. //
  1464. // RLF 08/17/94
  1465. //
  1466. // This is bad: this close complete call may cause the file context to
  1467. // become completely dereferenced, and hence free it and its buffer
  1468. // pools. But we still have the closing info packet allocated, so
  1469. // increase the reference count, free up the packet below, then deref
  1470. // the file context again, and cause it to be deleted (if that would
  1471. // have happened anyway)
  1472. //
  1473. ReferenceFileContext(pFileContext);
  1474. derefFileContext = TRUE;
  1475. pClosingInfo->pfCloseComplete(pFileContext, pClosingInfo, pClosingInfo->pCcbLink);
  1476. }
  1477. if (deallocatePacket) {
  1478. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pClosingInfo);
  1479. }
  1480. if (derefFileContext) {
  1481. DereferenceFileContext(pFileContext);
  1482. }
  1483. }
  1484. VOID
  1485. CleanUpEvents(
  1486. IN PDLC_FILE_CONTEXT pFileContext,
  1487. IN PDLC_CLOSE_WAIT_INFO pClosingInfo,
  1488. IN PDLC_OBJECT pDlcObject
  1489. )
  1490. /*++
  1491. Routine Description:
  1492. The primitive cleans up or modifies all events having a pointer
  1493. to the closed station object. This also chains one and only one
  1494. transmit ccb chain to the end of CCB chain, because the completed
  1495. commands (as transmit and command completion events in the event queue)
  1496. cannot be linked any more to other commands. Thus there can be
  1497. only one single chain in the end of the actual chain of the pending
  1498. commands.
  1499. This routines cleans up the commands as well.
  1500. Arguments:
  1501. FileContext - the process specific device context
  1502. pClosingInfo - all information needed for close or reset command
  1503. completion
  1504. pDlcObject - the closed or deleted object
  1505. Return Value:
  1506. STATUS_SUCCESS
  1507. --*/
  1508. {
  1509. PDLC_EVENT pNextEvent;
  1510. PDLC_EVENT pEvent;
  1511. BOOLEAN RemoveNextPacket;
  1512. for (pEvent = (PDLC_EVENT)pFileContext->EventQueue.Flink;
  1513. pEvent != (PDLC_EVENT)&pFileContext->EventQueue;
  1514. pEvent = pNextEvent) {
  1515. pNextEvent = (PDLC_EVENT)pEvent->LlcPacket.pNext;
  1516. if (pEvent->pOwnerObject == pDlcObject) {
  1517. //
  1518. // By defult we free the next packet
  1519. //
  1520. RemoveNextPacket = TRUE;
  1521. switch (pEvent->Event) {
  1522. case LLC_RECEIVE_DATA:
  1523. //
  1524. // The received frames are saved to circular lists,
  1525. // where the head points to the newest frame and
  1526. // the next element from it is the oldest one.
  1527. // We simply the new frames to the old head of list.
  1528. //
  1529. if (pClosingInfo->pRcvFrames == NULL) {
  1530. pClosingInfo->pRcvFrames = pEvent->pEventInformation;
  1531. } else {
  1532. //
  1533. // Initial state:
  1534. // H1 = N1->O1...->N1 and H2 = N2->O2...->N2
  1535. //
  1536. // End state:
  1537. // H1 = N1->O2...->N2->O1...->N1
  1538. //
  1539. // => Operations must be:
  1540. // Temp = H2->Next;
  1541. // H2->Next = H1->Next;
  1542. // H1->Next = Temp;
  1543. // (where H = list head, N = newest element, O = oldest)
  1544. //
  1545. PDLC_BUFFER_HEADER pTemp;
  1546. pTemp = ((PDLC_BUFFER_HEADER)pEvent->pEventInformation)->FrameBuffer.pNextFrame;
  1547. ((PDLC_BUFFER_HEADER)pEvent->pEventInformation)->FrameBuffer.pNextFrame =
  1548. ((PDLC_BUFFER_HEADER)pClosingInfo->pRcvFrames)->FrameBuffer.pNextFrame;
  1549. ((PDLC_BUFFER_HEADER)pClosingInfo->pRcvFrames)->FrameBuffer.pNextFrame = pTemp;
  1550. }
  1551. pDlcObject->pReceiveEvent = NULL;
  1552. break;
  1553. case LLC_TRANSMIT_COMPLETION:
  1554. //
  1555. // We cannot do nothing for single transmit commands, because
  1556. // they have already been completed, and the completed CCBs
  1557. // cannot any more be linked together. Thus we leave
  1558. // them to the event queue and will hope, that somebody
  1559. // will read them from the event queue. The memory is
  1560. // released when the file context is closed (eg. file close in
  1561. // the process exit). We just reset the dlc object pointer,
  1562. // that nobody would later use invalid pointer.
  1563. //
  1564. // The transmit commands chained of one closed station can
  1565. // be removed from the event list and chained to
  1566. // the end of the CCBs, BUT ONLY ONE! All other
  1567. // transmit completion events must be saved as a normal
  1568. // events with an invalid CCB count!!!!!
  1569. //
  1570. if (pClosingInfo->pCcbLink == NULL && pClosingInfo->ChainCommands) {
  1571. pClosingInfo->pCcbLink = pDlcObject->pPrevXmitCcbAddress;
  1572. pClosingInfo->CcbCount += pDlcObject->ChainedTransmitCount;
  1573. } else {
  1574. //
  1575. // We must change the format of this transmit completion
  1576. // into the similar to the command completion event
  1577. // packet of close command. Otherwise the application
  1578. // could lose the transmit CCBs, when it closes or
  1579. // resets a station.
  1580. //
  1581. PDLC_COMPLETION_EVENT_INFO pCompletionInfo;
  1582. pCompletionInfo = (PDLC_COMPLETION_EVENT_INFO)
  1583. ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
  1584. if (pCompletionInfo != NULL) {
  1585. pCompletionInfo->CcbCount = pDlcObject->ChainedTransmitCount;
  1586. pCompletionInfo->pCcbAddress = pDlcObject->pPrevXmitCcbAddress;
  1587. pCompletionInfo->CommandCompletionFlag = pEvent->SecondaryInfo;
  1588. pEvent->SecondaryInfo = 0;
  1589. pEvent->pEventInformation = pCompletionInfo;
  1590. pEvent->bFreeEventInfo = TRUE;
  1591. RemoveNextPacket = FALSE;
  1592. }
  1593. }
  1594. break;
  1595. //
  1596. // case DLC_COMMAND_COMPLETION ?
  1597. // The command completions have been saved without the
  1598. // the link to the Dlc structure -> they are automatically
  1599. // left into the completion queue.
  1600. //
  1601. case LLC_STATUS_CHANGE:
  1602. //
  1603. // Link station status changes cannot mean anytging after the
  1604. // link station has been deleted.
  1605. //
  1606. break;
  1607. #if LLC_DBG
  1608. default:
  1609. LlcInvalidObjectType();
  1610. break;
  1611. #endif
  1612. };
  1613. if (RemoveNextPacket) {
  1614. LlcRemoveEntryList(pEvent);
  1615. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pEvent);
  1616. } else {
  1617. //
  1618. // We must remove the reference to the deleted object
  1619. //
  1620. pEvent->pOwnerObject = NULL;
  1621. }
  1622. }
  1623. }
  1624. //
  1625. // The optional receive command must be removed first, otherwise
  1626. // it is cancelled with the other commands given to the deleted
  1627. // object.
  1628. //
  1629. if (pClosingInfo->CancelReceive && pDlcObject->pRcvParms != NULL) {
  1630. //
  1631. // The receive command linked to the DLC object is a special case:
  1632. // we must link it immediately after the close CCB
  1633. //
  1634. pClosingInfo->pRcvCommand = SearchAndRemoveAnyCommand(
  1635. pFileContext,
  1636. (ULONG)(-1),
  1637. (USHORT)DLC_IGNORE_STATION_ID,
  1638. (USHORT)DLC_STATION_MASK_SPECIFIC,
  1639. pDlcObject->pRcvParms->Async.Ccb.pCcbAddress
  1640. );
  1641. pDlcObject->pRcvParms = NULL;
  1642. }
  1643. //
  1644. // Cleanup the commands given to the dleted object
  1645. //
  1646. for (;;) {
  1647. NTSTATUS Status;
  1648. Status = AbortCommand(pFileContext,
  1649. pDlcObject->StationId,
  1650. (USHORT)(pDlcObject->Type == (UCHAR)DLC_SAP_OBJECT
  1651. ? DLC_STATION_MASK_SAP
  1652. : DLC_STATION_MASK_SPECIFIC),
  1653. DLC_IGNORE_SEARCH_HANDLE,
  1654. &pClosingInfo->pCcbLink,
  1655. pClosingInfo->CancelStatus,
  1656. FALSE // Don't suppress completion
  1657. );
  1658. if (Status != STATUS_SUCCESS) {
  1659. break;
  1660. }
  1661. //
  1662. // Now we can cancel and chain all commands destinated to the
  1663. // closed/reset station id.
  1664. // We always complete the commands given to the deletcd object,
  1665. // but we chain them together only if this flag has been set.
  1666. //
  1667. if (pClosingInfo->ChainCommands == FALSE) {
  1668. //
  1669. // Don't link the cancelled CCBs together
  1670. //
  1671. pClosingInfo->pCcbLink = NULL;
  1672. } else {
  1673. pClosingInfo->CcbCount++;
  1674. }
  1675. }
  1676. }
  1677. VOID
  1678. SearchReadCommandForClose(
  1679. IN PDLC_FILE_CONTEXT pFileContext,
  1680. IN PDLC_CLOSE_WAIT_INFO pClosingInfo,
  1681. IN PVOID pCcbAddress,
  1682. IN ULONG CommandCompletionFlag,
  1683. IN USHORT StationId,
  1684. IN USHORT StationIdMask
  1685. )
  1686. /*++
  1687. Routine Description:
  1688. The primitive searches a read command for a close command
  1689. and saves it into the closing info structure.
  1690. Arguments:
  1691. FileContext - the process specific device context
  1692. pClosingInfo - all information needed for close or reset command
  1693. completion
  1694. pCcbAddress - ccb address of the searched read command
  1695. StationId -
  1696. StationIdMask -
  1697. Return Value:
  1698. None.
  1699. --*/
  1700. {
  1701. //
  1702. // Allocate the parameter buffer for command completion with
  1703. // read if it is needed OR if we are closing everything because
  1704. // of a critical exception (ie. pIrp == NULL)
  1705. //
  1706. pClosingInfo->pCompletionInfo = (PDLC_COMPLETION_EVENT_INFO)
  1707. ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
  1708. if (pClosingInfo->pCompletionInfo != NULL) {
  1709. pClosingInfo->FreeCompletionInfo = TRUE;
  1710. //
  1711. // We must link all commands given to the deleted objects
  1712. //
  1713. pClosingInfo->pCompletionInfo->pCcbAddress = pCcbAddress;
  1714. pClosingInfo->pCompletionInfo->CommandCompletionFlag = CommandCompletionFlag;
  1715. pClosingInfo->ChainCommands = TRUE;
  1716. //
  1717. // A link station close command we be read as a command completion
  1718. // on its sap, but the other close commands cannot use any station id
  1719. //
  1720. if (StationIdMask == DLC_STATION_MASK_SPECIFIC) {
  1721. pClosingInfo->pCompletionInfo->StationId = (USHORT)(StationId & DLC_STATION_MASK_SAP);
  1722. } else {
  1723. pClosingInfo->pCompletionInfo->StationId = 0;
  1724. }
  1725. //
  1726. // Search first a special READ command dedicated only for
  1727. // this command completion. We must read the optional
  1728. // read command NOW. Otherwise it will be canceled
  1729. // with the other commands, that have been given for
  1730. // the deleted station(s).
  1731. //
  1732. pClosingInfo->pReadCommand = SearchAndRemoveCommandByHandle(
  1733. &pFileContext->CommandQueue,
  1734. pClosingInfo->Event,
  1735. (USHORT)DLC_IGNORE_STATION_ID,
  1736. (USHORT)DLC_STATION_MASK_SPECIFIC,
  1737. pCcbAddress
  1738. );
  1739. if (pClosingInfo->pReadCommand == NULL) {
  1740. //
  1741. // We do not really care about the result, because
  1742. // it is OK to return NULL. This completion event
  1743. // may be read sometime later.
  1744. //
  1745. pClosingInfo->pReadCommand = SearchAndRemoveCommand(
  1746. &pFileContext->CommandQueue,
  1747. pClosingInfo->Event,
  1748. StationId,
  1749. StationIdMask
  1750. );
  1751. }
  1752. }
  1753. }
  1754. VOID
  1755. CompleteLlcObjectClose(
  1756. IN PDLC_OBJECT pDlcObject
  1757. )
  1758. /*++
  1759. Routine Description:
  1760. This routine just derefernces a llc object, when its reference count
  1761. in DLC driver has been decremented to zero.
  1762. The reference count is used to prevent the closing of llc object
  1763. when it is simultaneously called elsewhere (that would invalidate
  1764. the llc object pointer)
  1765. Arguments:
  1766. pDlcObject - any DLC object.
  1767. Return Value:
  1768. none
  1769. --*/
  1770. {
  1771. PVOID hLlcObject = pDlcObject->hLlcObject;
  1772. if (hLlcObject != NULL) {
  1773. DLC_TRACE('P');
  1774. pDlcObject->hLlcObject = NULL;
  1775. LEAVE_DLC(pDlcObject->pFileContext);
  1776. LlcDereferenceObject(hLlcObject);
  1777. ENTER_DLC(pDlcObject->pFileContext);
  1778. }
  1779. }
  1780. BOOLEAN
  1781. DecrementCloseCounters(
  1782. PDLC_FILE_CONTEXT pFileContext,
  1783. PDLC_CLOSE_WAIT_INFO pClosingInfo
  1784. )
  1785. /*++
  1786. Routine Description:
  1787. This routine decrements the count of existing objects in the
  1788. chianed close command packets and completes the close commands,
  1789. if the count of the existing objects hits zero.
  1790. Arguments:
  1791. pFileContext - file handle context
  1792. pClosingInfo - close command packet
  1793. Return Value:
  1794. BOOLEAN
  1795. TRUE - all pending close/resets have been completed
  1796. FALSE - close/resets still pending
  1797. --*/
  1798. {
  1799. PDLC_CLOSE_WAIT_INFO pNextClosingInfo;
  1800. UINT loopCounter, closeCounter;
  1801. //
  1802. // Complete the reset command if all objects have been deleted,
  1803. // There may be another DirCloseAdapter chained its next pointer
  1804. //
  1805. for (loopCounter = 0, closeCounter = 0;
  1806. pClosingInfo != NULL;
  1807. pClosingInfo = pNextClosingInfo, ++loopCounter) {
  1808. pNextClosingInfo = pClosingInfo->pNext;
  1809. pClosingInfo->CloseCounter--;
  1810. if (pClosingInfo->CloseCounter == 0) {
  1811. //
  1812. // Call the completion routine of the close command.
  1813. // We don't need to check the status code.
  1814. //
  1815. CompleteCloseReset(pFileContext, pClosingInfo);
  1816. ++closeCounter;
  1817. }
  1818. }
  1819. //
  1820. // if we completed every close/reset we found then return TRUE
  1821. //
  1822. return loopCounter == closeCounter;
  1823. }
  1824. VOID
  1825. CompleteDirectOutIrp(
  1826. IN PIRP Irp,
  1827. IN UCHAR Status,
  1828. IN PLLC_CCB NextCcb
  1829. )
  1830. /*++
  1831. Routine Description:
  1832. For an IRP submitted as method DIRECT_OUT (DLC.CLOSE.STATION) complete the
  1833. CCB in user space by getting the mapped system address of the CCB and update
  1834. it with the completion code and next CCB pointer
  1835. Arguments:
  1836. Irp - pointer to DIRECT_OUT IRP to complete
  1837. Status - DLC status code
  1838. NextCcb - pointer to next CCB to chain
  1839. Return Value:
  1840. None.
  1841. --*/
  1842. {
  1843. PLLC_CCB ccb;
  1844. ccb = (PLLC_CCB)MmGetSystemAddressForMdl(Irp->MdlAddress);
  1845. RtlStoreUlongPtr((PULONG_PTR)&ccb->pNext, (ULONG_PTR)NextCcb);
  1846. ccb->uchDlcStatus = Status;
  1847. }