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.

595 lines
21 KiB

  1. /*
  2. (C) Copyright 1998
  3. All rights reserved.
  4. Portions of this software are:
  5. (C) Copyright 1995, 1999 TriplePoint, Inc. -- http://www.TriplePoint.com
  6. License to use this software is granted under the terms outlined in
  7. the TriplePoint Software Services Agreement.
  8. (C) Copyright 1992 Microsoft Corp. -- http://www.Microsoft.com
  9. License to use this software is granted under the terms outlined in
  10. the Microsoft Windows Device Driver Development Kit.
  11. @doc INTERNAL Transmit Transmit_c
  12. @module Transmit.c |
  13. This module implements the Miniport packet Transmit routines. This module is
  14. very dependent on the hardware/firmware interface and should be looked at
  15. whenever changes to these interfaces occur.
  16. @head3 Contents |
  17. @index class,mfunc,func,msg,mdata,struct,enum | Transmit_c
  18. @end
  19. */
  20. /* @doc EXTERNAL INTERNAL
  21. @topic 3.3 Sending Packets |
  22. <f MiniportWanSend> transmits a packet through the adapter
  23. onto the network.
  24. Ownership of both the packet descriptor and the packet data
  25. is transferred to the WAN NIC driver until this request is
  26. completed, either synchronously or asynchronously. If the
  27. WAN miniport returns NDIS_STATUS_PENDING, it must later
  28. indicate completion of the request by calling NdisMWanSendComplete.
  29. If the WAN miniport returns a status other than NDIS_STATUS_PENDING,
  30. the request is considered to be complete, and ownership of the packet
  31. immediately reverts to the caller.
  32. Unlike LAN miniports, the WAN driver cannot return a status of
  33. NDIS_STATUS_RESOURCES to indicate that it does not have enough
  34. resources currently available to process the transmit. Instead,
  35. the WAN miniport should queue the send internally for a later
  36. time and perhaps lower the SendWindow value on the line by
  37. making a line-up indication. The NDISWAN driver will insure
  38. that the WAN miniport driver never has more than SendWindow
  39. packets outstanding. If a WAN miniport makes a line-up indication
  40. for a particular line, and sets the SendWindow to zero, NDISWAN
  41. reverts to using the default value of the transmit window passed
  42. as the MaxTransmit value provided to an earlier OID_WAN_GET_INFO
  43. request.
  44. It is also an error for the WAN miniport NIC driver to
  45. call NdisMSendResourcesAvailable.
  46. The packet passed to <f MiniportWanSend> will contain simple HDLC
  47. PPP framing if PPP framing is set. For SLIP or RAS framing, the
  48. packet contains only the data portion with no framing whatsoever.
  49. Simple HDLC PPP framing is discussed later in more detail.
  50. A WAN NIC driver must not attempt to provide software loopback or
  51. promiscuous mode loopback. Both of these are fully supported in
  52. the NDISWAN driver.
  53. The MacReservedx members as well as the WanPacketQueue member of
  54. the <t NDIS_WAN_PACKET> is fully available for use by the WAN miniport.
  55. The available header padding is simply CurrentBuffer-StartBuffer.
  56. The available tail padding is EndBuffer-(CurrentBuffer+CurrentLength).
  57. The header and tail padding is guaranteed to be at least the amount
  58. requested, but it can be more.
  59. See <t NDIS_WAN_PACKET> in the Network Driver Reference for details of
  60. the WAN packet descriptor structure.
  61. A WAN miniport calls NdisMWanSendComplete to indicate that it has
  62. completed a previous transmit operation for which it returned
  63. NDIS_STATUS_PENDING. This does not necessarily imply that the
  64. packet has been transmitted, although, with the exception of
  65. intelligent adapters, it generally has. It does however, mean
  66. the miniport is ready to release ownership of the packet.
  67. When a WAN miniport calls NdisMWanSendComplete, it passes back
  68. the original packet to indicate which send operation was completed.
  69. If <f MiniportWanSend> returns a status other than NDIS_STATUS_PENDING,
  70. it does not call NdisMWanSendComplete for that packet.
  71. @end
  72. */
  73. #define __FILEID__ TRANSMIT_OBJECT_TYPE
  74. // Unique file ID for error logging
  75. #include "Miniport.h" // Defines all the miniport objects
  76. #if defined(NDIS_LCODE)
  77. # pragma NDIS_LCODE // Windows 95 wants this code locked down!
  78. # pragma NDIS_LDATA
  79. #endif
  80. /* @doc INTERNAL Transmit Transmit_c TransmitAddToQueue
  81. @func
  82. <f TransmitAddToQueue> places the packet on the transmit queue. If the
  83. queue was empty to begin with, TRUE is returned so the caller can kick
  84. start the transmiter.
  85. @rdesc
  86. <f TransmitAddToQueue> returns TRUE if this is the only entry in the
  87. list, FALSE otherwise.
  88. */
  89. DBG_STATIC BOOLEAN TransmitAddToQueue(
  90. IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm
  91. // A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
  92. IN PBCHANNEL_OBJECT pBChannel, // @parm
  93. // A pointer to the <t BCHANNEL_OBJECT> returned by <f BChannelCreate>.
  94. IN PNDIS_WAN_PACKET pWanPacket // @parm
  95. // A pointer to the associated NDIS packet structure <t NDIS_WAN_PACKET>.
  96. )
  97. {
  98. DBG_FUNC("TransmitAddToQueue")
  99. /*
  100. // Note if the list is empty to begin with.
  101. */
  102. BOOLEAN ListWasEmpty;
  103. DBG_ENTER(pAdapter);
  104. /*
  105. // Place the packet on the TransmitPendingList.
  106. */
  107. NdisAcquireSpinLock(&pAdapter->TransmitLock);
  108. ListWasEmpty = IsListEmpty(&pAdapter->TransmitPendingList);
  109. InsertTailList(&pAdapter->TransmitPendingList, &pWanPacket->WanPacketQueue);
  110. NdisReleaseSpinLock(&pAdapter->TransmitLock);
  111. DBG_RETURN(pAdapter, ListWasEmpty);
  112. return (ListWasEmpty);
  113. }
  114. /* @doc INTERNAL Transmit Transmit_c TransmitPacketHandler
  115. @func
  116. <f TransmitPacketHandler> removes an entry from the TransmitPendingList
  117. and places the packet on the appropriate B-channel and starts the
  118. transmission. The packet is then placed on the <t TransmitBusyList> to
  119. await a transmit complete event processed by <f TransmitCompleteHandler>.
  120. @comm
  121. The packets go out in a FIFO order for the entire driver, independent of
  122. the channel on which it goes out. This means that a slow link, or one
  123. that is backed up can hold up all other channels. There is no good way
  124. to get around this because we must to deliver packets in the order they
  125. are given to the Miniport, regardless of the link they are on.
  126. */
  127. DBG_STATIC VOID TransmitPacketHandler(
  128. IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm
  129. // A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
  130. )
  131. {
  132. DBG_FUNC("TransmitPacketHandler")
  133. PNDIS_WAN_PACKET pWanPacket;
  134. // Holds the packet being transmitted.
  135. USHORT BytesToSend;
  136. // Tells us how many bytes are to be transmitted.
  137. PBCHANNEL_OBJECT pBChannel;
  138. // A pointer to one of our <t BCHANNEL_OBJECT>'s.
  139. DBG_ENTER(pAdapter);
  140. /*
  141. // MUTEX to protect against async EventHandler access at the same time.
  142. */
  143. NdisAcquireSpinLock(&pAdapter->TransmitLock);
  144. #if DBG
  145. { // Sanity check!
  146. PLIST_ENTRY pList = &pAdapter->TransmitPendingList;
  147. ASSERT(pList->Flink && pList->Flink->Blink == pList);
  148. ASSERT(pList->Blink && pList->Blink->Flink == pList);
  149. }
  150. #endif // DBG
  151. /*
  152. // This might be called when no packets are queued!
  153. */
  154. while (!IsListEmpty(&pAdapter->TransmitPendingList))
  155. {
  156. /*
  157. // Remove the packet from the TransmitPendingList.
  158. */
  159. pWanPacket = (PNDIS_WAN_PACKET)RemoveHeadList(&pAdapter->TransmitPendingList);
  160. /*
  161. // Release MUTEX
  162. */
  163. NdisReleaseSpinLock(&pAdapter->TransmitLock);
  164. /*
  165. // Retrieve the information we saved in the packet reserved fields.
  166. */
  167. pBChannel = (PBCHANNEL_OBJECT) pWanPacket->MacReserved1;
  168. /*
  169. // Make sure the link is still up and can accept transmits.
  170. */
  171. if (pBChannel->CallState != LINECALLSTATE_CONNECTED)
  172. {
  173. /*
  174. // Indicate send complete failure to the NDIS wrapper.
  175. */
  176. DBG_WARNING(pAdapter,("Flushing send on link#%d (Packet=0x%X)\n",
  177. pBChannel->BChannelIndex, pWanPacket));
  178. if (pBChannel->NdisLinkContext)
  179. {
  180. NdisMWanSendComplete(pAdapter->MiniportAdapterHandle,
  181. pWanPacket, NDIS_STATUS_FAILURE);
  182. }
  183. /*
  184. // Reacquire MUTEX
  185. */
  186. NdisAcquireSpinLock(&pAdapter->TransmitLock);
  187. }
  188. else
  189. {
  190. BytesToSend = (USHORT) pWanPacket->CurrentLength;
  191. pAdapter->TotalTxBytes += BytesToSend;
  192. pAdapter->TotalTxPackets++;
  193. /*
  194. // Attempt to place the packet on the NIC for transmission.
  195. */
  196. if (!CardTransmitPacket(pAdapter->pCard, pBChannel, pWanPacket))
  197. {
  198. /*
  199. // ReQueue the packet on the TransmitPendingList and leave.
  200. // Reacquire MUTEX
  201. */
  202. NdisAcquireSpinLock(&pAdapter->TransmitLock);
  203. InsertHeadList(&pAdapter->TransmitPendingList, &pWanPacket->WanPacketQueue);
  204. break;
  205. }
  206. DBG_TX(pAdapter, pBChannel->BChannelIndex,
  207. BytesToSend, pWanPacket->CurrentBuffer);
  208. /*
  209. // Reacquire MUTEX
  210. */
  211. NdisAcquireSpinLock(&pAdapter->TransmitLock);
  212. }
  213. }
  214. /*
  215. // Release MUTEX
  216. */
  217. NdisReleaseSpinLock(&pAdapter->TransmitLock);
  218. DBG_LEAVE(pAdapter);
  219. }
  220. /* @doc INTERNAL Transmit Transmit_c TransmitCompleteHandler
  221. @func
  222. <f TransmitCompleteHandler> is called by <f MiniportTimer> to handle a
  223. transmit complete event. We walk the <t TransmitCompleteList> to find
  224. all the packets that have been sent out on the wire, and then tell the
  225. protocol stack that we're done with the packet, and it can be re-used.
  226. */
  227. VOID TransmitCompleteHandler(
  228. IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm
  229. // A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
  230. )
  231. {
  232. DBG_FUNC("TransmitCompleteHandler")
  233. PNDIS_WAN_PACKET pWanPacket;
  234. // Holds the packet that's just been transmitted.
  235. PBCHANNEL_OBJECT pBChannel;
  236. // A pointer to one of our <t BCHANNEL_OBJECT>'s.
  237. DBG_ENTER(pAdapter);
  238. /*
  239. // I find it useful to do this nest check, just so I can make sure
  240. // I handle it correctly when it happens.
  241. */
  242. if (++(pAdapter->NestedDataHandler) > 1)
  243. {
  244. DBG_ERROR(pAdapter,("NestedDataHandler=%d > 1\n",
  245. pAdapter->NestedDataHandler));
  246. }
  247. /*
  248. // MUTEX to protect against async EventHandler access at the same time.
  249. */
  250. NdisDprAcquireSpinLock(&pAdapter->TransmitLock);
  251. #if DBG
  252. { // Sanity check!
  253. PLIST_ENTRY pList = &pAdapter->TransmitCompleteList;
  254. ASSERT(pList->Flink && pList->Flink->Blink == pList);
  255. ASSERT(pList->Blink && pList->Blink->Flink == pList);
  256. }
  257. #endif // DBG
  258. while (!IsListEmpty(&pAdapter->TransmitCompleteList))
  259. {
  260. /*
  261. // Remove the packet from the TransmitCompleteList.
  262. */
  263. pWanPacket = (PNDIS_WAN_PACKET)RemoveHeadList(&pAdapter->TransmitCompleteList);
  264. /*
  265. // Release MUTEX
  266. */
  267. NdisDprReleaseSpinLock(&pAdapter->TransmitLock);
  268. /*
  269. // Retrieve the information we saved in the packet reserved fields.
  270. */
  271. pBChannel = (PBCHANNEL_OBJECT) pWanPacket->MacReserved1;
  272. /*
  273. // Indicate send complete to the NDIS wrapper.
  274. */
  275. DBG_TXC(pAdapter, pBChannel->BChannelIndex);
  276. NdisMWanSendComplete(pAdapter->MiniportAdapterHandle,
  277. pWanPacket, NDIS_STATUS_SUCCESS);
  278. /*
  279. // Reacquire MUTEX
  280. */
  281. NdisDprAcquireSpinLock(&pAdapter->TransmitLock);
  282. }
  283. /*
  284. // Release MUTEX
  285. */
  286. NdisDprReleaseSpinLock(&pAdapter->TransmitLock);
  287. /*
  288. // Start any other pending transmits.
  289. */
  290. TransmitPacketHandler(pAdapter);
  291. /*
  292. // I find it useful to do this nest check, just so I can make sure
  293. // I handle it correctly when it happens.
  294. */
  295. if (--(pAdapter->NestedDataHandler) < 0)
  296. {
  297. DBG_ERROR(pAdapter,("NestedDataHandler=%d < 0\n",
  298. pAdapter->NestedDataHandler));
  299. }
  300. DBG_LEAVE(pAdapter);
  301. }
  302. /* @doc INTERNAL Transmit Transmit_c MiniportWanSend
  303. @func
  304. <f MiniportWanSend> instructs a WAN driver to transmit a packet through
  305. the adapter onto the medium.
  306. @iex
  307. typedef struct _NDIS_WAN_PACKET
  308. {
  309. LIST_ENTRY WanPacketQueue;
  310. PUCHAR CurrentBuffer;
  311. ULONG CurrentLength;
  312. PUCHAR StartBuffer;
  313. PUCHAR EndBuffer;
  314. PVOID ProtocolReserved1;
  315. PVOID ProtocolReserved2;
  316. PVOID ProtocolReserved3;
  317. PVOID ProtocolReserved4;
  318. PVOID MacReserved1; // pBChannel
  319. PVOID MacReserved2;
  320. PVOID MacReserved3;
  321. PVOID MacReserved4;
  322. } NDIS_WAN_PACKET, *PNDIS_WAN_PACKET;
  323. @comm
  324. When <f MiniportWanSend> is called, ownership of both the packet descriptor and
  325. the packet data is transferred to the driver until it completes the given
  326. packet, either synchronously or asynchronously. If <f MiniportWanSend>
  327. returns a status other than NDIS_STATUS_PENDING, the request is
  328. considered complete and ownership of the packet immediately reverts
  329. to the initiator of the send request. If MiniportWanSend returns
  330. NDIS_STATUS_PENDING, the miniport subsequently must call
  331. NdisMWanSendComplete with the packet to indicate completion
  332. of the transmit request.
  333. MiniportWanSend can use both the <t MacReservedX> and <t WanPacketQueue>
  334. areas within the <t NDIS_WAN_PACKET> structure. However, the miniport
  335. cannot access the ProtocolReservedx members.
  336. Any NDIS intermediate driver that binds itself to an underlying
  337. WAN miniport is responsible for providing a fresh <t NDIS_WAN_PACKET>
  338. structure to the underlying driver's <f MiniportWanSend> function. Before
  339. such an intermediate driver calls NdisSend, it must repackage the send
  340. packet given to its MiniportWanSend function so the underlying driver
  341. will have MacReservedx and WanPacketQueue areas of its own to use.
  342. The available header padding within a given packet can be calculated
  343. as (CurrentBuffer - StartBuffer), the available tail padding as
  344. (EndBuffer - (CurrentBuffer + CurrentLength)). The header and
  345. tail padding is guaranteed to be at least the length that the
  346. miniport requested in response to a preceding OID_WAN_GET_INFO
  347. query. The header and/or tail padding for any packet given to
  348. <f MiniportWanSend> can be more than the length that was requested.
  349. <f MiniportWanSend> can neither return NDIS_STATUS_RESOURCES for an
  350. input packet nor call NdisMSendResourcesAvailable. Instead, the
  351. miniport must queue incoming send packets internally for subsequent
  352. transmission. The miniport controls how many packets NDIS will
  353. submit to MiniportWanSend when the NIC driver sets the SendWindow
  354. value in the driver's NDIS_MAC_LINE_UP indication to establish the
  355. given link. NDISWAN uses this value as an upper bound on uncompleted
  356. sends submitted to <f MiniportWanSend>, so the miniport's internal queue
  357. cannot be overrun, and the miniport can adjust the SendWindow
  358. dynamically with subsequent line-up indications for established
  359. links. If the miniport set the SendWindow to zero when it called
  360. NdisMIndicateStatus with a particular line-up indication, NDISWAN
  361. uses the MaxTransmit value that the driver originally set in response
  362. to the OID_WAN_GET_INFO query as its limit on submitted but uncompleted
  363. send packets.
  364. Each packet passed to <f MiniportWanSend> is set up according to one of
  365. the flags that the miniport set in the FramingBits member in response
  366. to the OID_WAN_GET_INFO query. It will contain simple HDLC PPP framing
  367. if the driver claimed to support PPP. For SLIP or RAS framing, such
  368. a packet contains only the data portion with no framing whatsoever.
  369. For more information about system-defined WAN and TAPI OIDs, see Part 2.
  370. <f Note>: A WAN driver cannot manage software loopback or promiscuous mode
  371. loopback internally. NDISWAN supplies this loopback support for
  372. WAN drivers.
  373. <f Note>: <f MiniportWanSend> can be pre-empted by an interrupt.
  374. By default, <f MiniportWanSend> runs at IRQL DISPATCH_LEVEL.
  375. @rdesc
  376. <f MiniportWanSend> can return one of the following:
  377. @flag NDIS_STATUS_SUCCESS |
  378. The driver (or its NIC) has accepted the packet data for
  379. transmission, so <f MiniportWanSend> is returning the packet.<nl>
  380. <f Note>: A non-zero return value indicates one of the following
  381. error codes:
  382. @iex
  383. NDIS_STATUS_INVALID_DATA
  384. NDIS_STATUS_INVALID_LENGTH
  385. NDIS_STATUS_INVALID_OID
  386. NDIS_STATUS_NOT_ACCEPTED
  387. NDIS_STATUS_NOT_SUPPORTED
  388. NDIS_STATUS_PENDING
  389. NDIS_STATUS_FAILURE
  390. */
  391. NDIS_STATUS MiniportWanSend(
  392. IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm
  393. // A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
  394. IN PBCHANNEL_OBJECT pBChannel, // @parm
  395. // A pointer to the <t BCHANNEL_OBJECT> returned by <f BChannelCreate>.
  396. IN PNDIS_WAN_PACKET pWanPacket // @parm
  397. // A pointer to the associated NDIS packet structure <t NDIS_WAN_PACKET>.
  398. // The structure contains a pointer to a contiguous buffer with guaranteed
  399. // padding at the beginning and end. The driver may manipulate the buffer
  400. // in any way.
  401. )
  402. {
  403. DBG_FUNC("MiniportWanSend")
  404. UINT BytesToSend;
  405. // Tells us how many bytes are to be transmitted.
  406. NDIS_STATUS Result;
  407. // Holds the result code returned by this function.
  408. ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE);
  409. ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE);
  410. ASSERT(pAdapter == pBChannel->pAdapter);
  411. DBG_ENTER(pAdapter);
  412. /*
  413. // Make sure the packet size is something we can deal with.
  414. */
  415. BytesToSend = pWanPacket->CurrentLength;
  416. if ((BytesToSend == 0) || (BytesToSend > pAdapter->pCard->BufferSize))
  417. {
  418. DBG_ERROR(pAdapter,("Bad packet size = %d\n",BytesToSend));
  419. Result = NDIS_STATUS_FAILURE;
  420. }
  421. /*
  422. // Return if line has been closed.
  423. */
  424. else if (pBChannel->CallClosing)
  425. {
  426. DBG_ERROR(pAdapter,("BChannel Closed\n"));
  427. Result = NDIS_STATUS_FAILURE;
  428. }
  429. else
  430. {
  431. /*
  432. // We have to accept the frame if possible, I just want to know
  433. // if somebody has lied to us...
  434. */
  435. if (BytesToSend > pBChannel->WanLinkInfo.MaxSendFrameSize)
  436. {
  437. DBG_NOTICE(pAdapter,("Line=%d Packet size=%d > %d\n",
  438. pBChannel->BChannelIndex, BytesToSend,
  439. pBChannel->WanLinkInfo.MaxSendFrameSize));
  440. }
  441. /*
  442. // We'll need to use these when the transmit completes.
  443. */
  444. pWanPacket->MacReserved1 = (PVOID) pBChannel;
  445. /*
  446. // Place the packet in the transmit list.
  447. */
  448. if (TransmitAddToQueue(pAdapter, pBChannel, pWanPacket) &&
  449. pAdapter->NestedDataHandler < 1)
  450. {
  451. /*
  452. // The queue was empty so we've gotta kick start it.
  453. // Once it's going, it runs off the DPC.
  454. //
  455. // No kick start is necessary if we're already running the the
  456. // TransmitCompleteHandler -- In fact, it will screw things up if
  457. // we call TransmitPacketHandler while TransmitCompleteHandler is
  458. // running.
  459. */
  460. TransmitPacketHandler(pAdapter);
  461. }
  462. Result = NDIS_STATUS_PENDING;
  463. }
  464. DBG_RETURN(pAdapter, Result);
  465. return (Result);
  466. }