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.

1596 lines
50 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1991 Nokia Data Systems AB
  4. Module Name:
  5. dlcindc.c
  6. Abstract:
  7. This module includes primitives to handle all events
  8. and indications from the LLC (802.2 data link) module.
  9. Contents:
  10. LlcReceiveIndication
  11. LlcEventIndication
  12. LlcCommandCompletion
  13. CompleteTransmitCommand
  14. CompleteDlcCommand
  15. Author:
  16. Antti Saarenheimo 01-Sep-1991
  17. Environment:
  18. Kernel mode
  19. Revision History:
  20. --*/
  21. //
  22. // This define enables the private DLC function prototypes
  23. // We don't want to export our data types to the llc layer.
  24. // MIPS compiler doesn't accept hiding of the internal data
  25. // structures by a PVOID in the function prototype.
  26. // i386 will check the type defines
  27. //
  28. #ifndef i386
  29. #define DLC_PRIVATE_PROTOTYPES
  30. #endif
  31. #include <dlc.h>
  32. #include <smbgtpt.h>
  33. #if 0
  34. //
  35. // if DLC and LLC share the same driver then we can use macros to access fields
  36. // in the BINDING_CONTEXT and ADAPTER_CONTEXT structures
  37. //
  38. #if DLC_AND_LLC
  39. #ifndef i386
  40. #define LLC_PRIVATE_PROTOTYPES
  41. #endif
  42. #include "llcdef.h"
  43. #include "llctyp.h"
  44. #include "llcapi.h"
  45. #endif
  46. #endif
  47. //
  48. // Table includes all llc header length of different frame types
  49. //
  50. static UCHAR aDlcHeaderLengths[LLC_LAST_FRAME_TYPE / 2] = {
  51. 0, // DLC_UNDEFINED_FRAME_TYPE = 0,
  52. 0, // DLC_MAC_FRAME = 0x02,
  53. 4, // DLC_I_FRAME = 0x04,
  54. 3, // DLC_UI_FRAME = 0x06,
  55. 3, // DLC_XID_COMMAND_POLL = 0x08,
  56. 3, // DLC_XID_COMMAND_NOT_POLL = 0x0a,
  57. 3, // DLC_XID_RESPONSE_FINAL = 0x0c,
  58. 3, // DLC_XID_RESPONSE_NOT_FINAL = 0x0e,
  59. 3, // DLC_TEST_RESPONSE_FINAL = 0x10,
  60. 3, // DLC_TEST_RESPONSE_NOT_FINAL = 0x12,
  61. 0, // DLC_DIRECT_8022 = 0x14,
  62. 3, // DLC_TEST_COMMAND = 0x16,
  63. 0 // DLC_DIRECT_ETHERNET_TYPE = 0x18
  64. };
  65. DLC_STATUS
  66. LlcReceiveIndication(
  67. IN PDLC_FILE_CONTEXT pFileContext,
  68. IN PDLC_OBJECT pDlcObject,
  69. IN NDIS_HANDLE MacReceiveContext,
  70. IN USHORT FrameType,
  71. IN PUCHAR pLookBuf,
  72. IN UINT cbPacketSize
  73. )
  74. /*++
  75. Routine Description:
  76. The primitive handles the receive data indication from
  77. the lower level
  78. the returned parameter block of the read command.
  79. IBM has successfully made the receive extremly complicated.
  80. We can distinguish at least four different ways to gather the
  81. receive information to the frame header, when we have received
  82. an I- frame for a link station:
  83. 1. Rcv command for link station, frames linked in link basis
  84. - user length and read options from link object
  85. - receive buffer base in link object
  86. - station information from link object
  87. 2. Rcv command for link station, frames linked in sap bases
  88. - user length and read options from link object
  89. - receive buffer base in sap object
  90. - station information from link object
  91. 3. Rcv command only for sap station, frames linked in link basis
  92. - user length and read options from sap object
  93. - receive buffer base in link object
  94. - station information from link object
  95. 4. Rcv command only for sap station, frames linked in sap basis
  96. - user length and read options from sap object
  97. - receive buffer base in sap object
  98. - station information from link object
  99. => We have three different DLC objects in receive:
  100. 1. The orginal destination of the frame, we will read station id
  101. from that object.
  102. 2. The owner of the receive, the read command must match to the
  103. station id of the events owner. The owner also chains the
  104. the received data in its frame list.
  105. 3. Receive object: the receive object defines the recieve options
  106. saved to the frame header and the read flag saved to the read
  107. parameters.
  108. At least two objects are same (the different ones in different cases),
  109. and in most cases all objects are the same dlc object.
  110. We will need to save these in rcv event:
  111. - The owner dlc object
  112. - Pointer to linked frame header list or to a single frame
  113. (defined by the receive read option in the next object).
  114. We can directly use the owner object, because the frames
  115. need to be chained. In that case we must save directly the
  116. reference of the buffer header.
  117. - The receive object, the dlc object having a pending receive,
  118. that was used to received this event.
  119. Arguments:
  120. pFileContext - the device context of this DLC client
  121. pDlcObject - the DLC client, that received the event.
  122. FrameType - current frame type
  123. pLookBuf - points to the data from the LLC header (ie. excludes the
  124. LAN header). MAY NOT CONTAIN ALL DATA
  125. cbPacketSize - amount of data to copy, including DLC header, but not
  126. including LLC header
  127. Return Value:
  128. DLC_STATUS:
  129. --*/
  130. {
  131. PDLC_OBJECT pRcvObject = pDlcObject;
  132. PDLC_OBJECT pOwnerObject;
  133. PDLC_BUFFER_HEADER pBufferHeader;
  134. DLC_STATUS Status = STATUS_SUCCESS;
  135. NTSTATUS NtStatus;
  136. UINT uiLlcOffset;
  137. UINT FrameHeaderSize;
  138. UINT LlcLength;
  139. PDLC_EVENT pRcvEvent;
  140. UINT DataSize;
  141. PFIRST_DLC_SEGMENT pFirstBuffer;
  142. PDLC_COMMAND pDlcCommand;
  143. UINT BufferSizeLeft;
  144. //
  145. // this function is called in the context of a DPC: it is the receive data
  146. // indication from NDIS
  147. //
  148. ASSUME_IRQL(DISPATCH_LEVEL);
  149. DLC_TRACE('D');
  150. if (pFileContext->State != DLC_FILE_CONTEXT_OPEN) {
  151. return DLC_STATUS_ADAPTER_CLOSED;
  152. }
  153. ENTER_DLC(pFileContext);
  154. #if LLC_DBG
  155. if (pDlcObject->State > DLC_OBJECT_CLOSED) {
  156. DbgPrint("Invalid object type!");
  157. DbgBreakPoint();
  158. }
  159. #endif
  160. //
  161. // Search the first object having a pending receive, loop
  162. // the link, the sap and the direct station until we find one.
  163. //
  164. while (pRcvObject != NULL && pRcvObject->pRcvParms == NULL) {
  165. if (pRcvObject->Type == DLC_LINK_OBJECT) {
  166. pRcvObject = pRcvObject->u.Link.pSap;
  167. } else if (pRcvObject->Type == DLC_SAP_OBJECT) {
  168. pRcvObject = pFileContext->SapStationTable[0];
  169. } else if (pRcvObject->Type == DLC_DIRECT_OBJECT) {
  170. pRcvObject = NULL;
  171. }
  172. }
  173. //
  174. // return error status if we cannot find any receive command.
  175. //
  176. if (pRcvObject == NULL) {
  177. Status = DLC_STATUS_NO_RECEIVE_COMMAND;
  178. //#if DBG
  179. // DbgPrint("DLC.LlcReceiveIndication.%d: Error: No receive command\n", __LINE__);
  180. //#endif
  181. goto ErrorExit;
  182. }
  183. //
  184. // Now we must figure out the actual owner of the received frame.
  185. // There are actually only two special cases:
  186. //
  187. if (pRcvObject->pRcvParms->Async.Parms.Receive.uchRcvReadOption == LLC_RCV_CHAIN_FRAMES_ON_LINK
  188. && pRcvObject->Type == DLC_SAP_OBJECT) {
  189. pOwnerObject = pDlcObject;
  190. } else if (pRcvObject->pRcvParms->Async.Parms.Receive.uchRcvReadOption == LLC_RCV_CHAIN_FRAMES_ON_SAP
  191. && pRcvObject->Type == DLC_LINK_OBJECT) {
  192. pOwnerObject = pRcvObject->u.Link.pSap;
  193. } else {
  194. //
  195. // In all other cases we chain the frames to the receive object
  196. // (actually IBM has not defined the case), the frames are
  197. // chained for direct if the rcv read option is set chaining for
  198. // sap or link station
  199. //
  200. pOwnerObject = pRcvObject;
  201. //
  202. // direct station can recieve only the frame
  203. // types defined by station id of the receive command
  204. // There are three types, we need to check the one, that does not work:
  205. //
  206. // DLC_DIRECT_ALL_FRAMES 0
  207. // DLC_DIRECT_MAC_FRAMES 1
  208. // DLC_DIRECT_NON_MAC_FRAMES 2
  209. //
  210. if (pRcvObject->Type == DLC_DIRECT_OBJECT) {
  211. if (FrameType == LLC_DIRECT_MAC) {
  212. if (pRcvObject->pRcvParms->Async.Parms.Receive.usStationId == LLC_DIRECT_8022) {
  213. Status = DLC_STATUS_NO_RECEIVE_COMMAND;
  214. goto ErrorExit;
  215. }
  216. } else {
  217. //
  218. // It must be a non-MAC frame
  219. //
  220. if (pRcvObject->pRcvParms->Async.Parms.Receive.usStationId == LLC_DIRECT_MAC) {
  221. Status = DLC_STATUS_NO_RECEIVE_COMMAND;
  222. goto ErrorExit;
  223. }
  224. }
  225. }
  226. }
  227. //
  228. // The frame length must be known when the buffers are allocated,
  229. // This may not be the same as the actual length of the received
  230. // LAN header (if we received a DIX frame)
  231. //
  232. uiLlcOffset = LlcGetReceivedLanHeaderLength(pFileContext->pBindingContext);
  233. //
  234. // Check first the buffer type (contiguous or non contiguous),
  235. // and then allocate it.
  236. // Note: WE DO NOT SUPPORT THE BREAK OPTION (because it would make
  237. // the current buffer management even more complicated)
  238. //
  239. LlcLength = aDlcHeaderLengths[FrameType / 2];
  240. //
  241. // DIX frames are a special case: they must be filtered
  242. // (DIX Llc header == ethernet type word is always 2 bytes,
  243. // nobody else use this llc type size).
  244. // A DIX application may define an offset, mask and match to
  245. // filter only those frames it is really needing.
  246. // This method works very well with XNS and TCP socket types
  247. //
  248. if ( LlcLength > cbPacketSize ) {
  249. Status = DLC_STATUS_INVALID_FRAME_LENGTH;
  250. goto ErrorExit;
  251. }
  252. if ((FrameType == LLC_DIRECT_ETHERNET_TYPE)
  253. && (pDlcObject->u.Direct.ProtocolTypeMask != 0)) {
  254. ULONG ProtocolType;
  255. //
  256. // there's a real good possibility here that if the app supplies a very
  257. // large value for the protocol offset, we will blow up - there's no
  258. // range checking performed!
  259. //
  260. ASSERT(pDlcObject->u.Direct.ProtocolTypeOffset >= 14);
  261. //
  262. // let's add that range check: if the protocol offset is before the
  263. // data part of the frame or past the end of this particular frame
  264. // then we say there's no receive defined for this frame
  265. //
  266. if ((pDlcObject->u.Direct.ProtocolTypeOffset < 14)
  267. || (pDlcObject->u.Direct.ProtocolTypeOffset > cbPacketSize + 10)) {
  268. return DLC_STATUS_NO_RECEIVE_COMMAND;
  269. }
  270. //
  271. // the offset to the protocol type field is given as offset from the
  272. // start of the frame: we only get to look in the lookahead buffer,
  273. // but we know that since this is an ethernet frame, the lookahead
  274. // buffer starts 14 bytes into the frame, so remove this length from
  275. // the protocol offset
  276. //
  277. ProtocolType = SmbGetUlong(&pLookBuf[pDlcObject->u.Direct.ProtocolTypeOffset - 14]);
  278. if ((ProtocolType & pDlcObject->u.Direct.ProtocolTypeMask) != pDlcObject->u.Direct.ProtocolTypeMatch) {
  279. return DLC_STATUS_NO_RECEIVE_COMMAND;
  280. }
  281. }
  282. //
  283. // The created MDL must not include the LAN header because it is not copied
  284. // by LlcTransferData. We use a temporary frame header size to allocate space
  285. // for the LAN header. The LLC header will be copied just as any other data
  286. //
  287. if (FrameType == LLC_DIRECT_MAC) {
  288. if (pRcvObject->pRcvParms->Async.Parms.Receive.uchOptions & DLC_CONTIGUOUS_MAC) {
  289. FrameHeaderSize = sizeof(DLC_CONTIGUOUS_RECEIVE) + uiLlcOffset;
  290. DataSize = cbPacketSize;
  291. } else {
  292. FrameHeaderSize = sizeof(DLC_NOT_CONTIGUOUS_RECEIVE);
  293. DataSize = cbPacketSize - LlcLength;
  294. }
  295. } else {
  296. if (pRcvObject->pRcvParms->Async.Parms.Receive.uchOptions & DLC_CONTIGUOUS_DATA) {
  297. FrameHeaderSize = sizeof(DLC_CONTIGUOUS_RECEIVE) + uiLlcOffset;
  298. DataSize = cbPacketSize;
  299. } else {
  300. FrameHeaderSize = sizeof(DLC_NOT_CONTIGUOUS_RECEIVE);
  301. DataSize = cbPacketSize - LlcLength;
  302. }
  303. }
  304. pBufferHeader = NULL;
  305. NtStatus = BufferPoolAllocate(
  306. #if DBG
  307. pFileContext,
  308. #endif
  309. pFileContext->hBufferPool,
  310. DataSize, // size of actual MDL buffers
  311. FrameHeaderSize, // frame hdr (and possibly lan hdr)
  312. pRcvObject->pRcvParms->Async.Parms.Receive.usUserLength,
  313. cbPacketSize + uiLlcOffset, // size of the packet
  314. (UINT)(-1), // any size is OK.
  315. &pBufferHeader, // returned buffer pointer
  316. &BufferSizeLeft
  317. );
  318. if (NtStatus != STATUS_SUCCESS) {
  319. if (FrameType != LLC_I_FRAME) {
  320. //
  321. // We must complete the receive with the given error status,
  322. // if this frame is not a I- frame. (I-frames can be dropped
  323. // to the floor, the other frames completes the receive with
  324. // an error status)
  325. // -----------------------------------------------
  326. // We should not complete commands in receive lookahead.
  327. // The correct way could be to queue this somehow in
  328. // data link and process this, when the command is completed
  329. // in the command completion indication.
  330. // On the other hand, NBF DOES THIS FOR EVERY IRP!
  331. //
  332. pDlcCommand = SearchAndRemoveCommandByHandle(
  333. &pFileContext->ReceiveQueue,
  334. (ULONG)-1,
  335. (USHORT)DLC_IGNORE_STATION_ID,
  336. (USHORT)DLC_STATION_MASK_SPECIFIC,
  337. pRcvObject->pRcvParms->Async.Ccb.pCcbAddress
  338. );
  339. //
  340. // RLF 11/24/92
  341. //
  342. // if pDlcCommand is NULL then check the command queue - this may
  343. // be a receive without a RECEIVE_FLAG parameter
  344. //
  345. if (!pDlcCommand) {
  346. pDlcCommand = SearchAndRemoveCommandByHandle(
  347. &pFileContext->CommandQueue,
  348. (ULONG)-1,
  349. (USHORT)DLC_IGNORE_STATION_ID,
  350. (USHORT)DLC_STATION_MASK_SPECIFIC,
  351. pRcvObject->pRcvParms->Async.Ccb.pCcbAddress
  352. );
  353. ASSERT(pDlcCommand);
  354. }
  355. pRcvObject->pRcvParms = NULL;
  356. #if LLC_DBG
  357. DbgPrint("cFramesReceived: %x\n", cFramesReceived);
  358. DbgPrint("cFramesIndicated: %x\n", cFramesIndicated);
  359. DbgPrint("cFramesReleased: %x\n", cFramesReleased);
  360. if (pDlcCommand == NULL) {
  361. DbgPrint("Lost receive command???");
  362. } else
  363. #endif
  364. CompleteDlcCommand(pFileContext,
  365. pRcvObject->StationId,
  366. pDlcCommand,
  367. DLC_STATUS_LOST_DATA_NO_BUFFERS
  368. );
  369. }
  370. //
  371. // Free the partial buffer
  372. //
  373. BufferPoolDeallocateList(pFileContext->hBufferPool, pBufferHeader);
  374. //#if DBG
  375. // DbgPrint("DLC.LlcReceiveIndication.%d: Error: Out of receive buffers\n", __LINE__);
  376. //#endif
  377. Status = DLC_STATUS_OUT_OF_RCV_BUFFERS;
  378. goto ErrorExit;
  379. }
  380. //
  381. // A link station may have committed memory from the buffer pool
  382. // when it local busy state was enabled after a local busy state
  383. // because of 'out of receive buffers'. We must uncommit all
  384. // packets received by that link station until the size of
  385. // the commited buffer space is zero
  386. //
  387. if (pDlcObject->CommittedBufferSpace != 0) {
  388. ULONG UncommittedBufferSpace;
  389. //
  390. // get the smaller
  391. //
  392. UncommittedBufferSpace = (pDlcObject->CommittedBufferSpace < BufGetPacketSize(cbPacketSize)
  393. ? pDlcObject->CommittedBufferSpace
  394. : BufGetPacketSize(cbPacketSize));
  395. pDlcObject->CommittedBufferSpace -= UncommittedBufferSpace;
  396. BufUncommitBuffers(pFileContext->hBufferPool, UncommittedBufferSpace);
  397. }
  398. //
  399. // By default this is linked only to itself.
  400. // We must create a event information every time,
  401. // because app might read the old chained frames
  402. // just between TransferData and its confirmation.
  403. // => we cannot chain frames before TransmitData is confirmed.
  404. // We should not either save any pointers to other objects,
  405. // because they might disappear before the confirm
  406. // (we use the pending transmit count to prevent OwnerObject
  407. // to disappear before the confirm)
  408. //
  409. pBufferHeader->FrameBuffer.pNextFrame = pBufferHeader;
  410. pRcvEvent = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
  411. if (pRcvEvent == NULL) {
  412. Status = DLC_STATUS_NO_MEMORY;
  413. BufferPoolDeallocateList(pFileContext->hBufferPool, pBufferHeader);
  414. #if DBG
  415. DbgPrint("DLC.LlcReceiveIndication.%d: Error: Out of memory\n", __LINE__);
  416. #endif
  417. goto ErrorExit;
  418. }
  419. pRcvEvent->Event = LLC_RECEIVE_DATA;
  420. pRcvEvent->StationId = pOwnerObject->StationId;
  421. pRcvEvent->pOwnerObject = pOwnerObject;
  422. pRcvEvent->Overlay.RcvReadOption = pRcvObject->pRcvParms->Async.Parms.Receive.uchRcvReadOption;
  423. pRcvEvent->SecondaryInfo = pRcvObject->pRcvParms->Async.Parms.Receive.ulReceiveFlag;
  424. pRcvEvent->pEventInformation = pBufferHeader;
  425. pOwnerObject->PendingLlcRequests++;
  426. pFirstBuffer = (PFIRST_DLC_SEGMENT)
  427. ((PUCHAR)pBufferHeader->FrameBuffer.pParent->Header.pGlobalVa
  428. + MIN_DLC_BUFFER_SEGMENT * pBufferHeader->FrameBuffer.Index);
  429. pFirstBuffer->Cont.Options = pRcvObject->pRcvParms->Async.Parms.Receive.uchOptions;
  430. pFirstBuffer->Cont.MessageType = (UCHAR)FrameType;
  431. pFirstBuffer->Cont.BuffersLeft = (USHORT)(BufferPoolCount(pFileContext->hBufferPool));
  432. pFirstBuffer->Cont.RcvFs = 0xCC;
  433. pFirstBuffer->Cont.AdapterNumber = pFileContext->AdapterNumber;
  434. pFirstBuffer->Cont.pNextFrame = NULL;
  435. pFirstBuffer->Cont.StationId = pDlcObject->StationId;
  436. //
  437. // A receive command without read flag is used only once.
  438. // The receive completion will complete also the receive command
  439. //
  440. if (pRcvObject->pRcvParms->Async.Parms.Receive.ulReceiveFlag == 0) {
  441. pRcvObject->pRcvParms = NULL;
  442. }
  443. //
  444. // copy NOT_CONTIGUOUS or CONTIGUOUS frame header to beginning of buffer
  445. //
  446. if (FrameHeaderSize == sizeof(DLC_NOT_CONTIGUOUS_RECEIVE)) {
  447. pFirstBuffer->Cont.UserOffset = sizeof(DLC_NOT_CONTIGUOUS_RECEIVE);
  448. LlcCopyReceivedLanHeader(pFileContext->pBindingContext,
  449. pFirstBuffer->NotCont.LanHeader,
  450. NULL
  451. );
  452. pFirstBuffer->NotCont.LanHeaderLength = (UCHAR)uiLlcOffset;
  453. if (FrameType != LLC_DIRECT_ETHERNET_TYPE) {
  454. pFirstBuffer->NotCont.DlcHeaderLength = (UCHAR)LlcLength;
  455. LlcMemCpy((PCHAR)pFirstBuffer->NotCont.DlcHeader,
  456. (PCHAR)pLookBuf,
  457. LlcLength
  458. );
  459. } else {
  460. USHORT ethernetType = LlcGetEthernetType(pFileContext->pBindingContext);
  461. UCHAR byte = ethernetType & 0xff;
  462. pFirstBuffer->NotCont.DlcHeaderLength = 2;
  463. ethernetType >>= 8;
  464. ethernetType |= ((USHORT)byte) << 8;
  465. *(PUSHORT)&pFirstBuffer->NotCont.DlcHeader = ethernetType;
  466. LlcLength = 0;
  467. }
  468. } else {
  469. //
  470. // We have included the LAN header size in the frame header size to
  471. // make room for this copy, but now we fix the UserOffset and everything
  472. // should be OK
  473. //
  474. LlcLength = 0;
  475. pFirstBuffer->Cont.UserOffset = sizeof(DLC_CONTIGUOUS_RECEIVE);
  476. LlcCopyReceivedLanHeader(pFileContext->pBindingContext,
  477. (PCHAR)pFirstBuffer
  478. + sizeof(DLC_CONTIGUOUS_RECEIVE)
  479. + pFirstBuffer->Cont.UserLength,
  480. NULL
  481. );
  482. }
  483. #if LLC_DBG
  484. cFramesReceived++;
  485. #endif
  486. //
  487. // Save the event only if this is the first chained frame.
  488. // The sequential received frames will be queued behind it.
  489. //
  490. LEAVE_DLC(pFileContext);
  491. RELEASE_DRIVER_LOCK();
  492. LlcTransferData(
  493. pFileContext->pBindingContext, // data link adapter context
  494. MacReceiveContext,
  495. &(pRcvEvent->LlcPacket), // receive packet
  496. pBufferHeader->FrameBuffer.pMdl, // destination mdl
  497. LlcLength, // offset in LookBuf to copy from
  498. cbPacketSize - LlcLength // length of copied data
  499. );
  500. ACQUIRE_DRIVER_LOCK();
  501. //
  502. // Transfer data returns always a pending status,
  503. // the success/error status is returned asynchronously
  504. // in the the receive indication completion (really?)
  505. // We should copy the whole frame here, if is visiable
  506. // in the receive lookahead buffer.
  507. //
  508. return STATUS_SUCCESS;
  509. ErrorExit:
  510. LEAVE_DLC(pFileContext);
  511. //
  512. // The receive status is very important for I- frames,
  513. // because the llc driver set the link busy when we return
  514. // DLC_STATUS_NO_RECEIVE_COMMAND or DLC_STATUS_OUT_OF_RCV_BUFFERS.
  515. //
  516. if (Status == DLC_STATUS_NO_MEMORY) {
  517. Status = DLC_STATUS_OUT_OF_RCV_BUFFERS;
  518. }
  519. return Status;
  520. }
  521. VOID
  522. LlcEventIndication(
  523. IN PDLC_FILE_CONTEXT pFileContext,
  524. IN PVOID hEventObject,
  525. IN UINT Event,
  526. IN PVOID pEventInformation,
  527. IN ULONG SecondaryInfo
  528. )
  529. /*++
  530. Routine Description:
  531. The primitive handles all LLC and NDIS events
  532. and translates them to DLC events, that are either immediately
  533. executed by a pending (and matching) read command or
  534. they are queued to the event queue.
  535. LLC cannot provide any packet with these events, beacuse they
  536. were not initiated by the protocol, but they just happened
  537. asynchronously in the data link driver.
  538. Special:
  539. This routine must not call back the data link driver, if has
  540. gon any other DLC status indication except INDICATE_CONNECT_REQUEST
  541. (that may be closed by DLC, if there are no available station ids
  542. on the sap).
  543. Arguments:
  544. pFileContext - DLC object handle or a file context of the event
  545. hEventObject - DLC object handle or a file context of the event
  546. Event - LLC event code. Usually it can be used directly as
  547. a DLC event code
  548. pEventInformation - information to DLC status change block
  549. (or another pointer to some misc information)
  550. SecondaryInformation - dword information used by some NDIS errors
  551. Return Value:
  552. None.
  553. --*/
  554. {
  555. PDLC_OBJECT pDlcObject;
  556. ASSUME_IRQL(DISPATCH_LEVEL);
  557. DLC_TRACE('E');
  558. if (pFileContext->State != DLC_FILE_CONTEXT_OPEN) {
  559. return;
  560. }
  561. ENTER_DLC(pFileContext);
  562. //
  563. // DLC status and NDIS adapter status events have different parameters,
  564. // => we cannot do any common preprocessing for them.
  565. //
  566. switch (Event) {
  567. case LLC_STATUS_CHANGE_ON_SAP:
  568. Event = LLC_STATUS_CHANGE;
  569. case LLC_STATUS_CHANGE:
  570. pDlcObject = (PDLC_OBJECT)hEventObject;
  571. #if LLC_DBG
  572. if (pDlcObject != NULL && pDlcObject->State > DLC_OBJECT_CLOSED) {
  573. DbgPrint("Invalid object type!");
  574. DbgBreakPoint();
  575. }
  576. #endif
  577. //
  578. // We must create a DLC driver object, if a
  579. // connect request has created a new link station
  580. // in the data link driver.
  581. //
  582. if (SecondaryInfo & INDICATE_CONNECT_REQUEST) {
  583. //
  584. // Create the DLC driver object, if remote connection
  585. // request created a new link station on LLC.
  586. // The connect request may be done as well for
  587. // a disconnected station.
  588. //
  589. if (pDlcObject->Type == DLC_SAP_OBJECT) {
  590. NTSTATUS Status;
  591. Status = InitializeLinkStation(
  592. pFileContext,
  593. pDlcObject, // Sap station id
  594. NULL,
  595. ((PDLC_STATUS_TABLE)pEventInformation)->hLlcLinkStation,
  596. &pDlcObject // NEW Link station id
  597. );
  598. if (Status != STATUS_SUCCESS) {
  599. //
  600. // This client has all its available link stations
  601. // reserved or we are simply run out of memory.
  602. // Several LLC clients may share the same SAP.
  603. // All remote connections are handled by the
  604. // first client registered on the sap
  605. // until it runs out of available link stations.
  606. // LlcCloseStation for a link indicating connect request
  607. // will redirect the connection request to the next
  608. // possible LLC client having opened the same sap or
  609. // deletes the link station, if there are no clients left
  610. //
  611. LEAVE_DLC(pFileContext);
  612. LlcCloseStation(
  613. ((PDLC_STATUS_TABLE)pEventInformation)->hLlcLinkStation,
  614. NULL
  615. );
  616. ENTER_DLC(pFileContext);
  617. break; // We have done it
  618. }
  619. }
  620. }
  621. //
  622. // The remotely created link station may send also other indications
  623. // than Connect, even if there is not yet a link station object
  624. // created in DLC driver. We must skip all those events.
  625. //
  626. if (pDlcObject->Type == DLC_LINK_OBJECT) {
  627. PDLC_EVENT pDlcEvent = pDlcObject->u.Link.pStatusEvent;
  628. pDlcEvent->Event = Event;
  629. pDlcEvent->StationId = pDlcObject->StationId;
  630. pDlcEvent->pOwnerObject = pDlcObject;
  631. pDlcEvent->pEventInformation = pEventInformation;
  632. pDlcEvent->SecondaryInfo |= SecondaryInfo;
  633. //
  634. // The next pointer is reset whenever the status event
  635. // packet is read and disconnected from the event queue.
  636. //
  637. if (pDlcEvent->LlcPacket.pNext == NULL) {
  638. QueueDlcEvent(pFileContext, (PDLC_PACKET)pDlcEvent);
  639. }
  640. }
  641. break;
  642. case NDIS_STATUS_RING_STATUS:
  643. ASSERT ( IS_NDIS_RING_STATUS(SecondaryInfo) );
  644. //
  645. // The secondary information is directly the
  646. // the network statys code as defined for
  647. // ibm token-ring and dlc api!
  648. //
  649. Event = LLC_NETWORK_STATUS;
  650. //
  651. // This event should go to all READ having defined the
  652. // the network status flag!
  653. //
  654. MakeDlcEvent(pFileContext,
  655. Event,
  656. (USHORT)(-1),
  657. NULL,
  658. pEventInformation,
  659. NDIS_RING_STATUS_TO_DLC_RING_STATUS(SecondaryInfo),
  660. FALSE
  661. );
  662. break;
  663. case NDIS_STATUS_CLOSED:
  664. //
  665. // NDIS status closed is given only when the network
  666. // administrator is for some reason unloading NDIS.
  667. // Thus we must always return the 'System Action' error
  668. // code ('04') with LLC_CRITICAL_ERROR, but
  669. // we will add it later when all stations has been closed.
  670. //
  671. if (pFileContext->State != DLC_FILE_CONTEXT_CLOSED) {
  672. pFileContext->State = DLC_FILE_CONTEXT_CLOSED;
  673. CloseAllStations(
  674. pFileContext,
  675. NULL, // we don't have any command to complete
  676. LLC_CRITICAL_EXCEPTION,
  677. NULL,
  678. NULL,
  679. &pFileContext->ClosingPacket
  680. );
  681. }
  682. break;
  683. case LLC_TIMER_TICK_EVENT:
  684. //
  685. // This flag is used to limit the number of the failing expand
  686. // operations for the buffer pool. We don't try to do it again
  687. // for a while, if we cannot lock memory.
  688. //
  689. MemoryLockFailed = FALSE;
  690. //
  691. // We free the extra locked pages in the buffer pool once
  692. // in five seconds. The unlocking takes some time, and we
  693. // don't want to do it whenever a read command is executed
  694. // (as we do with the expanding)
  695. //
  696. pFileContext->TimerTickCounter++;
  697. if ((pFileContext->TimerTickCounter % 10) == 0 && pFileContext->hBufferPool != NULL) {
  698. BufferPoolFreeExtraPages(
  699. #if DBG
  700. pFileContext,
  701. #endif
  702. (PDLC_BUFFER_POOL)pFileContext->hBufferPool
  703. );
  704. }
  705. //
  706. // Decrement the tick count of the first object in the timer queue
  707. // (if there is any) and complete its all sequential commands
  708. // having zero tickout.
  709. //
  710. if (pFileContext->pTimerQueue != NULL) {
  711. pFileContext->pTimerQueue->Overlay.TimerTicks--;
  712. while (pFileContext->pTimerQueue != NULL
  713. && pFileContext->pTimerQueue->Overlay.TimerTicks == 0) {
  714. PDLC_COMMAND pCommand;
  715. pCommand = pFileContext->pTimerQueue;
  716. pFileContext->pTimerQueue = (PDLC_COMMAND)pCommand->LlcPacket.pNext;
  717. #if LLC_DBG
  718. pCommand->LlcPacket.pNext = NULL;
  719. #endif
  720. CompleteDlcCommand(pFileContext, 0, pCommand, STATUS_SUCCESS);
  721. }
  722. }
  723. break;
  724. #if LLC_DBG
  725. default:
  726. LlcInvalidObjectType();
  727. break;
  728. #endif
  729. }
  730. LEAVE_DLC(pFileContext);
  731. }
  732. VOID
  733. LlcCommandCompletion(
  734. IN PDLC_FILE_CONTEXT pFileContext,
  735. IN PDLC_OBJECT pDlcObject,
  736. IN PDLC_PACKET pPacket
  737. )
  738. /*++
  739. Routine Description:
  740. The routine completes the asynchronous DLC operations: Transmit,
  741. TransferData (for receive), LlcConnect and LlcDisconnect.
  742. Arguments:
  743. pFileContext - DLC process and adapter specific file context
  744. pDlcObject - the object, that was assosiated with the command
  745. pPacket - packet assosiated with the command
  746. Return Value:
  747. None
  748. --*/
  749. {
  750. PDLC_PACKET pRootNode;
  751. UINT Status;
  752. ASSUME_IRQL(DISPATCH_LEVEL);
  753. DLC_TRACE('B');
  754. Status = (UINT)pPacket->LlcPacket.Data.Completion.Status;
  755. ENTER_DLC(pFileContext);
  756. #if LLC_DBG
  757. if (pDlcObject != NULL && pDlcObject->State > DLC_OBJECT_CLOSED) {
  758. DbgPrint("Invalid object type!");
  759. DbgBreakPoint();
  760. }
  761. #endif
  762. switch (pPacket->LlcPacket.Data.Completion.CompletedCommand) {
  763. case LLC_RECEIVE_COMPLETION:
  764. //
  765. // The receiving object may be different from the
  766. // actual object given by data link.
  767. // (this case should be moved to a subprocedure, that would
  768. // be called directly from the receive data handler, if
  769. // TransferData is executed synchronously (it always does it).
  770. // That would save at least 100 instructions.)
  771. //
  772. DLC_TRACE('h');
  773. pDlcObject = pPacket->Event.pOwnerObject;
  774. pDlcObject->PendingLlcRequests--;
  775. if (Status != STATUS_SUCCESS || pDlcObject->State != DLC_OBJECT_OPEN) {
  776. //
  777. // We must free the receive buffers, the packet
  778. // will be deallocated in the end of this procedure.
  779. //
  780. BufferPoolDeallocateList(pFileContext->hBufferPool,
  781. pPacket->Event.pEventInformation
  782. );
  783. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pPacket);
  784. } else {
  785. if (pPacket->Event.Overlay.RcvReadOption != LLC_RCV_READ_INDIVIDUAL_FRAMES) {
  786. //
  787. // The received frames must be chained,
  788. // add the new buffer header to the old
  789. // link list if there is any, The buffers
  790. // are saved to a circular link list to make
  791. // possible to build easily the final link list in
  792. // application address space.
  793. //
  794. if (pDlcObject->pReceiveEvent != NULL) {
  795. //
  796. // new: pPacket->Event.pEventInformation
  797. // base: pDlcObject->pReceiveEvent->pEventInformation
  798. // Operations when a new element is added to base:
  799. //
  800. //
  801. // 1. new->next = base->next
  802. //
  803. ((PDLC_BUFFER_HEADER)pPacket->Event.pEventInformation)->FrameBuffer.pNextFrame
  804. = ((PDLC_BUFFER_HEADER)pDlcObject->pReceiveEvent->pEventInformation)->FrameBuffer.pNextFrame;
  805. //
  806. // 2. base->next = new
  807. //
  808. ((PDLC_BUFFER_HEADER)pDlcObject->pReceiveEvent->pEventInformation)->FrameBuffer.pNextFrame
  809. = (PDLC_BUFFER_HEADER)pPacket->Event.pEventInformation;
  810. //
  811. // 3. base = new
  812. //
  813. pDlcObject->pReceiveEvent->pEventInformation = pPacket->Event.pEventInformation;
  814. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pPacket);
  815. //
  816. // This event is already queued =>
  817. // we may leave this procedure
  818. //
  819. break; // ********** EXIT ************
  820. } else {
  821. pDlcObject->pReceiveEvent = &pPacket->Event;
  822. }
  823. }
  824. //
  825. // All receives are events. The event is handled immediately
  826. // if there is a pending command in the command queue,
  827. // otherwise the command is queued to the event queue to be
  828. // read by a command issued later.
  829. //
  830. pPacket->Event.Overlay.StationIdMask = (USHORT)(-1);
  831. QueueDlcEvent(pFileContext, pPacket);
  832. }
  833. break;
  834. case LLC_SEND_COMPLETION:
  835. //
  836. // We first free or/and unlock all buffers, that
  837. // were used in the transmit of this frame.
  838. //
  839. DLC_TRACE('i');
  840. BufferPoolFreeXmitBuffers(pFileContext->hBufferPool, pPacket);
  841. //
  842. // Reset the local busy states, if there is now enough
  843. // buffers the receive the expected stuff for a link station.
  844. //
  845. if (!IsListEmpty(&pFileContext->FlowControlQueue)
  846. && pFileContext->hBufferPool != NULL
  847. && BufGetUncommittedSpace(pFileContext->hBufferPool) >= 0) {
  848. ResetLocalBusyBufferStates(pFileContext);
  849. }
  850. //
  851. // This code completes a transmit command.
  852. // It releases all resources allocated for the transmit
  853. // and completes the command, if this was the last
  854. // transmit associated with it.
  855. // Note:
  856. // Single transmit command may consists of several frames.
  857. // We must wait until all NDIS send requests have been completed
  858. // before we can complete the command. That's why the first transmit
  859. // node is also a root node. All transmit nodes have a reference
  860. // to the root node.
  861. // (why we incrment/decrement the object reference count separately
  862. // for each frame, we could do it only once for a transmit command).
  863. //
  864. pDlcObject->PendingLlcRequests--;
  865. pRootNode = pPacket->Node.pTransmitNode;
  866. //
  867. // Don't delete root node packet, we will need it to queue the
  868. // command completion (if the command completion flag is used)
  869. //
  870. if (pPacket != pRootNode) {
  871. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pPacket);
  872. }
  873. //
  874. // We will save and keep the first asynchronous error status
  875. //
  876. if (Status != STATUS_SUCCESS && pRootNode->Node.pIrp->IoStatus.Status == STATUS_SUCCESS) {
  877. pRootNode->Node.pIrp->IoStatus.Status = Status;
  878. }
  879. pRootNode->Node.FrameCount--;
  880. if (pRootNode->Node.FrameCount == 0) {
  881. CompleteTransmitCommand(pFileContext,
  882. pRootNode->Node.pIrp,
  883. pDlcObject,
  884. pRootNode
  885. );
  886. }
  887. break;
  888. case LLC_RESET_COMPLETION:
  889. pPacket->ResetPacket.pClosingInfo->CloseCounter--;
  890. if (pPacket->ResetPacket.pClosingInfo->CloseCounter == 0) {
  891. CompleteCloseReset(pFileContext, pPacket->ResetPacket.pClosingInfo);
  892. }
  893. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pPacket);
  894. break;
  895. case LLC_CONNECT_COMPLETION:
  896. DLC_TRACE('e');
  897. CompleteDlcCommand(pFileContext,
  898. pDlcObject->StationId,
  899. &pPacket->DlcCommand,
  900. Status
  901. );
  902. pDlcObject->PendingLlcRequests--;
  903. break;
  904. case LLC_DISCONNECT_COMPLETION:
  905. //
  906. // The disconnect is in dlc driver always connected to
  907. // the closing of the link station. We just continue
  908. // the asynchronous command. Still this process (waiting
  909. // the other side to ack to disconnect packet DISC)
  910. // may be interrupted by an immediate close command
  911. // (DLC.RESET or DIR.CLOSE.ADAPTER).
  912. //
  913. DLC_TRACE('g');
  914. if (pDlcObject->LlcObjectExists == TRUE) {
  915. pDlcObject->LlcObjectExists = FALSE;
  916. LEAVE_DLC(pFileContext);
  917. LlcCloseStation(pDlcObject->hLlcObject, (PLLC_PACKET)pPacket);
  918. ENTER_DLC(pFileContext);
  919. DereferenceLlcObject(pDlcObject);
  920. //
  921. // We don't want to complete a dlc object twice.
  922. //
  923. LEAVE_DLC(pFileContext);
  924. return;
  925. }
  926. case LLC_CLOSE_COMPLETION:
  927. //
  928. // Just free the command packet and update the reference counter.
  929. // The end of this procedure takes care of the rest.
  930. //
  931. DLC_TRACE('f');
  932. pDlcObject->PendingLlcRequests--;
  933. if (&pDlcObject->ClosePacket != (PLLC_PACKET) pPacket) {
  934. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pPacket);
  935. } else {
  936. pDlcObject->ClosePacketInUse = 0;
  937. }
  938. break;
  939. #if LLC_DBG
  940. default:
  941. LlcInvalidObjectType();
  942. break;
  943. #endif
  944. };
  945. #if LLC_DBG
  946. if (pDlcObject != NULL && pDlcObject->PendingLlcRequests < 0) {
  947. DbgPrint("Error: PendingLlcRequests < 0!!!\n");
  948. DbgBreakPoint();
  949. }
  950. #endif
  951. //
  952. // we can try to complete the close/reset only when there are no
  953. // pending commands issued to LLC (and NDIS).
  954. // The procedure will check, if there is still pending commands.
  955. //
  956. if (pDlcObject != NULL && pDlcObject->State != DLC_OBJECT_OPEN) {
  957. CompleteCloseStation(pFileContext, pDlcObject);
  958. }
  959. LEAVE_DLC(pFileContext);
  960. }
  961. VOID
  962. CompleteTransmitCommand(
  963. IN PDLC_FILE_CONTEXT pFileContext,
  964. IN PIRP pIrp,
  965. IN PDLC_OBJECT pChainObject,
  966. IN PDLC_PACKET pPacket
  967. )
  968. /*++
  969. Routine Description:
  970. The routine completes the DLC transmit command and optionally
  971. chains its CCB(s) to the completion list.
  972. The transmit read option defines, if the transmit commands
  973. are chained or if each command is completed with a separate
  974. READ- command.
  975. Arguments:
  976. pFileContext - DLC process and adapter specific file context
  977. pIrp - Io- request packet of the completed command
  978. pChainObject - the DLC object the packet(s) was transmitted from
  979. pPacket - the orginal packet of the transmit command
  980. Return Value:
  981. None
  982. --*/
  983. {
  984. PVOID pUserCcbPointer = NULL;
  985. PNT_DLC_PARMS pDlcParms = (PNT_DLC_PARMS)pIrp->AssociatedIrp.SystemBuffer;
  986. //
  987. // MODMOD RLF 01/19/93
  988. //
  989. BOOLEAN queuePacket = FALSE;
  990. PVOID pCcb;
  991. ULONG eventFlags;
  992. ASSUME_IRQL(DISPATCH_LEVEL);
  993. //
  994. // MODMOD ends
  995. //
  996. pDlcParms->Async.Parms.Transmit.FrameStatus = 0xCC;
  997. //
  998. // Check if the transmit commands should be linked to the completion list
  999. //
  1000. if (pDlcParms->Async.Ccb.CommandCompletionFlag != 0) {
  1001. //
  1002. // Are they linked together in the same completion event?
  1003. //
  1004. if (pDlcParms->Async.Parms.Transmit.XmitReadOption != LLC_COMPLETE_SINGLE_XMIT_FRAME) {
  1005. if (pDlcParms->Async.Parms.Transmit.XmitReadOption == LLC_CHAIN_XMIT_COMMANDS_ON_SAP
  1006. && pChainObject->Type == DLC_LINK_OBJECT) {
  1007. pChainObject = pChainObject->u.Link.pSap;
  1008. }
  1009. pChainObject->ChainedTransmitCount++;
  1010. pUserCcbPointer = pChainObject->pPrevXmitCcbAddress;
  1011. pChainObject->pPrevXmitCcbAddress = pDlcParms->Async.Ccb.pCcbAddress;
  1012. //
  1013. // Make new event only for the first transmit completion
  1014. //
  1015. if (pChainObject->ChainedTransmitCount == 1) {
  1016. pChainObject->pFirstChainedCcbAddress = pDlcParms->Async.Ccb.pCcbAddress;
  1017. pPacket->Event.pOwnerObject = pChainObject;
  1018. } else {
  1019. //
  1020. // There is already a pending event for the
  1021. // this transmit command, we may free this one.
  1022. // The space & speed optimal code execution requires
  1023. // a shameful jump.
  1024. //
  1025. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pPacket);
  1026. //
  1027. // MODMOD RLF 01/21/93
  1028. //
  1029. pCcb = pDlcParms->Async.Ccb.pCcbAddress;
  1030. //
  1031. // MODMOD ends
  1032. //
  1033. //
  1034. // ***** G-O-T-O ********
  1035. //
  1036. goto ThisIsA_SHAME;
  1037. }
  1038. } else {
  1039. pPacket->Event.pOwnerObject = NULL;
  1040. }
  1041. //
  1042. // MODMOD RLF 01/19/93
  1043. //
  1044. ////
  1045. //// We translate the orginal transit packet to a new event packet
  1046. ////
  1047. //
  1048. //pPacket->Event.Event = LLC_TRANSMIT_COMPLETION;
  1049. //pPacket->Event.StationId = (USHORT)pChainObject->StationId;
  1050. //pPacket->Event.pEventInformation = pDlcParms->Async.Ccb.pCcbAddress;
  1051. //pPacket->Event.SecondaryInfo = pDlcParms->Async.Ccb.CommandCompletionFlag;
  1052. //QueueDlcEvent(pFileContext, pPacket);
  1053. queuePacket = TRUE;
  1054. pCcb = pDlcParms->Async.Ccb.pCcbAddress;
  1055. eventFlags = pDlcParms->Async.Ccb.CommandCompletionFlag;
  1056. //
  1057. // MODMOD ends
  1058. //
  1059. } else {
  1060. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pPacket);
  1061. }
  1062. ThisIsA_SHAME:
  1063. //
  1064. // Set the default value to the returned frame status
  1065. //
  1066. if (pIrp->IoStatus.Status != STATUS_SUCCESS) {
  1067. //
  1068. // Set the FS (frame status) error code, NDIS has
  1069. // returned an FS-related error code.
  1070. // Note: This error status is never returned in the
  1071. // case of I- frames (or should it be?).
  1072. //
  1073. if (pIrp->IoStatus.Status == NDIS_STATUS_NOT_RECOGNIZED) {
  1074. pDlcParms->Async.Parms.Transmit.FrameStatus = 0;
  1075. pDlcParms->Async.Ccb.uchDlcStatus = LLC_STATUS_TRANSMIT_ERROR_FS;
  1076. } else if (pIrp->IoStatus.Status == NDIS_STATUS_NOT_COPIED) {
  1077. pDlcParms->Async.Parms.Transmit.FrameStatus = 0x44;
  1078. pDlcParms->Async.Ccb.uchDlcStatus = LLC_STATUS_TRANSMIT_ERROR_FS;
  1079. } else if (pIrp->IoStatus.Status == NDIS_STATUS_INVALID_PACKET) {
  1080. pDlcParms->Async.Parms.Transmit.FrameStatus = 0;
  1081. pDlcParms->Async.Ccb.uchDlcStatus = LLC_STATUS_INVALID_FRAME_LENGTH;
  1082. } else {
  1083. //
  1084. // Don't overwrite the existing DLC error codes!
  1085. //
  1086. if (pIrp->IoStatus.Status < DLC_STATUS_ERROR_BASE
  1087. || pIrp->IoStatus.Status > DLC_STATUS_MAX_ERROR) {
  1088. pDlcParms->Async.Ccb.uchDlcStatus = (UCHAR)LLC_STATUS_TRANSMIT_ERROR;
  1089. } else {
  1090. pDlcParms->Async.Ccb.uchDlcStatus = (UCHAR)(pIrp->IoStatus.Status - DLC_STATUS_ERROR_BASE);
  1091. }
  1092. }
  1093. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1094. } else {
  1095. pDlcParms->Async.Ccb.uchDlcStatus = (UCHAR)STATUS_SUCCESS;
  1096. }
  1097. pDlcParms->Async.Ccb.pCcbAddress = pUserCcbPointer;
  1098. //
  1099. // Copy the optional second output buffer to user memory.
  1100. //
  1101. if (IoGetCurrentIrpStackLocation(pIrp)->Parameters.DeviceIoControl.IoControlCode == IOCTL_DLC_TRANSMIT) {
  1102. //
  1103. // MODMOD RLF 01/21/93
  1104. //
  1105. // Transmit now uses METHOD_OUT_DIRECT which means we update the CCB
  1106. // with the pNext and uchDlcStatus fields
  1107. //
  1108. PLLC_CCB pInputCcb;
  1109. PUCHAR pFrameStatus;
  1110. pInputCcb = (PLLC_CCB)MmGetSystemAddressForMdl(pIrp->MdlAddress);
  1111. //
  1112. // the pointer may be an unaligned VDM pointer!
  1113. //
  1114. RtlStoreUlongPtr((PULONG_PTR)(&pInputCcb->pNext),
  1115. (ULONG_PTR)pUserCcbPointer);
  1116. pInputCcb->uchDlcStatus = pDlcParms->Async.Ccb.uchDlcStatus;
  1117. //
  1118. // MODMOD ends
  1119. //
  1120. //
  1121. // performance (slight) improvement. The following copies A SINGLE BYTE
  1122. // (the frame status field). Replace call to copy routine with single
  1123. // byte move
  1124. //
  1125. //LlcMemCpy(MmGetSystemAddressForMdl((PMDL)pDlcParms->Async.Ccb.u.pMdl),
  1126. // &pDlcParms->Async.Parms.Transmit.FrameStatus,
  1127. // aSpecialOutputBuffers[IOCTL_DLC_TRANSMIT_INDEX]
  1128. // );
  1129. pFrameStatus = (PUCHAR)MmGetSystemAddressForMdl((PMDL)pDlcParms->Async.Ccb.u.pMdl);
  1130. *pFrameStatus = pDlcParms->Async.Parms.Transmit.FrameStatus;
  1131. UnlockAndFreeMdl(pDlcParms->Async.Ccb.u.pMdl);
  1132. }
  1133. //
  1134. // we are about to complete this IRP - remove the cancel routine
  1135. //
  1136. // RELEASE_DRIVER_LOCK();
  1137. SetIrpCancelRoutine(pIrp, FALSE);
  1138. IoCompleteRequest(pIrp, (CCHAR)IO_NETWORK_INCREMENT);
  1139. // ACQUIRE_DRIVER_LOCK();
  1140. //
  1141. // MODMOD RLF 01/19/93
  1142. //
  1143. // Moved queueing of the event until after the IoCompleteRequest because it
  1144. // was possible for the following to occur:
  1145. //
  1146. // Thread A:
  1147. //
  1148. // 1. app allocates transmit CCB & submits it. Transmit completion is to
  1149. // be picked up on a READ CCB
  1150. // 2. transmit completes
  1151. // 3. DLC queues event for transmit completion
  1152. //
  1153. // Thread B:
  1154. //
  1155. // 4. app submits READ CCB
  1156. // 5. READ finds completed transmit event on DLC event queue & removes it
  1157. // 6. READ IRP is completed (IoCompleteRequest)
  1158. // 7. app checks READ CCB and deallocates transmit CCB
  1159. // 8. app reallocates memory previously used for transmit CCB
  1160. //
  1161. // Thread A:
  1162. //
  1163. // 9. transmit IRP is completed (IoCompleteRequest)
  1164. //
  1165. // At this point, the IoCompleteRequest for the transmit copies some
  1166. // completion info over the area which used to be the original transmit CCB
  1167. // but has since been reallocated, causing lachrymae maximus
  1168. //
  1169. // This is safe because in this case we know we have a transmit which is
  1170. // destined to be picked up by a READ (its ulCompletionFlag parameter is
  1171. // non-zero), so it doesn't do any harm if we complete the IRP before
  1172. // queueing the event for a READ
  1173. //
  1174. if (queuePacket) {
  1175. pPacket->Event.Event = LLC_TRANSMIT_COMPLETION;
  1176. pPacket->Event.StationId = (USHORT)pChainObject->StationId;
  1177. pPacket->Event.pEventInformation = pCcb;
  1178. pPacket->Event.SecondaryInfo = eventFlags;
  1179. QueueDlcEvent(pFileContext, pPacket);
  1180. }
  1181. //
  1182. // MODMOD ends
  1183. //
  1184. DereferenceFileContext(pFileContext);
  1185. }
  1186. VOID
  1187. CompleteDlcCommand(
  1188. IN PDLC_FILE_CONTEXT pFileContext,
  1189. IN USHORT StationId,
  1190. IN PDLC_COMMAND pDlcCommand,
  1191. IN UINT Status
  1192. )
  1193. /*++
  1194. Routine Description:
  1195. The routine completes the DLC command and optionally
  1196. saves its CCB(s) to the completion list, if the command
  1197. has a command completion flag.
  1198. Arguments:
  1199. pFileContext - DLC process and adapter specific file context
  1200. StationId - the station id of the completed command (0 for non station
  1201. based commands)
  1202. pDlcCommand - the caller must provide either command completion packet
  1203. or IRP
  1204. Status - command completion status
  1205. Return Value:
  1206. None
  1207. --*/
  1208. {
  1209. PVOID pCcbAddress;
  1210. ULONG CommandCompletionFlag;
  1211. PIRP pIrp;
  1212. pIrp = pDlcCommand->pIrp;
  1213. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pDlcCommand);
  1214. pCcbAddress = ((PNT_DLC_PARMS)pIrp->AssociatedIrp.SystemBuffer)->Async.Ccb.pCcbAddress;
  1215. CommandCompletionFlag = ((PNT_DLC_PARMS)pIrp->AssociatedIrp.SystemBuffer)->Async.Ccb.CommandCompletionFlag;
  1216. CompleteAsyncCommand(pFileContext, Status, pIrp, NULL, FALSE);
  1217. //
  1218. // Queue command completion event, if the command completion flag was set
  1219. //
  1220. if (CommandCompletionFlag != 0) {
  1221. MakeDlcEvent(pFileContext,
  1222. DLC_COMMAND_COMPLETION,
  1223. StationId,
  1224. NULL,
  1225. pCcbAddress,
  1226. CommandCompletionFlag,
  1227. FALSE
  1228. );
  1229. }
  1230. }
  1231.