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.

491 lines
11 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. net\routing\ip\ipinip\rcv.c
  5. Abstract:
  6. Revision History:
  7. --*/
  8. #define __FILE_SIG__ RCV_SIG
  9. #include "inc.h"
  10. IP_STATUS
  11. IpIpRcvDatagram(
  12. IN PVOID pvIpContext,
  13. IN DWORD dwDestAddr,
  14. IN DWORD dwSrcAddr,
  15. IN DWORD dwAcceptAddr,
  16. IN DWORD dwRcvAddr,
  17. IN IPHeader UNALIGNED pHeader,
  18. IN UINT uiHdrLen,
  19. IN IPRcvBuf *pRcvBuf,
  20. IN UINT uiTotalLen,
  21. IN BOOLEAN bIsBCast,
  22. IN BYTE byProtocol,
  23. IN IPOptInfo *pOptInfo
  24. )
  25. /*++
  26. Routine Description
  27. This
  28. Locks
  29. Arguments
  30. pvIpContext IP's context for the receive indication. Currently this
  31. is a pointer to the source NTE
  32. dwDestAddr The Destination address in the header
  33. dwSrcAddr The Source Address in the header
  34. dwAcceptAddr The address of the NTE which "accepted" this packet
  35. dwRcvAddr The address of the NTE on which the packet was received
  36. pHeader Pointer to the IP Header
  37. uiHdrLen The header length
  38. pRcvBuf The COMPLETE packet in an IPRcvBuf structure
  39. uiRcvdDataLen The size of the received datagram
  40. bIsBCast Whether the packet was a link layer broadcast
  41. byProtocol The Protocol ID in the header
  42. pOptInfo Pointer to Option info
  43. Return Value
  44. IP_SUCCESS
  45. --*/
  46. {
  47. PTRANSFER_CONTEXT pXferCtxt;
  48. PNDIS_BUFFER pnbFirstBuffer;
  49. PVOID pvData;
  50. PIRP pIrp;
  51. IP_HEADER UNALIGNED *pInHeader, *pOutHeader;
  52. ULARGE_INTEGER uliTunnelId;
  53. PTUNNEL pTunnel;
  54. ULONG ulOutHdrLen, ulDataLen;
  55. BOOLEAN bNonUnicast;
  56. TraceEnter(RCV, "TdixReceiveIpIp");
  57. //
  58. // Get a pointer to the first buffer
  59. //
  60. pvData = (PVOID)(pRcvBuf->ipr_buffer);
  61. RtAssert(pvData);
  62. //
  63. // Figure out the tunnel for this receive
  64. // Since the transport indicates atleast 128 bytes, we can safely read out
  65. // the IP Header
  66. //
  67. RtAssert(uiTotalLen > sizeof(IP_HEADER));
  68. pOutHeader = pHeader;
  69. RtAssert(pOutHeader->byProtocol is PROTO_IPINIP);
  70. RtAssert(pOutHeader->byVerLen >> 4 is IP_VERSION_4);
  71. //
  72. // These defines depend upon a variable being named "uliTunnelId"
  73. //
  74. REMADDR = dwSrcAddr;
  75. LOCALADDR = dwDestAddr;
  76. //
  77. // Bunch of checks to make sure the packet and the handler
  78. // are telling us the same thing
  79. //
  80. RtAssert(pOutHeader->dwSrc is dwSrcAddr);
  81. RtAssert(pOutHeader->dwDest is dwDestAddr);
  82. //
  83. // Get a pointer to the inside header
  84. //
  85. ulOutHdrLen = LengthOfIPHeader(pOutHeader);
  86. pInHeader = (IP_HEADER UNALIGNED *)((PBYTE)pOutHeader + ulOutHdrLen);
  87. #if DBG
  88. //
  89. // The size of the inner data must be total bytes - outer header
  90. //
  91. ulDataLen = ntohs(pInHeader->wLength);
  92. RtAssert((ulDataLen + ulOutHdrLen) is uiTotalLen);
  93. //
  94. // The outer header should also give a good length
  95. //
  96. ulDataLen = ntohs(pOutHeader->wLength);
  97. //
  98. // Data length and bytes available must match
  99. //
  100. RtAssert(ulDataLen is uiTotalLen);
  101. #endif
  102. //
  103. // Find the TUNNEL. We need to acquire the tunnel list lock
  104. //
  105. EnterReaderAtDpcLevel(&g_rwlTunnelLock);
  106. pTunnel = FindTunnel(&uliTunnelId);
  107. ExitReaderFromDpcLevel(&g_rwlTunnelLock);
  108. if(pTunnel is NULL)
  109. {
  110. Trace(RCV, WARN,
  111. ("TdixReceiveIpIp: Couldnt find tunnel for %d.%d.%d.%d/%d.%d.%d.%d\n",
  112. PRINT_IPADDR(REMADDR),
  113. PRINT_IPADDR(LOCALADDR)));
  114. //
  115. // Could not find a matching tunnel
  116. //
  117. TraceLeave(RCV, "TdixReceiveIpIp");
  118. //
  119. // Return a code that will cause IP to send the right ICMP message
  120. //
  121. return IP_DEST_PROT_UNREACHABLE;;
  122. }
  123. //
  124. // Ok, so we have the tunnel and it is ref counted and locked
  125. //
  126. //
  127. // The number of octets received
  128. //
  129. pTunnel->ulInOctets += ulBytesAvailable;
  130. //
  131. // Check the actual (inside) destination
  132. //
  133. if(IsUnicastAddr(pInHeader->dwDest))
  134. {
  135. //
  136. // TODO: should we check to see that the address is not 0.0.0.0?
  137. //
  138. pTunnel->ulInUniPkts++;
  139. bNonUnicast = FALSE;
  140. }
  141. else
  142. {
  143. pTunnel->ulInNonUniPkts++;
  144. if(IsClassEAddr(pInHeader->dwDest))
  145. {
  146. //
  147. // Bad address - throw it away
  148. //
  149. pTunnel->ulInErrors++;
  150. //
  151. // Releaselock, free buffer chain
  152. //
  153. }
  154. bNonUnicast = TRUE;
  155. }
  156. //
  157. // If the tunnel is non operational yet we are getting packets, means
  158. // it probably should be made operational
  159. //
  160. RtAssert(pTunnel->dwOperState is MIB_IF_OPER_STATUS_OPERATIONAL);
  161. if((pTunnel->dwAdminState isnot MIB_IF_ADMIN_STATUS_UP) or
  162. (pTunnel->dwOperState isnot MIB_IF_OPER_STATUS_OPERATIONAL))
  163. {
  164. Trace(RCV, WARN,
  165. ("TdixReceiveIpIp: Tunnel %x is not up\n",
  166. pTunnel));
  167. pTunnel->ulInDiscards++;
  168. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  169. DereferenceTunnel(pTunnel);
  170. TraceLeave(RCV, "TdixReceiveIpIp");
  171. return STATUS_DATA_NOT_ACCEPTED;
  172. }
  173. //
  174. // Allocate a transfer context
  175. //
  176. pXferCtxt = AllocateTransferContext();
  177. if(pXferCtxt is NULL)
  178. {
  179. Trace(RCV, ERROR,
  180. ("TdixReceiveIpIp: Couldnt allocate transfer context\n"));
  181. //
  182. // Could not allocate context, free the data, unlock and deref
  183. // the tunnel
  184. //
  185. pTunnel->ulInDiscards++;
  186. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  187. DereferenceTunnel(pTunnel);
  188. TraceLeave(RCV, "TdixReceiveIpIp");
  189. return STATUS_DATA_NOT_ACCEPTED;
  190. }
  191. //
  192. // Ok, all statistics are done.
  193. // Release the lock on the tunnel
  194. //
  195. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  196. //
  197. // Fill in the read-datagram context with the information that won't
  198. // otherwise be available in the completion routine.
  199. //
  200. pXferCtxt->pTunnel = pTunnel;
  201. pXferCtxt->pRcvBuf = pRcvBuf;
  202. pXferCtxt->uiTotalLen = uiTotalLen;
  203. pXferCtxt->ulProtoOffset = ulOutHdrLen;
  204. //
  205. // The data starts at pInHeader
  206. // We indicate the only the first buffer to IP which means
  207. // (ulFirstBufLen - outer header length) bytes
  208. // The total data is the (ulTotalLen - outer header)
  209. // We associate a TRANSFER_CONTEXT with this indication,
  210. // The Protocol Offset is just our outer header
  211. //
  212. g_pfnIPRcv(pTunnel->pvIpContext,
  213. pInHeader,
  214. ulFirstBufLen - ulOutHdrLen,
  215. ulTotalLen - ulOutHdrLen,
  216. pXferCtxt,
  217. ulOutHdrLen,
  218. bNonUnicast);
  219. //
  220. // Deref the tunnel (finally)
  221. //
  222. DereferenceTunnel(pTunnel);
  223. TraceLeave(RCV, "TdixReceiveIpIp");
  224. return STATUS_SUCCESS;
  225. }
  226. NDIS_STATUS
  227. IpIpTransferData(
  228. PVOID pvContext,
  229. NDIS_HANDLE nhMacContext,
  230. UINT uiProtoOffset,
  231. UINT uiTransferOffset,
  232. UINT uiTransferLength,
  233. PNDIS_PACKET pnpPacket,
  234. PUINT puiTransferred
  235. )
  236. /*++
  237. Routine Description
  238. Locks
  239. Arguments
  240. Return Value
  241. NO_ERROR
  242. --*/
  243. {
  244. PTRANSFER_CONTEXT pXferCtxt;
  245. TraceEnter(SEND, "IpIpTransferData");
  246. pXferCtxt = (PTRANSFER_CONTEXT)nhMacContext;
  247. RtAssert(pXferCtxt->pTunnel is pvContext);
  248. RtAssert(pXferCtxt->ulProtoOffset is uiProtoOffset);
  249. //
  250. // Should not be asking to transfer more than was indicated
  251. // Since the transfer will start at and offset of
  252. // uiProtoOffset + uiTransferOffset, the following should hold
  253. //
  254. RtAssert((pXferContext->uiTotalLen - uiProtoOffset - uiTransferOffset) >=
  255. uiTransferLength);
  256. //
  257. // Copy the data from the RCV buffer to the given NDIS_BUFFER
  258. //
  259. *puiTransferred = CopyRcvBufferToNdisBuffer(pXferCtxt->pRcvBuf,
  260. pnbFirstBuffer,
  261. uiTransferLength,
  262. uiProtoOffset + uiTransferOffset,
  263. uiTransferOffset);
  264. TraceLeave(SEND, "IpIpTransferData");
  265. return NDIS_STATUS_PENDING;
  266. }
  267. uint
  268. CopyRcvBufferToNdisBuffer(
  269. IN IPRcvBuf *pRcvBuffer,
  270. IN OUT PNDIS_BUFFER pnbNdisBuffer,
  271. IN uint Size,
  272. IN uint RcvBufferOffset,
  273. IN uint NdisBufferOffset
  274. )
  275. {
  276. uint TotalBytesCopied = 0; // Bytes we've copied so far.
  277. uint BytesCopied = 0; // Bytes copied out of each buffer.
  278. uint DestSize, RcvSize; // Size left in current destination and
  279. // recv. buffers, respectively.
  280. uint BytesToCopy; // How many bytes to copy this time.
  281. NTSTATUS Status;
  282. RtAssert(RcvBuf != NULL);
  283. RtAssert(RcvOffset <= RcvBuf->ipr_size);
  284. //
  285. // The destination buffer can be NULL - this is valid, if odd.
  286. //
  287. if(pnbDestBuf != NULL)
  288. {
  289. }
  290. RcvSize = RcvBuf->ipr_size - RcvOffset;
  291. DestSize = NdisBufferLength(DestBuf);
  292. if (Size < DestSize)
  293. {
  294. DestSize = Size;
  295. }
  296. do
  297. {
  298. //
  299. // Compute the amount to copy, and then copy from the
  300. // appropriate offsets.
  301. BytesToCopy = MIN(DestSize, RcvSize);
  302. Status = TdiCopyBufferToMdl(RcvBuf->ipr_buffer,
  303. RcvOffset,
  304. BytesToCopy,
  305. DestBuf,
  306. DestOffset,
  307. &BytesCopied);
  308. if (!NT_SUCCESS(Status))
  309. {
  310. break;
  311. }
  312. RtAssert(BytesCopied == BytesToCopy);
  313. TotalBytesCopied += BytesCopied;
  314. DestSize -= BytesCopied;
  315. DestOffset += BytesCopied;
  316. RcvSize -= BytesToCopy;
  317. if (!RcvSize)
  318. {
  319. //
  320. // Exhausted this buffer.
  321. RcvBuf = RcvBuf->ipr_next;
  322. //
  323. // If we have another one, use it.
  324. //
  325. if (RcvBuf != NULL)
  326. {
  327. RcvOffset = 0;
  328. RcvSize = RcvBuf->ipr_size;
  329. }
  330. else
  331. {
  332. break;
  333. }
  334. }
  335. else
  336. {
  337. //
  338. // Buffer not exhausted, update offset.
  339. //
  340. RcvOffset += BytesToCopy;
  341. }
  342. }while (DestSize);
  343. return TotalBytesCopied;
  344. }