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.

1250 lines
29 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. ipinip\send.c
  5. Abstract:
  6. The file contains the part of interface of the IP in IP tunnel driver
  7. to the TCP/IP stack that deals with sending data
  8. The code is a cleaned up version of wanarp\ipif.c which in turn
  9. was derived from HenrySa's ip\arp.c
  10. Revision History:
  11. AmritanR
  12. --*/
  13. #define __FILE_SIG__ SEND_SIG
  14. #include "inc.h"
  15. IP_STATUS
  16. SendICMPErr(IPAddr Src, IPHeader UNALIGNED *Header, uchar Type, uchar Code,
  17. ulong Pointer);
  18. VOID
  19. SendIcmpError(
  20. DWORD dwLocalAddress,
  21. PNDIS_BUFFER pnbFirstBuff,
  22. PVOID pvFirstData,
  23. ULONG ulFirstLen,
  24. BYTE byType,
  25. BYTE byCode
  26. );
  27. NDIS_STATUS
  28. IpIpSend(
  29. PVOID pvContext,
  30. NDIS_PACKET **ppPacketArray,
  31. UINT uiNumPackets,
  32. DWORD dwDestAddr,
  33. RouteCacheEntry *pRce,
  34. PVOID pvLinkContext
  35. )
  36. /*++
  37. Routine Description
  38. Function called by IP to send a packet
  39. Locks
  40. The TUNNEL is refcounted (by virtue of being in IP)
  41. Arguments
  42. pvContext Our context to IP for the interface - the PTUNNEL
  43. ppPacketArray The array of NDIS_PACKETs to send
  44. uiNumPackets The number of packets in the array
  45. dwDestAddr The destination (next hop) address
  46. pRce Pointer to RCE.
  47. pvLinkContext Only for P2MP interfaces
  48. Return Value
  49. NDIS_STATUS_SUCCESS
  50. --*/
  51. {
  52. PTUNNEL pTunnel;
  53. PWORK_QUEUE_ITEM pWorkItem;
  54. PQUEUE_NODE pQueueNode;
  55. KIRQL kiIrql;
  56. DWORD dwLastAddr;
  57. #if PROFILE
  58. LONGLONG llTime, llNow;
  59. KeQueryTickCount((PLARGE_INTEGER)&llTime);
  60. #endif
  61. TraceEnter(SEND, "IpIpSend");
  62. pTunnel = (PTUNNEL)pvContext;
  63. //
  64. // TODO: No one has a clue as to how to deal with multi-packet
  65. // sends. Right now we assume we get one packet. Later we can fix this
  66. //
  67. RtAssert(uiNumPackets is 1);
  68. //
  69. // All our packets are queued onto the TUNNEL before the transmit
  70. // routine is called. Allocate a link in the queue
  71. //
  72. pQueueNode = AllocateQueueNode();
  73. if(pQueueNode is NULL)
  74. {
  75. //
  76. // Running out of memory
  77. //
  78. Trace(SEND, INFO,
  79. ("IpIpSend: Couldnt allocate queue node\n"));
  80. TraceLeave(SEND, "IpIpSend");
  81. return NDIS_STATUS_RESOURCES;
  82. }
  83. pWorkItem = &(pQueueNode->WorkItem);
  84. pQueueNode->ppPacketArray = &(pQueueNode->pnpPacket);
  85. pQueueNode->pnpPacket = ppPacketArray[0];
  86. pQueueNode->uiNumPackets = uiNumPackets;
  87. pQueueNode->dwDestAddr = dwDestAddr;
  88. //
  89. // If we are not at PASSIVE, just schedule a worker to come back and
  90. // handle this
  91. //
  92. if(KeGetCurrentIrql() > PASSIVE_LEVEL)
  93. {
  94. Trace(SEND, INFO,
  95. ("IpIpSend: Irql too high, queueing packet\n"));
  96. //
  97. // We dont need to reference the TUNNEL because IP has a reference
  98. // to the INTERFACE
  99. //
  100. RtAcquireSpinLockAtDpcLevel(&(pTunnel->rlLock));
  101. //
  102. // Hack for quenching ICMP errors to the same destination
  103. //
  104. dwLastAddr = 0;
  105. if(pTunnel->dwOperState isnot IF_OPER_STATUS_OPERATIONAL)
  106. {
  107. ULONG i, ulFirstLen, ulTotalLen;
  108. PNDIS_PACKET pnpPacket;
  109. PNDIS_BUFFER pnbFirstBuff, pnbNewBuffer;
  110. PVOID pvFirstData;
  111. PIP_HEADER pHeader;
  112. //
  113. // Cant transmit on this, either because we are deleting this
  114. // interface, or because the admin has shut us down
  115. //
  116. for(i = 0; i < uiNumPackets; i++)
  117. {
  118. pnpPacket = ppPacketArray[i];
  119. //
  120. // Get the information about the packet and buffer
  121. //
  122. NdisGetFirstBufferFromPacket(pnpPacket,
  123. &pnbFirstBuff,
  124. &pvFirstData,
  125. &ulFirstLen,
  126. &ulTotalLen);
  127. RtAssert(pvFirstData isnot NULL);
  128. RtAssert(ulFirstLen >= sizeof(IP_HEADER));
  129. pHeader = (PIP_HEADER)pvFirstData;
  130. if(IsUnicastAddr(pHeader->dwDest))
  131. {
  132. pTunnel->ulOutUniPkts++;
  133. }
  134. else
  135. {
  136. pTunnel->ulOutNonUniPkts++;
  137. }
  138. pTunnel->ulOutDiscards++;
  139. //
  140. // Send an ICMP error
  141. //
  142. if(dwLastAddr isnot pHeader->dwSrc)
  143. {
  144. SendIcmpError(pTunnel->LOCALADDR,
  145. pnbFirstBuff,
  146. pvFirstData,
  147. ulFirstLen,
  148. ICMP_TYPE_DEST_UNREACHABLE,
  149. ICMP_CODE_HOST_UNREACHABLE);
  150. dwLastAddr = pHeader->dwSrc;
  151. }
  152. }
  153. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  154. FreeQueueNode(pQueueNode);
  155. Trace(SEND, INFO,
  156. ("IpIpSend: Tunnel %x has admin state %d so not sending\n",
  157. pTunnel,
  158. pTunnel->dwAdminState));
  159. TraceLeave(SEND, "IpIpSend");
  160. return NDIS_STATUS_SUCCESS;
  161. }
  162. //
  163. // Insert at the end of the queue
  164. //
  165. InsertTailList(&(pTunnel->lePacketQueueHead),
  166. &(pQueueNode->leQueueItemLink));
  167. #if PROFILE
  168. //
  169. // The time at which IP called us for these packets
  170. //
  171. pQueueNode->llSendTime = llTime;
  172. #endif
  173. if(pTunnel->bWorkItemQueued is FALSE)
  174. {
  175. //
  176. // Need to schedule a work item since one is not already scheduled
  177. //
  178. ExInitializeWorkItem(pWorkItem,
  179. IpIpDelayedSend,
  180. pTunnel);
  181. //
  182. // TODO: For delayed sends we ref the tunnel. Do we need to?
  183. //
  184. ReferenceTunnel(pTunnel);
  185. //
  186. // Reference the driver since the worker has to be scheduled
  187. //
  188. RtAcquireSpinLockAtDpcLevel(&g_rlStateLock);
  189. g_ulNumThreads++;
  190. RtReleaseSpinLockFromDpcLevel(&g_rlStateLock);
  191. pTunnel->bWorkItemQueued = TRUE;
  192. ExQueueWorkItem(pWorkItem,
  193. CriticalWorkQueue);
  194. }
  195. #if PROFILE
  196. //
  197. // We update this field after queing the work item, but it is
  198. // still safe since the field is protected by the tunnel lock
  199. // This is the time at which the work item was queued
  200. //
  201. KeQueryTickCount((PLARGE_INTEGER)&(pQueueNode->llCallTime));
  202. #endif
  203. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  204. TraceLeave(SEND, "IpIpSend");
  205. return NDIS_STATUS_PENDING;
  206. }
  207. //
  208. // We dont need to reference the TUNNEL because IP has a reference to
  209. // the INTERFACE
  210. //
  211. //
  212. // If we are here, it is because we are at passive
  213. //
  214. //
  215. // Just hook the queue item to the end of the list and call the
  216. // transmit routine
  217. //
  218. RtAcquireSpinLock(&(pTunnel->rlLock),
  219. &kiIrql);
  220. InsertTailList(&(pTunnel->lePacketQueueHead),
  221. &(pQueueNode->leQueueItemLink));
  222. RtReleaseSpinLock(&(pTunnel->rlLock),
  223. kiIrql);
  224. #if PROFILE
  225. pQueueNode->llSendTime = llTime;
  226. KeQueryTickCount((PLARGE_INTEGER)&llNow);
  227. pQueueNode->llCallTime = llNow;
  228. #endif
  229. IpIpTransmit(pTunnel,
  230. FALSE);
  231. return NDIS_STATUS_PENDING;
  232. }
  233. VOID
  234. IpIpDelayedSend(
  235. PVOID pvContext
  236. )
  237. /*++
  238. Routine Description
  239. The worker function called when we find that the send from IP was
  240. not at PASSIVE
  241. Locks
  242. None
  243. Arguments
  244. None
  245. Return Value
  246. None
  247. --*/
  248. {
  249. PTUNNEL pTunnel;
  250. ULONG i;
  251. KIRQL irql;
  252. NDIS_STATUS nsStatus;
  253. TraceEnter(SEND, "IpIpDelayedSend");
  254. pTunnel = (PTUNNEL)pvContext;
  255. RtAssert(pTunnel);
  256. IpIpTransmit(pTunnel,
  257. TRUE);
  258. //
  259. // Either IpIpTransmit or TdixSendComplete will do the SendComplete
  260. //
  261. //
  262. // We referenced the tunnel if we put it on the work queue
  263. // Deref it now
  264. //
  265. DereferenceTunnel(pTunnel);
  266. RtAcquireSpinLock(&g_rlStateLock,
  267. &irql);
  268. g_ulNumThreads--;
  269. if((g_dwDriverState is DRIVER_STOPPED) and
  270. (g_ulNumThreads is 0))
  271. {
  272. KeSetEvent(&g_keStateEvent,
  273. 0,
  274. FALSE);
  275. }
  276. RtReleaseSpinLock(&g_rlStateLock,
  277. irql);
  278. TraceLeave(SEND, "IpIpDelayedSend");
  279. }
  280. VOID
  281. IpIpTransmit(
  282. PTUNNEL pTunnel,
  283. BOOLEAN bFromWorker
  284. )
  285. /*++
  286. Routine Description
  287. Called to transmit any queued packets on the tunnel
  288. Locks
  289. This MUST be called at passive
  290. Arguments
  291. pTunnel The tunnel whose queue needs to be transmitted
  292. bFromWorker TRUE if called off a worker
  293. Return Value
  294. None
  295. This is an implicit asynchronous call
  296. --*/
  297. {
  298. PIP_HEADER pHeader, pNewHeader;
  299. USHORT usLength;
  300. KIRQL irql;
  301. UINT i;
  302. ULONG ulFirstLen, ulTotalLen;
  303. PNDIS_PACKET pnpPacket;
  304. PNDIS_BUFFER pnbFirstBuff, pnbNewBuffer;
  305. PVOID pvFirstData;
  306. NTSTATUS nStatus;
  307. PLIST_ENTRY pleNode;
  308. PQUEUE_NODE pQueueNode;
  309. #if PROFILE
  310. LONGLONG llCurrentTime;
  311. KeQueryTickCount((PLARGE_INTEGER)&llCurrentTime);
  312. #endif
  313. TraceEnter(SEND, "IpIpTransmit");
  314. RtAcquireSpinLock(&(pTunnel->rlLock),
  315. &irql);
  316. if(pTunnel->dwOperState isnot IF_OPER_STATUS_OPERATIONAL)
  317. {
  318. //
  319. // Cant transmit on this, either because we are deleting this
  320. // interface, or because the admin has shut us down
  321. // Just walk all the packets, increment the stats and then
  322. // call SendComplete for the packet
  323. //
  324. while(!IsListEmpty(&(pTunnel->lePacketQueueHead)))
  325. {
  326. DWORD dwLastAddr;
  327. pleNode = RemoveHeadList(&(pTunnel->lePacketQueueHead));
  328. pQueueNode = CONTAINING_RECORD(pleNode,
  329. QUEUE_NODE,
  330. leQueueItemLink);
  331. dwLastAddr = 0;
  332. for(i = 0; i < pQueueNode->uiNumPackets; i++)
  333. {
  334. pnpPacket = pQueueNode->ppPacketArray[i];
  335. //
  336. // Get the information about the packet and buffer
  337. //
  338. NdisGetFirstBufferFromPacket(pnpPacket,
  339. &pnbFirstBuff,
  340. &pvFirstData,
  341. &ulFirstLen,
  342. &ulTotalLen);
  343. RtAssert(pvFirstData isnot NULL);
  344. RtAssert(ulFirstLen >= sizeof(IP_HEADER));
  345. pHeader = (PIP_HEADER)pvFirstData;
  346. if(IsUnicastAddr(pHeader->dwDest))
  347. {
  348. pTunnel->ulOutUniPkts++;
  349. }
  350. else
  351. {
  352. pTunnel->ulOutNonUniPkts++;
  353. }
  354. pTunnel->ulOutDiscards++;
  355. RtReleaseSpinLock(&(pTunnel->rlLock),
  356. irql);
  357. //
  358. // Send an ICMP error
  359. //
  360. if(dwLastAddr isnot pHeader->dwSrc)
  361. {
  362. SendIcmpError(pTunnel->LOCALADDR,
  363. pnbFirstBuff,
  364. pvFirstData,
  365. ulFirstLen,
  366. ICMP_TYPE_DEST_UNREACHABLE,
  367. ICMP_CODE_HOST_UNREACHABLE);
  368. dwLastAddr = pHeader->dwSrc;
  369. }
  370. g_pfnIpSendComplete(pTunnel->pvIpContext,
  371. pnpPacket,
  372. NDIS_STATUS_ADAPTER_NOT_READY);
  373. RtAcquireSpinLock(&(pTunnel->rlLock),
  374. &irql);
  375. }
  376. FreeQueueNode(pQueueNode);
  377. }
  378. if(bFromWorker)
  379. {
  380. pTunnel->bWorkItemQueued = FALSE;
  381. }
  382. RtReleaseSpinLock(&(pTunnel->rlLock),
  383. irql);
  384. TraceLeave(SEND, "IpIpTransmit");
  385. return;
  386. }
  387. while(!IsListEmpty(&(pTunnel->lePacketQueueHead)))
  388. {
  389. pleNode = RemoveHeadList(&(pTunnel->lePacketQueueHead));
  390. pQueueNode = CONTAINING_RECORD(pleNode,
  391. QUEUE_NODE,
  392. leQueueItemLink);
  393. for(i = 0; i < pQueueNode->uiNumPackets; i++)
  394. {
  395. pnpPacket = pQueueNode->ppPacketArray[i];
  396. //
  397. // Get the information about the packet and buffer
  398. //
  399. NdisGetFirstBufferFromPacket(pnpPacket,
  400. &pnbFirstBuff,
  401. &pvFirstData,
  402. &ulFirstLen,
  403. &ulTotalLen);
  404. RtAssert(pvFirstData isnot NULL);
  405. //
  406. // Remove this till NK fixes the bug in IPTransmit
  407. // NB:
  408. //RtAssert(ulFirstLen >= sizeof(IP_HEADER));
  409. pHeader = (PIP_HEADER)pvFirstData;
  410. if(IsUnicastAddr(pHeader->dwDest))
  411. {
  412. pTunnel->ulOutUniPkts++;
  413. }
  414. else
  415. {
  416. pTunnel->ulOutNonUniPkts++;
  417. if(IsClassEAddr(pHeader->dwDest))
  418. {
  419. //
  420. // Bad address - throw it away
  421. //
  422. pTunnel->ulOutErrors++;
  423. //
  424. // Release the spinlock, call IP's SendComplete,
  425. // reacquire the spinlock and continue processing the
  426. // array
  427. //
  428. RtReleaseSpinLock(&(pTunnel->rlLock),
  429. irql);
  430. g_pfnIpSendComplete(pTunnel->pvIpContext,
  431. pnpPacket,
  432. NDIS_STATUS_INVALID_PACKET);
  433. RtAcquireSpinLock(&(pTunnel->rlLock),
  434. &irql);
  435. continue;
  436. }
  437. }
  438. //
  439. // We dont need to muck with the TTL, since the IP stack would have
  440. // decremented it
  441. //
  442. //
  443. // RFC 2003 pg 6:
  444. // If the IP Source Address of the datagram matches router's own
  445. // IP Address, on any of its network interfaces, the router MUST NOT
  446. // tunnel the datagram; instead the datagram SHOULD be discarded
  447. //
  448. // TODO: This means comparing it against all the addresses that we
  449. // have
  450. //
  451. // RFC 2003 pg 6:
  452. // If the IP Source Address of the datagram matches the IP Address
  453. // of the Tunnel Destination, the router MUST NOT tunnel the
  454. // datagram; instead the datagram SHOULD be discarded
  455. //
  456. if(pHeader->dwDest is pTunnel->REMADDR)
  457. {
  458. Trace(SEND, ERROR,
  459. ("IpIpTransmit: Packet # %d had dest of %d.%d.%d.%d which matches the remote endpoint\n",
  460. i, PRINT_IPADDR(pHeader->dwDest)));
  461. pTunnel->ulOutErrors++;
  462. RtReleaseSpinLock(&(pTunnel->rlLock),
  463. irql);
  464. g_pfnIpSendComplete(pTunnel->pvIpContext,
  465. pnpPacket,
  466. NDIS_STATUS_INVALID_PACKET);
  467. RtAcquireSpinLock(&(pTunnel->rlLock),
  468. &irql);
  469. continue;
  470. }
  471. //
  472. // Slap on an IP header
  473. //
  474. pNewHeader = GetIpHeader(pTunnel);
  475. if(pNewHeader is NULL)
  476. {
  477. pTunnel->ulOutDiscards++;
  478. //
  479. // Not enough resources
  480. //
  481. Trace(SEND, ERROR,
  482. ("IpIpTransmit: Could not get buffer for header\n"));
  483. RtReleaseSpinLock(&(pTunnel->rlLock),
  484. irql);
  485. g_pfnIpSendComplete(pTunnel->pvIpContext,
  486. pnpPacket,
  487. NDIS_STATUS_RESOURCES);
  488. RtAcquireSpinLock(&(pTunnel->rlLock),
  489. &irql);
  490. continue;
  491. }
  492. pNewHeader->byVerLen = IP_VERSION_LEN;
  493. pNewHeader->byTos = pHeader->byTos;
  494. //
  495. // Currently we dont have any options, so all we do
  496. // is add 20 bytes to the length
  497. //
  498. usLength = RtlUshortByteSwap(pHeader->wLength) + MIN_IP_HEADER_LENGTH;
  499. pNewHeader->wLength = RtlUshortByteSwap(usLength);
  500. //
  501. // Id is set up by IP stack
  502. // If the DF flag is set, copy that out
  503. //
  504. pNewHeader->wFlagOff = (pHeader->wFlagOff & IP_DF_FLAG);
  505. pNewHeader->byTtl = pTunnel->byTtl;
  506. pNewHeader->byProtocol = PROTO_IPINIP;
  507. //
  508. // XSum is done by IP, but we need to zero it out
  509. //
  510. pNewHeader->wXSum = 0x0000;
  511. pNewHeader->dwSrc = pTunnel->LOCALADDR;
  512. pNewHeader->dwDest = pTunnel->REMADDR;
  513. //
  514. // Slap on the buffer in front of the current packet
  515. // and we are done
  516. //
  517. pnbNewBuffer = GetNdisBufferFromBuffer((PBYTE)pNewHeader);
  518. RtAssert(pnbNewBuffer);
  519. #if DBG
  520. //
  521. // Query the buffer to see that everything is setup OK
  522. //
  523. #endif
  524. NdisChainBufferAtFront(pnpPacket,
  525. pnbNewBuffer);
  526. //
  527. // Reference the tunnel, once for every send
  528. // ulOutDiscards, ulOutOctets are incremented in
  529. // SendComplete handler.
  530. //
  531. pTunnel->ulOutQLen++;
  532. ReferenceTunnel(pTunnel);
  533. RtReleaseSpinLock(&(pTunnel->rlLock),
  534. irql);
  535. //
  536. // Dont really care about the return code from here.
  537. // Even if it is an error, TdixSendDatagram will call our send
  538. // complete handler
  539. //
  540. #if PROFILE
  541. TdixSendDatagram(pTunnel,
  542. pnpPacket,
  543. pnbNewBuffer,
  544. usLength,
  545. pQueueNode->llSendTime,
  546. pQueueNode->llCallTime,
  547. llCurrentTime);
  548. #else
  549. TdixSendDatagram(pTunnel,
  550. pnpPacket,
  551. pnbNewBuffer,
  552. usLength);
  553. #endif
  554. //
  555. // If we come till here, we will always have our SendComplete called
  556. // The DereferenceTunnel() will be done there
  557. //
  558. RtAcquireSpinLock(&(pTunnel->rlLock),
  559. &irql);
  560. }
  561. FreeQueueNode(pQueueNode);
  562. }
  563. //
  564. // Dont have a work item queued
  565. //
  566. if(bFromWorker)
  567. {
  568. pTunnel->bWorkItemQueued = FALSE;
  569. }
  570. RtReleaseSpinLock(&(pTunnel->rlLock),
  571. irql);
  572. TraceLeave(SEND, "IpIpTransmit");
  573. }
  574. VOID
  575. IpIpInvalidateRce(
  576. PVOID pvContext,
  577. RouteCacheEntry *pRce
  578. )
  579. /*++
  580. Routine Description
  581. Called by IP when an RCE is closed or otherwise invalidated.
  582. Locks
  583. Arguments
  584. Return Value
  585. NO_ERROR
  586. --*/
  587. {
  588. }
  589. UINT
  590. IpIpReturnPacket(
  591. PVOID pARPInterfaceContext,
  592. PNDIS_PACKET pPacket
  593. )
  594. {
  595. return STATUS_SUCCESS;
  596. }
  597. VOID
  598. IpIpSendComplete(
  599. NTSTATUS nSendStatus,
  600. PTUNNEL pTunnel,
  601. PNDIS_PACKET pnpPacket,
  602. ULONG ulPktLength
  603. )
  604. /*++
  605. Routine Description
  606. Locks
  607. We acquire the TUNNEL lock
  608. Arguments
  609. Return Value
  610. --*/
  611. {
  612. KIRQL irql;
  613. PNDIS_BUFFER pnbFirstBuffer;
  614. UINT uiFirstLength;
  615. PVOID pvFirstData;
  616. TraceEnter(SEND, "IpIpSendComplete");
  617. //
  618. // The tunnel was refcounted, so could not have gone away
  619. // Lock it
  620. //
  621. RtAcquireSpinLock(&(pTunnel->rlLock),
  622. &irql);
  623. //
  624. // If the status was success, increment the bytes sent
  625. // otherwise increment the bytes
  626. //
  627. if(nSendStatus isnot STATUS_SUCCESS)
  628. {
  629. Trace(SEND, ERROR,
  630. ("IpIpSendComplete: Status %x sending data\n",
  631. nSendStatus));
  632. pTunnel->ulOutDiscards++;
  633. }
  634. else
  635. {
  636. pTunnel->ulOutOctets += ulPktLength;
  637. }
  638. //
  639. // Decrement the Qlen
  640. //
  641. pTunnel->ulOutQLen--;
  642. RtReleaseSpinLock(&(pTunnel->rlLock),
  643. irql);
  644. //
  645. // Free the IP header we slapped on
  646. //
  647. NdisUnchainBufferAtFront(pnpPacket,
  648. &pnbFirstBuffer);
  649. NdisQueryBuffer(pnbFirstBuffer,
  650. &pvFirstData,
  651. &uiFirstLength);
  652. RtAssert(uiFirstLength is MIN_IP_HEADER_LENGTH);
  653. FreeIpHeader(pTunnel,
  654. pvFirstData);
  655. //
  656. // We are done. Just indicate everything back up to IP
  657. //
  658. g_pfnIpSendComplete(pTunnel->pvIpContext,
  659. pnpPacket,
  660. nSendStatus);
  661. //
  662. // Done with the tunnel, deref it
  663. //
  664. DereferenceTunnel(pTunnel);
  665. TraceEnter(SEND, "IpIpSendComplete");
  666. }
  667. #if 0
  668. NDIS_STATUS
  669. IpIpTransferData(
  670. PVOID pvContext,
  671. NDIS_HANDLE nhMacContext,
  672. UINT uiProtoOffset,
  673. UINT uiTransferOffset,
  674. UINT uiTransferLength,
  675. PNDIS_PACKET pnpPacket,
  676. PUINT puiTransferred
  677. )
  678. /*++
  679. Routine Description
  680. Locks
  681. Arguments
  682. Return Value
  683. NO_ERROR
  684. --*/
  685. {
  686. NTSTATUS nStatus;
  687. PNDIS_PACKET pnpOriginalPacket;
  688. ULONG ulTotalSrcLen, ulTotalDestLen;
  689. ULONG ulDestOffset, ulSrcOffset;
  690. ULONG ulCopyLength, ulBytesCopied;
  691. PNDIS_BUFFER pnbSrcBuffer, pnbDestBuffer;
  692. PVOID pvDataToCopy;
  693. //
  694. // The TD context we gave IP was just a pointer to the NDIS_PACKET
  695. //
  696. pnpOriginalPacket = (PNDIS_PACKET)nhMacContext;
  697. //
  698. // Get info about the first buffer in the src packet
  699. //
  700. NdisQueryPacket(pnpOriginalPacket,
  701. NULL,
  702. NULL,
  703. &pnbSrcBuffer,
  704. &ulTotalSrcLen);
  705. //
  706. // Query the given packet to get the Destination buffer
  707. // and the Total length
  708. //
  709. NdisQueryPacket(pnpPacket,
  710. NULL,
  711. NULL,
  712. &pnbDestBuffer,
  713. &ulTotalDestLen);
  714. ulSrcOffset = uiTransferOffset + uiProtoOffset;
  715. //
  716. // Make sure that we have enough data to fulfil the request
  717. //
  718. RtAssert((ulTotalSrcLen - ulSrcOffset) >= uiTransferLength);
  719. RtAssert(pnbDestBuffer);
  720. //
  721. // ulDestOffset is also a count of the bytes copied till now
  722. //
  723. ulDestOffset = 0;
  724. while(pnbSrcBuffer)
  725. {
  726. NdisQueryBuffer(pnbSrcBuffer,
  727. &pvDataToCopy,
  728. &ulCopyLength);
  729. //
  730. // See if we need to copy the whole buffer or only part
  731. // of it. ulDestOffset is also a count of he bytes copied
  732. // up till this point
  733. //
  734. if(uiTransferLength - ulDestOffset < ulCopyLength)
  735. {
  736. //
  737. // Need to copy less than this buffer
  738. //
  739. ulCopyLength = uiTransferLength - ulDestOffset;
  740. }
  741. #if NDISBUFFERISMDL
  742. nStatus = TdiCopyBufferToMdl(pvDataToCopy,
  743. ulSrcOffset,
  744. ulCopyLength,
  745. pnbDestBuffer,
  746. ulDestOffset,
  747. &ulBytesCopied);
  748. #else
  749. #error "Fix this"
  750. #endif
  751. if((nStatus isnot STATUS_SUCCESS) and
  752. (ulBytesCopied isnot ulCopyLength))
  753. {
  754. //
  755. // something bad happened in the copy
  756. //
  757. }
  758. ulSrcOffset = 0;
  759. ulDestOffset += ulBytesCopied;
  760. NdisGetNextBuffer(pnbSrcBuffer, &pnbSrcBuffer);
  761. }
  762. *puiTransferred = ulDestOffset;
  763. }
  764. #endif
  765. NDIS_STATUS
  766. IpIpTransferData(
  767. PVOID pvContext,
  768. NDIS_HANDLE nhMacContext,
  769. UINT uiProtoOffset,
  770. UINT uiTransferOffset,
  771. UINT uiTransferLength,
  772. PNDIS_PACKET pnpPacket,
  773. PUINT puiTransferred
  774. )
  775. /*++
  776. Routine Description
  777. Locks
  778. Arguments
  779. Return Value
  780. NO_ERROR
  781. --*/
  782. {
  783. PTRANSFER_CONTEXT pXferCtxt;
  784. TraceEnter(SEND, "IpIpTransferData");
  785. pXferCtxt = (PTRANSFER_CONTEXT)nhMacContext;
  786. pXferCtxt->pvContext = pvContext;
  787. pXferCtxt->uiProtoOffset = uiProtoOffset;
  788. pXferCtxt->uiTransferOffset = uiTransferOffset;
  789. pXferCtxt->uiTransferLength = uiTransferLength;
  790. pXferCtxt->pnpTransferPacket = pnpPacket;
  791. *puiTransferred = 0;
  792. pXferCtxt->bRequestTransfer = TRUE;
  793. TraceLeave(SEND, "IpIpTransferData");
  794. return NDIS_STATUS_PENDING;
  795. }
  796. VOID
  797. SendIcmpError(
  798. DWORD dwLocalAddress,
  799. PNDIS_BUFFER pnbFirstBuff,
  800. PVOID pvFirstData,
  801. ULONG ulFirstLen,
  802. BYTE byType,
  803. BYTE byCode
  804. )
  805. /*++
  806. Routine Description:
  807. Internal routine called to send an icmp error message
  808. Locks:
  809. None needed, the buffers shouldnt be modified while the function is
  810. in progress
  811. Arguments:
  812. dwLocalAddress NTE on which this packet was received
  813. pnbFirstBuffer The buffer that has the IP Header
  814. pvFirstData Pointer to the data in the buffer
  815. ulFirstLen Size of the buffer
  816. byType ICMP type to return
  817. byCode ICMP code to return
  818. Return Value:
  819. None
  820. --*/
  821. {
  822. struct IPHeader *pErrorHeader;
  823. BYTE FlatHeader[MAX_IP_HEADER_LENGTH + ICMP_HEADER_LENGTH];
  824. ULONG ulSecondLen, ulLeft;
  825. PVOID pvSecondBuff;
  826. //
  827. // If the error is being sent in response to an ICMP
  828. // packet, tcpip will touch the icmp header also
  829. // So we copy it into a flat buffer
  830. //
  831. pErrorHeader = NULL;
  832. if((ulFirstLen < MAX_IP_HEADER_LENGTH + ICMP_HEADER_LENGTH) and
  833. (ulFirstLen < (ULONG)RtlUshortByteSwap(((PIP_HEADER)pvFirstData)->wLength)))
  834. {
  835. NdisQueryBufferSafe(NDIS_BUFFER_LINKAGE(pnbFirstBuff),
  836. &pvSecondBuff,
  837. &ulSecondLen,
  838. LowPagePriority);
  839. if(pvSecondBuff isnot NULL)
  840. {
  841. //
  842. // First copy out what's in the first buffer
  843. //
  844. RtlCopyMemory(FlatHeader,
  845. pvFirstData,
  846. ulFirstLen);
  847. //
  848. // How much is left in the flat buffer?
  849. //
  850. ulLeft = (MAX_IP_HEADER_LENGTH + ICMP_HEADER_LENGTH) - ulFirstLen;
  851. //
  852. // Copy out MIN(SecondBuffer, What's Left)
  853. //
  854. ulLeft = (ulSecondLen < ulLeft) ? ulSecondLen: ulLeft;
  855. RtlCopyMemory(FlatHeader + ulFirstLen,
  856. pvSecondBuff,
  857. ulLeft);
  858. pErrorHeader = (struct IPHeader *)&FlatHeader;
  859. }
  860. }
  861. else
  862. {
  863. pErrorHeader = (struct IPHeader *)pvFirstData;
  864. }
  865. if(pErrorHeader isnot NULL)
  866. {
  867. SendICMPErr(dwLocalAddress,
  868. pErrorHeader,
  869. ICMP_TYPE_DEST_UNREACHABLE,
  870. ICMP_CODE_HOST_UNREACHABLE,
  871. 0);
  872. }
  873. }