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.

352 lines
14 KiB

  1. /*
  2. (C) Copyright 1999
  3. All rights reserved.
  4. Portions of this software are:
  5. (C) Copyright 1995 TriplePoint, Inc. -- http://www.TriplePoint.com
  6. License to use this software is granted under the same terms
  7. outlined in the Microsoft Windows Device Driver Development Kit.
  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 Receive Receive_c
  12. @module Receive.c |
  13. This module implements the Miniport packet receive routines. Basically,
  14. the asynchronous receive processing routine. This module is very
  15. dependent on the hardware/firmware interface and should be looked at
  16. whenever changes to these interfaces occur.
  17. @head3 Contents |
  18. @index class,mfunc,func,msg,mdata,struct,enum | Receive_c
  19. @end
  20. */
  21. /* @doc EXTERNAL INTERNAL
  22. @topic 3.4 Receiving Packets |
  23. A connection-oriented miniport or MCM calls NdisMCoIndicateReceivePacket to
  24. indicate one or more received packets up to a connection-oriented client or
  25. call manager. If the miniport or MCM handles interrupts, it calls
  26. NdisMCoIndicateReceivePacket from its MiniportHandleInterrupt function.
  27. @ex Receiving packets through an MCM |
  28. Miniport NDIS NdisWan
  29. |----------------------------------|----------------------------------|
  30. | NdisMCoIndicateReceivePacket | |
  31. |---------------------------------| |
  32. | | ProtocolCoReceivePacket |
  33. | |---------------------------------|
  34. | NdisMCoIndicateReceivePacket | |
  35. |---------------------------------| |
  36. | . | ProtocolCoReceivePacket |
  37. | . |---------------------------------|
  38. | . | . |
  39. | | . |
  40. | NdisMCoReceiveComplete | . |
  41. |---------------------------------| |
  42. | | ProtocolReceiveComplete |
  43. | |---------------------------------|
  44. | | |
  45. | | NdisReturnPackets |
  46. | |---------------------------------|
  47. | MiniportReturnPacket | . |
  48. |---------------------------------| . |
  49. | MiniportReturnPacket | . |
  50. |---------------------------------| |
  51. | . | |
  52. | . | |
  53. | . | |
  54. |----------------------------------|----------------------------------|
  55. @normal
  56. In the call to NdisMCoIndicateReceivePacket, the miniport or MCM passes a
  57. pointer to an array of packet descriptor pointers. The miniport or MCM also
  58. passes an NdisVcHandle that identifies the VC on which the packets were
  59. received. Before calling NdisMCoIndicateReceivePacket, the miniport or MCM
  60. must set up a packet array (see Part 2, Section 4.6).
  61. The call to NdisMCoIndicateReceivePacket causes NDIS to call the
  62. ProtocolCoReceivePacket function of the protocol driver (connection-oriented
  63. client or call manager) that shares the indicated VC with the miniport. The
  64. ProtocolCoReceivePacket function processes the receive indication.
  65. After some miniport-determined number of calls to
  66. NdisMCoIndicateReceivePacket, the miniport must call NdisMCoReceiveComplete
  67. to indicate the completion of the previous receive indications made with one
  68. or more calls to NdisMCoIndicateReceivePacket. The call to
  69. NdisMCoReceiveComplete causes NDIS to call the ProtocolReceiveComplete
  70. function of the connection-oriented client or call manager.
  71. If a protocol does not return the miniport-allocated resources for a receive
  72. indication promptly enough, the miniport or MCM can call
  73. NdisMCoIndicateStatus with NDIS_STATUS_RESOURCES to alert the offending
  74. protocol that the miniport or MCM is running low on available packet or
  75. buffer descriptors (or even on NIC receive buffer space) for subsequent
  76. receive indications.
  77. @end
  78. */
  79. #define __FILEID__ RECEIVE_OBJECT_TYPE
  80. // Unique file ID for error logging
  81. #include "Miniport.h" // Defines all the miniport objects
  82. #if defined(NDIS_LCODE)
  83. # pragma NDIS_LCODE // Windows 9x wants this code locked down!
  84. # pragma NDIS_LDATA
  85. #endif
  86. /* @doc INTERNAL Receive Receive_c ReceivePacketHandler
  87. @func
  88. <f ReceivePacketHandler> is called from <f MiniportTimer> to handle
  89. a packet receive event. We enter here with interrupts enabled on
  90. the adapter and the processor, but the NDIS Wrapper holds a spin lock
  91. since we are executing on an NDIS timer thread.
  92. @comm
  93. We loop in here until all the available incoming packets have been passed
  94. up to the protocol stack. As we find each good packet, it is passed up
  95. to the protocol stack using <f NdisMWanIndicateReceive>. When NDIS
  96. returns control from this call, we resubmit the packet to the adapter
  97. so it can be used to receive another incoming packet. The link flag
  98. <p NeedReceiveCompleteIndication> is set TRUE if any packets are received
  99. on a particular link. This is used later, before returning from the
  100. async event handler, to notify NDIS of any ReceiveCompleteIndications.
  101. */
  102. void ReceivePacketHandler(
  103. IN PBCHANNEL_OBJECT pBChannel, // @parm
  104. // A Pointer to one of our <t BCHANNEL_OBJECT>'s.
  105. IN PNDIS_BUFFER pNdisBuffer, // @parm
  106. // A pointer to the NDIS buffer we use to indicate the receive.
  107. IN ULONG BytesReceived // @parm
  108. // Number of bytes received.
  109. )
  110. {
  111. DBG_FUNC("ReceivePacketHandler")
  112. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  113. PUCHAR ReceiveBuffer;
  114. // Pointer to first byte received.
  115. ULONG BufferLength;
  116. // Length of first buffer.
  117. PMINIPORT_ADAPTER_OBJECT pAdapter;
  118. // A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
  119. PNDIS_PACKET pNdisPacket;
  120. // A pointer to the NDIS packet we use to indicate the receive.
  121. ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE);
  122. pAdapter = GET_ADAPTER_FROM_BCHANNEL(pBChannel);
  123. ASSERT(pNdisBuffer);
  124. DBG_ENTER(pAdapter);
  125. /*
  126. // I find it useful to do this nest check, just so I can make sure
  127. // I handle it correctly when it happens.
  128. */
  129. if (++(pAdapter->NestedDataHandler) > 1)
  130. {
  131. DBG_ERROR(pAdapter,("NestedDataHandler=%d > 1\n",
  132. pAdapter->NestedDataHandler));
  133. }
  134. NdisQueryBufferSafe(pNdisBuffer, &ReceiveBuffer, &BufferLength,
  135. NormalPagePriority);
  136. ASSERT(ReceiveBuffer && BufferLength);
  137. /*
  138. // Is there someone up there who cares?
  139. */
  140. if (pBChannel->NdisVcHandle == NULL)
  141. {
  142. DBG_WARNING(pAdapter, ("Packet recvd on disconnected channel #%d\n",pBChannel->ObjectID));
  143. FREE_MEMORY(ReceiveBuffer, BufferLength);
  144. NdisFreeBuffer(pNdisBuffer);
  145. }
  146. else
  147. {
  148. pAdapter->TotalRxBytes += BytesReceived;
  149. pAdapter->TotalRxPackets++;
  150. /*
  151. // We have to accept the frame if possible, I just want to know
  152. // if somebody has lied to us...
  153. */
  154. if (BytesReceived > pBChannel->WanLinkInfo.MaxRecvFrameSize)
  155. {
  156. DBG_NOTICE(pAdapter,("Packet size=%d > %d\n",
  157. BytesReceived, pBChannel->WanLinkInfo.MaxRecvFrameSize));
  158. }
  159. DBG_RX(pAdapter, pBChannel->ObjectID, BufferLength, ReceiveBuffer);
  160. /*
  161. // Indiciate the packet up to the protocol stack.
  162. */
  163. NdisAllocatePacket(&Status, &pNdisPacket,
  164. pAdapter->pCard->PacketPoolHandle);
  165. if (Status == NDIS_STATUS_SUCCESS)
  166. {
  167. NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
  168. NDIS_SET_PACKET_STATUS(pNdisPacket, NDIS_STATUS_SUCCESS);
  169. NDIS_SET_PACKET_HEADER_SIZE(pNdisPacket, 0);
  170. NdisMCoIndicateReceivePacket(
  171. pBChannel->NdisVcHandle,
  172. &pNdisPacket, // PacketArray
  173. 1 // NumberOfPackets
  174. );
  175. pBChannel->NeedReceiveCompleteIndication = TRUE;
  176. }
  177. else
  178. {
  179. DBG_ERROR(pAdapter,("NdisAllocatePacket Error=0x%X\n",Status));
  180. }
  181. }
  182. /*
  183. // I find it useful to do this nest check, just so I can make sure
  184. // I handle it correctly when it happens.
  185. */
  186. if (--(pAdapter->NestedDataHandler) < 0)
  187. {
  188. DBG_ERROR(pAdapter,("NestedDataHandler=%d < 0\n",
  189. pAdapter->NestedDataHandler));
  190. }
  191. DBG_LEAVE(pAdapter);
  192. }
  193. /* @doc EXTERNAL INTERNAL Receive Receive_c MiniportReturnPacket
  194. @func
  195. <f MiniportReturnPacket> is a required function in drivers that
  196. indicate receives with NdisMIndicateReceivePacket.
  197. @comm
  198. A miniport driver of a busmaster DMA NIC that supports multipacket
  199. receives and a miniport driver that supplies media-specific information,
  200. such as packet priorities, with its receive indications must have a
  201. MiniportReturnPacket function. An NDIS intermediate driver that binds
  202. itself to such a miniport driver also must have a MiniportReturnPacket
  203. function.
  204. Any packet with associated NDIS_PACKET_OOB_DATA in which the Status is set
  205. to NDIS_STATUS_PENDING on return from NdisMIndicateReceivePacket will be
  206. returned to MiniportReturnPacket. When all bound protocols have called
  207. NdisReturnPackets as many times as necessary to release their references
  208. to the originally indicated packet array, NDIS returns pended packets from
  209. the array to the MiniportReturnPacket function of the driver that
  210. originally allocated the packet array.
  211. Usually, MiniportReturnPacket prepares such a returned packet to be used
  212. in a subsequent receive indication. Although MiniportReturnPacket could
  213. return the buffer descriptors chained to the packet to buffer pool and the
  214. packet descriptor itself to packet pool, it is far more efficient to reuse
  215. returned descriptors.
  216. MiniportReturnPacket must call NdisUnchainBufferAtXxx as many times as
  217. necessary to save the pointers to all chained buffer descriptors before it
  218. calls NdisReinitializePacket. Otherwise, MiniportReturnPacket cannot
  219. recover the buffer descriptors the driver originally chained to the packet
  220. for the indication.
  221. MiniportReturnPacket also can call NdisZeroMemory with the pointer
  222. returned by NDIS_OOB_DATA_FROM_PACKET to prepare the packet's associated
  223. out-of-band block for reuse.
  224. If a particular buffer descriptor was shortened to match the size of an
  225. indicated range of data, MiniportReturnPacket should call
  226. NdisAdjustBufferLength with that buffer descriptor to restore its mapping
  227. of the NIC's receive buffer range.
  228. By default, MiniportReturnPacket runs at IRQL DISPATCH_LEVEL.
  229. @rdesc
  230. <f MiniportReturnPacket> returns zero if it is successful.<nl>
  231. Otherwise, a non-zero return value indicates an error condition.
  232. @xref
  233. <f NdisAdjustBufferLength>, <f NdisAllocateBuffer>, <f NdisAllocatePacket>,
  234. <f NdisMIndicateReceivePacket>, <t NDIS_OOB_DATA_FROM_PACKET>,
  235. <t NDIS_PACKET>, <t NDIS_PACKET_OOB_DATA>, <f NdisReinitializePacket>,
  236. <f NdisReturnPackets>, <f NdisUnchainBufferAtBack>,
  237. <f NdisUnchainBufferAtFront>, <f NdisZeroMemory>
  238. */
  239. VOID MiniportReturnPacket(
  240. IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm
  241. // A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
  242. IN PNDIS_PACKET pNdisPacket // @parm
  243. // A pointer to a <t NDIS_PACKET> that was passed up thru the NDIS
  244. // wrapper by an earlier call to <f NdisMIndicateReceivePacket>.
  245. )
  246. {
  247. DBG_FUNC("MiniportReturnPacket")
  248. PNDIS_BUFFER pNdisBuffer;
  249. ULONG ByteCount = 0;
  250. PUCHAR pMemory = NULL;
  251. ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE);
  252. ASSERT(pNdisPacket);
  253. DBG_ENTER(pAdapter);
  254. NdisUnchainBufferAtFront(pNdisPacket, &pNdisBuffer);
  255. ASSERT(pNdisBuffer);
  256. NdisQueryBufferSafe(pNdisBuffer, &pMemory, &ByteCount, NormalPagePriority);
  257. ASSERT(pMemory && ByteCount);
  258. FREE_MEMORY(pMemory, ByteCount);
  259. NdisFreeBuffer(pNdisBuffer);
  260. NdisFreePacket(pNdisPacket);
  261. DBG_LEAVE(pAdapter);
  262. }