Source code of Windows XP (NT5)
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.

562 lines
18 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1991 Nokia Data Systems AB
  4. Module Name:
  5. dlcxmit.c
  6. Abstract:
  7. This module implements all transmit commands of Windows/Nt DLC API
  8. Contents:
  9. DlcTransmit
  10. Author:
  11. Antti Saarenheimo 01-Aug-1991
  12. Environment:
  13. Kernel mode
  14. Revision History:
  15. --*/
  16. #include <dlc.h>
  17. NTSTATUS
  18. DlcTransmit(
  19. IN PIRP pIrp,
  20. IN PDLC_FILE_CONTEXT pFileContext,
  21. IN PNT_DLC_PARMS pDlcParms,
  22. IN ULONG ParameterLength,
  23. IN ULONG OutputBufferLength
  24. )
  25. /*++
  26. Routine Description:
  27. The procedure implements the gather send of one or more frames.
  28. DLC API DLL translates all transmit commands to the single command,
  29. that is implemented by this driver. All frames must have the same type.
  30. The general pseudo code for procedure:
  31. Check input parameters
  32. for all frames until error
  33. {
  34. lock xmit buffers (buffer in buffer pool are already locked)
  35. if UI, TEST or XID command
  36. build DLC frame, set the sources address
  37. send frame
  38. if command status not pending
  39. call asynchronous completion routine
  40. }
  41. Arguments:
  42. pIrp - current io request packet
  43. pFileContext - DLC process specific adapter context
  44. pParameters - the current parameter block
  45. ParameterLength - the length of input parameters
  46. Return Value:
  47. NTSTATUS
  48. STATUS_PENDING
  49. DLC_STATUS_TRANSMIT_ERROR
  50. DLC_STATUS_NO_MEMORY
  51. DLC_STATUS_INVALID_OPTION
  52. DLC_STATUS_INVALID_STATION_ID;
  53. --*/
  54. {
  55. PDLC_OBJECT pTransmitObject;
  56. UINT i;
  57. PDLC_PACKET pXmitNode, pRootXmitNode;
  58. UINT FirstSegment;
  59. NTSTATUS Status;
  60. UINT DescriptorCount;
  61. USHORT FrameType;
  62. USHORT RemoteSap;
  63. static LARGE_INTEGER UnlockTimeout = { (ULONG) -TRANSMIT_RETRY_WAIT, -1 };
  64. BOOLEAN mapFrameType = FALSE;
  65. UNREFERENCED_PARAMETER(OutputBufferLength);
  66. ASSUME_IRQL(DISPATCH_LEVEL);
  67. DLC_TRACE('T');
  68. //
  69. // first, get and check the DLC station (Direct, SAP or Link)
  70. //
  71. Status = GetStation(pFileContext,
  72. pDlcParms->Async.Parms.Transmit.StationId,
  73. &pTransmitObject
  74. );
  75. if (Status != STATUS_SUCCESS) {
  76. return Status;
  77. }
  78. RemoteSap = (USHORT)pDlcParms->Async.Parms.Transmit.RemoteSap;
  79. FrameType = pDlcParms->Async.Parms.Transmit.FrameType;
  80. //
  81. // The object type and the transmitted frame types must be compatible!
  82. //
  83. if (FrameType == LLC_I_FRAME) {
  84. if (pTransmitObject->Type != DLC_LINK_OBJECT) {
  85. return DLC_STATUS_INVALID_STATION_ID;
  86. }
  87. } else if (FrameType == LLC_DIRECT_TRANSMIT
  88. || FrameType == LLC_DIRECT_MAC
  89. || FrameType == LLC_DIRECT_8022
  90. || FrameType >= LLC_FIRST_ETHERNET_TYPE) {
  91. if (pTransmitObject->Type != DLC_DIRECT_OBJECT) {
  92. return DLC_STATUS_INVALID_STATION_ID;
  93. }
  94. //
  95. // RLF 3/4/94
  96. //
  97. // This is somewhat bogus: it was originally intended that AcsLan would
  98. // pass in a meaningful FrameType value for TRANSMIT.DIR.FRAME.
  99. // However, it always passes through LLC_TRANSMIT_DIRECT. It is obvious
  100. // that for DIX frames, FrameType should contain the DIX type field. For
  101. // example, the RIPL server talks using DIX frame type 0x0600. Therefore,
  102. // the FrameType *should* be 0x0600 if comments and some of the code in
  103. // this driver is to be believed (not entirely a good idea). However,
  104. // AcsLan is missing an important piece of information: it doesn't know
  105. // if the direct station was opened to transmit DIX frames on ethernet,
  106. // or if its the originally intended direct station used to send and
  107. // receive MAC frames on Token Ring (although it wouldn't be too difficult
  108. // to make a good guess at this). So AcsLan just punts and hands
  109. // responsibility to this routine which then abnegates that responsibility.
  110. // So this following if (...) is always going to branch to the next block
  111. // if we were entered as a consequence of AcsLan (virtual 100% probability).
  112. // We'll leave it here just in case somebody has forsaken AcsLan and used
  113. // their own call into the driver (but lets face it, DIX frames will never
  114. // work without this fix, so its moot).
  115. // We instead set mapFrameType = TRUE if FrameType was LLC_DIRECT_TRANSMIT
  116. // on entry AND the protocol offset in the DIX station object is not zero.
  117. // Just before we submit the frame to LlcSendU we will convert the FrameType
  118. // and RemoteSap parameters - at that point we have all the information and
  119. // we know exactly where the DIX type field is kept
  120. //
  121. if (FrameType >= LLC_FIRST_ETHERNET_TYPE) {
  122. //
  123. // LlcSendU requires the ethernet type in RemoteSap
  124. //
  125. RemoteSap = FrameType;
  126. FrameType = 0;
  127. } else if (FrameType == LLC_DIRECT_TRANSMIT) {
  128. if (pTransmitObject->u.Direct.ProtocolTypeOffset) {
  129. mapFrameType = TRUE;
  130. }
  131. }
  132. } else if (FrameType > LLC_TEST_COMMAND_POLL || FrameType & 1) {
  133. return DLC_STATUS_INVALID_OPTION;
  134. } else {
  135. if (pTransmitObject->Type != DLC_SAP_OBJECT) {
  136. return DLC_STATUS_INVALID_STATION_ID;
  137. }
  138. }
  139. if (pDlcParms->Async.Parms.Transmit.XmitReadOption > DLC_CHAIN_XMIT_IN_SAP) {
  140. return DLC_STATUS_INVALID_OPTION;
  141. }
  142. //
  143. // check the input buffer size and that it is consistent
  144. // with the descriptor count
  145. //
  146. DescriptorCount = (UINT)pDlcParms->Async.Parms.Transmit.XmitBufferCount;
  147. if (sizeof(LLC_TRANSMIT_DESCRIPTOR) * (DescriptorCount - 1)
  148. + sizeof(NT_DLC_TRANSMIT_PARMS)
  149. + sizeof(NT_DLC_CCB) != (UINT)ParameterLength) {
  150. return DLC_STATUS_TRANSMIT_ERROR;
  151. }
  152. //
  153. // The transmit node (or packet) of the frame is also the root node of all
  154. // frames in this command. The transmit command is completed when all its
  155. // frames have been sent or acknowledged (if we are sending I-frames)
  156. //
  157. pXmitNode = pRootXmitNode = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
  158. if (pRootXmitNode == NULL) {
  159. return DLC_STATUS_NO_MEMORY;
  160. }
  161. //
  162. // This counter keeps this object alive, when the transmit command is being
  163. // processed (actually it doesn't help when the adapter is closed or a DLC
  164. // SAP is reset)
  165. //
  166. pTransmitObject->PendingLlcRequests++;
  167. pRootXmitNode->Node.FrameCount = 1;
  168. pRootXmitNode->Node.pIrp = pIrp;
  169. FirstSegment = 0;
  170. for (i = 1; ; i++) {
  171. if (i == DescriptorCount
  172. || pDlcParms->Async.Parms.Transmit.XmitBuffer[i].eSegmentType == LLC_FIRST_DATA_SEGMENT) {
  173. //
  174. // The send completion routine will complete the whole IRP,
  175. // when the frame count hits zero => we must have one
  176. // extra frame all the time to prevent the command
  177. // to complete when we are still sending it in LLC.
  178. //
  179. pRootXmitNode->Node.FrameCount++;
  180. pTransmitObject->PendingLlcRequests++;
  181. //
  182. // We must reference the LLC object to keep it alive,
  183. // when the transmit command is queued on LLC.
  184. // For example, Control-C could kill the llc object and
  185. // reset its pointer while we are calling the llc object
  186. // (that really happened!)
  187. //
  188. ReferenceLlcObject(pTransmitObject);
  189. //
  190. // The xmit buffer building may cause a page fault =>
  191. // we must lower the IRQ level and release the spin locks.
  192. //
  193. LEAVE_DLC(pFileContext);
  194. RELEASE_DRIVER_LOCK();
  195. //
  196. // We don't need to reference the buffer pool, that may
  197. // exist, because the llc object reference counter
  198. // protects also the buffer pool. The buffer pool
  199. // is not deleted before all llc objects have been deleted!
  200. //
  201. //
  202. // Operating system allows each process lock physical memory
  203. // only a limited amount. The whole system may also be out
  204. // of the available physical memory (and it's a very typical
  205. // situation in Windows/Nt)
  206. //
  207. Status = BufferPoolBuildXmitBuffers(
  208. pFileContext->hBufferPool,
  209. i - FirstSegment,
  210. &pDlcParms->Async.Parms.Transmit.XmitBuffer[FirstSegment],
  211. pXmitNode
  212. );
  213. ACQUIRE_DRIVER_LOCK();
  214. if (Status != STATUS_SUCCESS) {
  215. //
  216. // The muliple packet sends are very difficult to recover.
  217. // The caller cannot really know which frames were sent
  218. // and which ones were lost. Thus we just spend 1 second
  219. // sleeping and retrying to send the data. Note: this
  220. // time is aways from from any abortive closing, thus
  221. // this cannot be any longer wait. Keep this stuff is also
  222. // outside of the main transmit code path.
  223. //
  224. if (i < DescriptorCount) {
  225. UINT RetryCount;
  226. for (RetryCount = 0;
  227. (RetryCount < 10) && (Status != STATUS_SUCCESS);
  228. RetryCount++) {
  229. RELEASE_DRIVER_LOCK();
  230. //
  231. // Sleep 100 ms and try again.
  232. //
  233. LlcSleep(100000L); // this is microseconds!
  234. Status = BufferPoolBuildXmitBuffers(
  235. pFileContext->hBufferPool,
  236. i - FirstSegment,
  237. &pDlcParms->Async.Parms.Transmit.XmitBuffer[FirstSegment],
  238. pXmitNode
  239. );
  240. ACQUIRE_DRIVER_LOCK();
  241. //#if DBG
  242. // if (Status != STATUS_SUCCESS) {
  243. // DbgPrint("DLC.DlcTransmit: Error: Can't build transmit buffer, retrying. Status=%x\n",
  244. // Status
  245. // );
  246. // }
  247. //#endif
  248. }
  249. }
  250. if (Status != STATUS_SUCCESS) {
  251. ENTER_DLC(pFileContext);
  252. //
  253. // We failed, cancel the transmit command
  254. //
  255. DereferenceLlcObject(pTransmitObject);
  256. //
  257. // The first error cancels the whole transmit command.
  258. // Usually there is no sense to send more frames when
  259. // the send of a frame has been failed.
  260. //
  261. pTransmitObject->PendingLlcRequests--;
  262. pRootXmitNode->Node.FrameCount--;
  263. if (pXmitNode != pRootXmitNode) {
  264. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pXmitNode);
  265. pXmitNode = NULL;
  266. }
  267. pIrp->IoStatus.Status = Status;
  268. //#if DBG
  269. // DbgPrint("DLC.DlcTransmit: Error: Can't build transmit buffer. Status=%x\n",
  270. // Status
  271. // );
  272. //#endif
  273. goto DlcTransmit_ErrorExit;
  274. }
  275. }
  276. //
  277. // Chain the returned buffers to the root xmit node
  278. // of this transmit command
  279. //
  280. pXmitNode->Node.pTransmitNode = pRootXmitNode;
  281. FirstSegment = i;
  282. if (FrameType == LLC_I_FRAME) {
  283. pXmitNode->LlcPacket.Data.Xmit.pMdl = pXmitNode->Node.pMdl;
  284. LlcSendI(pTransmitObject->hLlcObject,
  285. &(pXmitNode->LlcPacket)
  286. );
  287. } else {
  288. //
  289. // For non-I frames the LAN header and its actual information
  290. // buffers are in diffenret MDLs. The first MDL includes the
  291. // LAN header. The LAN header length must be excluded from the
  292. // length of the information field ?
  293. // We don't need to know the LAN header length, because figured
  294. // out by the data link layer (actually we could not know it
  295. // here, the real packet length depends on the LAN header type
  296. // we are really using).
  297. //
  298. pXmitNode->LlcPacket.Data.Xmit.pLanHeader = MmGetSystemAddressForMdl(pXmitNode->Node.pMdl);
  299. pXmitNode->LlcPacket.Data.Xmit.pMdl = pXmitNode->Node.pMdl->Next;
  300. pXmitNode->LlcPacket.InformationLength -= (USHORT)MmGetMdlByteCount(pXmitNode->Node.pMdl);
  301. //
  302. // RLF 3/4/94
  303. //
  304. // if the frame is being sent on the direct station, but we are
  305. // on ethernet and actually have the direct station open in DIX
  306. // mode, then we need to convert the FrameType and RemoteSap to
  307. // be 0 and the DIX identifier, respectively
  308. //
  309. if (mapFrameType) {
  310. PUCHAR lanHeader = pXmitNode->LlcPacket.Data.Xmit.pLanHeader;
  311. //
  312. // the DIX format is fixed, and unlike the rest of DLC,
  313. // expects ethernet format addresses, with no AC or FC
  314. // bytes
  315. //
  316. RemoteSap = ((USHORT)lanHeader[12]) << 8 | lanHeader[13];
  317. FrameType = 0;
  318. }
  319. LlcSendU(pTransmitObject->hLlcObject,
  320. &(pXmitNode->LlcPacket),
  321. FrameType,
  322. RemoteSap
  323. );
  324. }
  325. ENTER_DLC(pFileContext);
  326. //
  327. // Note: Llc object may be deleted during this dereference,
  328. // but is does not delete the DLC object.
  329. // We will return with an error, if there are more frames
  330. // to be sent and the dlc object is not any more open
  331. // (but not yet deleted).
  332. //
  333. DereferenceLlcObject(pTransmitObject);
  334. //
  335. // Allocate a new packet, if we are sending multiple packets,
  336. // We must also check, that the current object is still
  337. // alive and that we can send the packets
  338. //
  339. if (i < DescriptorCount) {
  340. if (pTransmitObject->State != DLC_OBJECT_OPEN) {
  341. pIrp->IoStatus.Status = DLC_STATUS_CANCELLED_BY_SYSTEM_ACTION;
  342. break;
  343. }
  344. pXmitNode = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
  345. if (pXmitNode == NULL) {
  346. pIrp->IoStatus.Status = DLC_STATUS_NO_MEMORY;
  347. break;
  348. }
  349. } else {
  350. break;
  351. }
  352. }
  353. }
  354. //
  355. // fall through here on normal exit
  356. //
  357. DlcTransmit_Exit:
  358. //
  359. // Decrement the frame counter to the correct value to make
  360. // the IRP command completion possible.
  361. //
  362. //
  363. // If we determine that we couldn't give the frame to LLC then we will
  364. // complete the transmit request with an immediate status IF there was
  365. // only 1 frame submitted. If the request was TRANSMIT.FRAMES then we
  366. // may have already submitted several frames which may have been completed
  367. // asynchronously
  368. //
  369. // If we are completed the request synchronously make sure that we have
  370. // gotten rid of any resources we allocated
  371. //
  372. ASSUME_IRQL(DISPATCH_LEVEL);
  373. pRootXmitNode->Node.FrameCount--;
  374. if (pRootXmitNode->Node.FrameCount == 0) {
  375. CompleteTransmitCommand(pFileContext, pIrp, pTransmitObject, pRootXmitNode);
  376. }
  377. #if DBG
  378. else
  379. {
  380. //
  381. // this IRP is cancellable
  382. //
  383. SetIrpCancelRoutine(pIrp, TRUE);
  384. }
  385. #endif // DBG
  386. Status = STATUS_PENDING;
  387. //
  388. // Now this transmit operation is complete,
  389. // We must decrement the reference counter and
  390. // check, if we should call the close completion routine.
  391. //
  392. DlcTransmit_CheckClose:
  393. pTransmitObject->PendingLlcRequests--;
  394. if (pTransmitObject->State != DLC_OBJECT_OPEN) {
  395. CompleteCloseStation(pFileContext, pTransmitObject);
  396. }
  397. //
  398. // The DLC completion routine will always complete the transmit
  399. // commands. Usually the command is already completed here in
  400. // the case of connectionless frames.
  401. //
  402. return Status;
  403. DlcTransmit_ErrorExit:
  404. //
  405. // come here if we determine that we couldn't give a frame to LLC. This may
  406. // be a single frame transmit, or multiple (TRANSMIT.FRAMES). If multiple
  407. // then we have to take the asynchronous way out if frames have already been
  408. // submitted. If a single frame then we can complete the IRP synchronously
  409. // and return an immediate error status
  410. //
  411. if (pRootXmitNode->Node.FrameCount > 1) {
  412. //
  413. // multiple frames!
  414. //
  415. //#if DBG
  416. // DbgPrint("DLC.DlcTransmit: Multiple frame error exit! (%d). Status = %x\n",
  417. // pRootXmitNode->Node.FrameCount,
  418. // Status
  419. // );
  420. //#endif
  421. goto DlcTransmit_Exit;
  422. }
  423. pRootXmitNode->Node.FrameCount--;
  424. ASSERT(pRootXmitNode->Node.FrameCount == 0);
  425. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pRootXmitNode);
  426. pIrp->IoStatus.Status = STATUS_SUCCESS;
  427. if (Status >= DLC_STATUS_ERROR_BASE && Status <= DLC_STATUS_MAX_ERROR) {
  428. Status -= DLC_STATUS_ERROR_BASE;
  429. }
  430. ASSERT(Status <= LLC_STATUS_MAX_ERROR);
  431. pDlcParms->Async.Ccb.uchDlcStatus = (LLC_STATUS)Status;
  432. //#if DBG
  433. // DbgPrint("DLC.DlcTransmit: Returning Immediate Status %x\n", Status);
  434. //#endif
  435. goto DlcTransmit_CheckClose;
  436. }