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.

5447 lines
188 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. ipxmit.c - IP transmit routines.
  5. Abstract:
  6. This module contains all transmit related IP routines.
  7. Author:
  8. [Environment:]
  9. kernel mode only
  10. [Notes:]
  11. optional-notes
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #include "info.h"
  16. #include "iproute.h"
  17. #include "iprtdef.h"
  18. #include "arpdef.h"
  19. #include "tcpipbuf.h"
  20. #include "mdlpool.h"
  21. #include "tcp.h"
  22. #include "tcpsend.h"
  23. #if DBG
  24. ulong DbgIPSendHwChkSum = 0;
  25. uint dbg_hdrincl = 0;
  26. #endif
  27. extern uint IPSecStatus;
  28. extern IPSecQStatusRtn IPSecQueryStatusPtr;
  29. extern Interface *IFList;
  30. extern NetTableEntry **NewNetTableList; // hash table for NTEs
  31. extern uint NET_TABLE_SIZE;
  32. extern NetTableEntry *LoopNTE; // Pointer to loopback NTE.
  33. extern NetTableEntry *DHCPNTE; // Pointer to NTE currently being DHCP'd.
  34. extern ulong TimeStamp; // Starting timestamp.
  35. extern ulong TSFlag; // Mask to use on this.
  36. extern uint NumNTE;
  37. IPID_CACHE_LINE IPIDCacheLine;
  38. // Global variables for buffers and packets.
  39. HANDLE IpHeaderPool;
  40. //
  41. // the global address for unnumbered interfaces
  42. //
  43. extern IPAddr g_ValidAddr;
  44. BufferReference *GetBufferReference(void);
  45. IP_STATUS ARPResolve(IPAddr DestAddress, IPAddr SourceAddress,
  46. ARPControlBlock *ControlBlock, ArpRtn Callback);
  47. NDIS_STATUS ARPResolveIP(void *Context, IPAddr Destination,
  48. ARPControlBlock *ArpContB);
  49. IP_STATUS SendICMPIPSecErr(IPAddr, IPHeader UNALIGNED *, uchar, uchar, ulong);
  50. int ReferenceBuffer(BufferReference * BR, int Count);
  51. extern Interface LoopInterface;
  52. extern uint NumIF;
  53. NDIS_HANDLE NdisPacketPool = NULL;
  54. NDIS_HANDLE BufferPool;
  55. #define BCAST_IF_CTXT (Interface *)-1
  56. uint PacketPoolSizeMin = PACKET_GROW_COUNT;
  57. uint PacketPoolSizeMax = SMALL_POOL;
  58. //** GetIPID - Routine to get IP identification
  59. //
  60. // Input: None
  61. //
  62. // Returns: IPID+1
  63. //
  64. ushort
  65. GetIPID()
  66. {
  67. return((ushort)InterlockedExchangeAdd(&IPIDCacheLine.Value, 1));
  68. }
  69. //** FreeIPHdrBuffer - Free a buffer back to the pool.
  70. //
  71. // Input: Buffer - Hdr buffer to be freed.
  72. //
  73. // Returns: Nothing.
  74. //
  75. __inline
  76. VOID
  77. FreeIPHdrBuffer(PNDIS_BUFFER Buffer)
  78. {
  79. MdpFree(Buffer);
  80. }
  81. //** FreeIPBufferChain - Free a chain of IP buffers.
  82. //
  83. // This routine takes a chain of NDIS_BUFFERs, and frees them all.
  84. //
  85. // Entry: Buffer - Pointer to buffer chain to be freed.
  86. //
  87. // Returns: Nothing.
  88. //
  89. void
  90. FreeIPBufferChain(PNDIS_BUFFER Buffer)
  91. {
  92. PNDIS_BUFFER NextBuffer;
  93. while (Buffer != (PNDIS_BUFFER) NULL) {
  94. NdisGetNextBuffer(Buffer, &NextBuffer);
  95. NdisFreeBuffer(Buffer);
  96. Buffer = NextBuffer;
  97. }
  98. }
  99. //** Free payload mdl
  100. //
  101. // Input: Buffer - Bufferchain which has ip allocated ndis_buffer
  102. // OriginalBuffer - Original buffer which needs to be restored
  103. //
  104. // Returns: Nothing.
  105. //
  106. __inline
  107. VOID
  108. FreeIPPayloadBuffer(PNDIS_BUFFER Buffer, PNDIS_BUFFER OrgBuffer)
  109. {
  110. PNDIS_BUFFER PayloadBuffer;
  111. PayloadBuffer = NDIS_BUFFER_LINKAGE(Buffer);
  112. NDIS_BUFFER_LINKAGE(Buffer) = OrgBuffer;
  113. ASSERT(NDIS_BUFFER_LINKAGE(OrgBuffer) == NDIS_BUFFER_LINKAGE(PayloadBuffer));
  114. //KdPrint(("sendbcast restoring hdrincl %x %x\n",OrgBuffer,PayloadBuffer));
  115. NDIS_BUFFER_LINKAGE(PayloadBuffer) = NULL;
  116. NdisFreeBuffer(PayloadBuffer);
  117. }
  118. //** RestoreUserBuffer - Restores original user supplied buffer
  119. //
  120. // Takes orginal buffer and chains it back in the packet,
  121. // freeing the one allocated by the stack.
  122. //
  123. // Entry: Packet
  124. //
  125. // Returns: Nothing.
  126. //
  127. void
  128. RestoreUserBuffer(PNDIS_PACKET Packet)
  129. {
  130. PNDIS_BUFFER NextBuffer;
  131. PacketContext *pc = (PacketContext *) Packet->ProtocolReserved;
  132. PNDIS_BUFFER OrgBuffer, FirewallBuffer, Buffer;
  133. BufferReference *BufRef;
  134. BufRef = pc->pc_br;
  135. FirewallBuffer = pc->pc_firewall;
  136. OrgBuffer = pc->pc_hdrincl;
  137. ASSERT(OrgBuffer != NULL);
  138. pc->pc_hdrincl = NULL;
  139. NdisQueryPacket(Packet, NULL, NULL, &NextBuffer, NULL);
  140. if (!FirewallBuffer) {
  141. // Firewall didn't munge the buffer: apply the normal stuff
  142. // if bufref is true, IPFrag was called.
  143. // buffer chain will be at ->br_buffer.
  144. if (BufRef == (BufferReference *) NULL) {
  145. Buffer = NDIS_BUFFER_LINKAGE(NextBuffer);
  146. if (pc->pc_common.pc_flags & PACKET_FLAG_OPTIONS) {
  147. Buffer = NDIS_BUFFER_LINKAGE(Buffer);
  148. }
  149. } else {
  150. Buffer = BufRef->br_buffer;
  151. }
  152. FreeIPPayloadBuffer(Buffer, OrgBuffer);
  153. } else {
  154. if (BufRef == NULL) {
  155. Buffer = FirewallBuffer;
  156. if (pc->pc_common.pc_flags & PACKET_FLAG_OPTIONS) {
  157. Buffer = NDIS_BUFFER_LINKAGE(Buffer);
  158. }
  159. FreeIPPayloadBuffer(Buffer, OrgBuffer);
  160. }
  161. }
  162. }
  163. //* FreeIPPacket - Free an IP packet when we're done with it.
  164. //
  165. // Called when a send completes and a packet needs to be freed. We look at the
  166. // packet, decide what to do with it, and free the appropriate components.
  167. //
  168. // Entry: Packet - Packet to be freed.
  169. // FixHdrs - If true, restores headers changed by ipsec/firewall and hdrinclude
  170. // before freeing the packet.
  171. // Status - final status from packet-processing.
  172. //
  173. // Returns: Pointer to next unfreed buffer on packet, or NULL if all buffers freed
  174. // (i.e. this was a fragmented packet).
  175. //
  176. PNDIS_BUFFER
  177. FreeIPPacket(PNDIS_PACKET Packet, BOOLEAN FixHdrs, IP_STATUS Status)
  178. {
  179. PNDIS_BUFFER NextBuffer, OldBuffer;
  180. PacketContext *pc = (PacketContext *) Packet->ProtocolReserved;
  181. PNDIS_BUFFER OrgBuffer = NULL;
  182. PNDIS_BUFFER FirewallBuffer = NULL;
  183. FWContext *FWC = (FWContext *) Packet->ProtocolReserved;
  184. BufferReference *BufRef; // Buffer reference, if any.
  185. BOOLEAN InitFirewallContext = FALSE;
  186. NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ClassificationHandlePacketInfo) = NULL;
  187. NdisClearPacketFlags(Packet, (NDIS_FLAGS_DONT_LOOPBACK | NDIS_FLAGS_LOOPBACK_ONLY));
  188. #if !MILLEN
  189. // ndis 5.1 feature
  190. NDIS_SET_PACKET_CANCEL_ID(Packet, NULL);
  191. #endif
  192. NdisQueryPacket(Packet, NULL, NULL, &NextBuffer, NULL);
  193. if ((pc->pc_common.pc_flags & PACKET_FLAG_FW) && FWC->fc_bufown) {
  194. //Pkt forwarded thru buffer owner ship
  195. ASSERT(pc->pc_firewall == NULL);
  196. return NextBuffer;
  197. }
  198. BufRef = pc->pc_br;
  199. // Restore the original buffer and MDL chain back.
  200. // We should restore the reverse order in which the input Buffer was modified
  201. // Order of modification: hdr_incl -> firewall -> ipsec
  202. // Order of restoration: ipsec -> firewall -> hdr_incl
  203. //
  204. // See if IPSEC has to fix up anything
  205. //
  206. if (FixHdrs && pc->pc_common.pc_IpsecCtx) {
  207. PNDIS_BUFFER NewBuffer;
  208. if (!BufRef || (pc->pc_ipsec_flags & IPSEC_FLAG_FRAG_DONE)) {
  209. ASSERT(IPSecSendCmpltPtr);
  210. (*IPSecSendCmpltPtr) (Packet,
  211. NextBuffer,
  212. pc->pc_common.pc_IpsecCtx,
  213. Status,
  214. &NewBuffer);
  215. pc->pc_common.pc_IpsecCtx = NULL;
  216. if (NewBuffer) {
  217. NextBuffer = NewBuffer;
  218. } else {
  219. //
  220. // Reinjected packet, no IP resources to free
  221. //
  222. pc->pc_firewall = NULL;
  223. pc->pc_firewall2 = NULL;
  224. NdisFreePacket(Packet);
  225. return NULL;
  226. }
  227. } else {
  228. pc->pc_common.pc_IpsecCtx = NULL;
  229. }
  230. }
  231. //
  232. // FirewallBuffer will point to the input buffer which was passed to the
  233. // firewall hook it will be non-NULL only if hook touched the packet
  234. //
  235. FirewallBuffer = pc->pc_firewall;
  236. //
  237. // Check if the buffers were munged by the firewall: FirewallBuffer != NULL
  238. // If yes, restore original buffer
  239. //
  240. if (FixHdrs && FirewallBuffer) {
  241. PNDIS_BUFFER NewBuffer;
  242. PNDIS_BUFFER TmpBuffer;
  243. if (BufRef == NULL) {
  244. // Non fragmentation path
  245. // if bufref is true means
  246. // IPFrag was called buffer chain will.
  247. // be at ->br_buffer.
  248. // restoration will be done in ipsendcomplete when last fragment
  249. // send completes
  250. NewBuffer = NextBuffer;
  251. if (!((pc->pc_common.pc_flags & PACKET_FLAG_IPHDR) ||
  252. (pc->pc_common.pc_flags & PACKET_FLAG_OPTIONS))) {
  253. // neither header nor option buffer
  254. NdisReinitializePacket(Packet);
  255. NdisChainBufferAtBack(Packet, FirewallBuffer);
  256. NextBuffer = FirewallBuffer;
  257. } else if ((pc->pc_common.pc_flags & PACKET_FLAG_IPHDR) &&
  258. (pc->pc_common.pc_flags & PACKET_FLAG_OPTIONS)) {
  259. // both header and option buffer
  260. ASSERT(NewBuffer != NULL);
  261. NewBuffer = NDIS_BUFFER_LINKAGE(NewBuffer); // skip hdr buffer
  262. ASSERT(NewBuffer != NULL);
  263. TmpBuffer = NewBuffer;
  264. NewBuffer = NDIS_BUFFER_LINKAGE(NewBuffer); // skip options buffer
  265. NDIS_BUFFER_LINKAGE(TmpBuffer) = FirewallBuffer;
  266. } else {
  267. // just header buffer
  268. ASSERT(pc->pc_common.pc_flags & PACKET_FLAG_IPHDR);
  269. ASSERT(!(pc->pc_common.pc_flags & PACKET_FLAG_OPTIONS));
  270. ASSERT(NewBuffer != NULL);
  271. TmpBuffer = NewBuffer;
  272. NewBuffer = NDIS_BUFFER_LINKAGE(NewBuffer); // skip the header buffer
  273. NDIS_BUFFER_LINKAGE(TmpBuffer) = FirewallBuffer;
  274. }
  275. //
  276. // At this point NewBuffer points to the MDL chain allocated by
  277. // the firewall. WE have already restored the original chain back
  278. //
  279. FreeIPBufferChain(NewBuffer);
  280. pc->pc_firewall = NULL;
  281. //
  282. // We have to free OutRcvBuf chain we allocated and passed to
  283. // firewall. This is the completion point, so we should free this
  284. // chain here
  285. //
  286. ASSERT(pc->pc_firewall2);
  287. IPFreeBuff(pc->pc_firewall2);
  288. pc->pc_firewall2 = NULL;
  289. } else { // bufref != NULL
  290. // Firewall Headers are restored in IPSendComplete
  291. // or in completion path that is executed when
  292. // bufrefcnt is zero.
  293. // These paths have already captured pc_firewall pointer.
  294. // Initialize the packetcontext after calling RestoreUserBuffer
  295. // below.
  296. InitFirewallContext = TRUE;
  297. }
  298. }
  299. // If users header is used as IP header, restore it.
  300. if (FixHdrs && pc->pc_hdrincl) {
  301. RestoreUserBuffer(Packet);
  302. }
  303. if (InitFirewallContext) {
  304. pc->pc_firewall = NULL;
  305. pc->pc_firewall2 = NULL;
  306. }
  307. // If there's no IP header on this packet, we have nothing else to do.
  308. if (!(pc->pc_common.pc_flags & (PACKET_FLAG_IPHDR | PACKET_FLAG_FW))) {
  309. pc->pc_firewall = NULL;
  310. pc->pc_firewall2 = NULL;
  311. NdisFreePacket(Packet);
  312. return NextBuffer;
  313. }
  314. pc->pc_common.pc_flags &= ~PACKET_FLAG_IPHDR;
  315. OldBuffer = NextBuffer;
  316. ASSERT(OldBuffer != NULL);
  317. NextBuffer = NDIS_BUFFER_LINKAGE(NextBuffer);
  318. if (pc->pc_common.pc_flags & PACKET_FLAG_OPTIONS) {
  319. // Have options with this packet.
  320. PNDIS_BUFFER OptBuffer;
  321. void *Options;
  322. uint OptSize;
  323. OptBuffer = NextBuffer;
  324. ASSERT(OptBuffer != NULL);
  325. NdisGetNextBuffer(OptBuffer, &NextBuffer);
  326. ASSERT(NextBuffer != NULL);
  327. TcpipQueryBuffer(OptBuffer, &Options, &OptSize, HighPagePriority);
  328. // If this is a FW packet, the options don't really belong to us, so
  329. // don't free them.
  330. if (!(pc->pc_common.pc_flags & PACKET_FLAG_FW)) {
  331. if (Options != NULL) {
  332. CTEFreeMem(Options);
  333. }
  334. // Else leak Options b/c we can't get virtual address.
  335. }
  336. NdisFreeBuffer(OptBuffer);
  337. pc->pc_common.pc_flags &= ~PACKET_FLAG_OPTIONS;
  338. }
  339. if (pc->pc_common.pc_flags & PACKET_FLAG_IPBUF) { // This packet is all
  340. // IP buffers.
  341. (void)FreeIPBufferChain(NextBuffer);
  342. NextBuffer = (PNDIS_BUFFER) NULL;
  343. pc->pc_common.pc_flags &= ~PACKET_FLAG_IPBUF;
  344. }
  345. if (!(pc->pc_common.pc_flags & PACKET_FLAG_FW)) {
  346. FreeIPHdrBuffer(OldBuffer);
  347. pc->pc_firewall = NULL;
  348. pc->pc_firewall2 = NULL;
  349. NdisFreePacket(Packet);
  350. }
  351. return NextBuffer;
  352. }
  353. //** AllocIPPacketList - Allocate the packet pool
  354. //
  355. // Called during initialization to allocate the packet pool
  356. //
  357. // Input: Nothing.
  358. //
  359. // Returns: TRUE if it succeeds, FALSE otherwise
  360. //
  361. BOOLEAN
  362. AllocIPPacketList(void)
  363. {
  364. PacketContext * pc;
  365. NDIS_STATUS Status;
  366. //
  367. // Determine the size of the machine and allocate the packet pool accordingly
  368. //
  369. #if MILLEN
  370. PacketPoolSizeMax = SMALL_POOL;
  371. #else // MILLEN
  372. switch (MmQuerySystemSize()) {
  373. case MmSmallSystem:
  374. PacketPoolSizeMax = SMALL_POOL;
  375. break;
  376. case MmMediumSystem:
  377. PacketPoolSizeMax = MEDIUM_POOL;
  378. break;
  379. case MmLargeSystem:
  380. PacketPoolSizeMax = LARGE_POOL;
  381. break;
  382. }
  383. #endif // !MILLEN
  384. NdisAllocatePacketPoolEx(&Status,
  385. &NdisPacketPool,
  386. PacketPoolSizeMin,
  387. PacketPoolSizeMax-PacketPoolSizeMin,
  388. sizeof(PacketContext));
  389. if (Status == NDIS_STATUS_SUCCESS) {
  390. NdisSetPacketPoolProtocolId(NdisPacketPool, NDIS_PROTOCOL_ID_TCP_IP);
  391. }
  392. return (NdisPacketPool != NULL);
  393. }
  394. //** GetIPPacket - Get an NDIS packet to use.
  395. //
  396. // A routine to allocate an NDIS packet.
  397. //
  398. // Entry: Nothing.
  399. //
  400. // Returns: Pointer to NDIS_PACKET if allocated, or NULL.
  401. //
  402. PNDIS_PACKET
  403. GetIPPacket(void)
  404. {
  405. PNDIS_PACKET Packet;
  406. NDIS_STATUS Status;
  407. NdisAllocatePacket(&Status, &Packet, NdisPacketPool);
  408. if (Packet != NULL) {
  409. PNDIS_PACKET_EXTENSION PktExt;
  410. PacketContext * pc;
  411. PktExt = NDIS_PACKET_EXTENSION_FROM_PACKET(Packet);
  412. PktExt->NdisPacketInfo[TcpIpChecksumPacketInfo] = NULL;
  413. PktExt->NdisPacketInfo[IpSecPacketInfo] = NULL;
  414. PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] = NULL;
  415. PktExt->NdisPacketInfo[ClassificationHandlePacketInfo] = NULL;
  416. NdisClearPacketFlags(Packet, (NDIS_FLAGS_DONT_LOOPBACK | NDIS_FLAGS_LOOPBACK_ONLY));
  417. pc = (PacketContext *)Packet->ProtocolReserved;
  418. pc->pc_if = NULL;
  419. pc->pc_iflink = NULL;
  420. pc->pc_common.pc_flags = 0;
  421. pc->pc_common.pc_owner = PACKET_OWNER_IP;
  422. pc->pc_hdrincl = 0;
  423. }
  424. return Packet;
  425. }
  426. //** GetIPHdrBuffer - Get an IP header buffer.
  427. //
  428. // A routine to allocate an IP header buffer, with an NDIS buffer.
  429. //
  430. // Entry: Nothing.
  431. //
  432. // Returns: Pointer to NDIS_BUFFER if allocated, or NULL.
  433. //
  434. __inline
  435. PNDIS_BUFFER
  436. GetIPHdrBuffer(IPHeader **Header)
  437. {
  438. return MdpAllocate(IpHeaderPool, Header);
  439. }
  440. //** GetIPHeader - Get a header buffer and packet.
  441. //
  442. // Called when we need to get a header buffer and packet. We allocate both,
  443. // and chain them together.
  444. //
  445. // Input: Pointer to where to store packet.
  446. //
  447. // Returns: Pointer to IP header.
  448. //
  449. IPHeader *
  450. GetIPHeader(PNDIS_PACKET *PacketPtr)
  451. {
  452. PNDIS_BUFFER Buffer;
  453. PNDIS_PACKET Packet;
  454. IPHeader *pIph;
  455. Packet = GetIPPacket();
  456. if (Packet != NULL) {
  457. Buffer = GetIPHdrBuffer(&pIph);
  458. if (Buffer != NULL) {
  459. PacketContext *PC = (PacketContext *) Packet->ProtocolReserved;
  460. PC->pc_common.pc_flags |= PACKET_FLAG_IPHDR;
  461. NdisChainBufferAtBack(Packet, Buffer);
  462. *PacketPtr = Packet;
  463. return pIph;
  464. }
  465. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  466. }
  467. return NULL;
  468. }
  469. //** ReferenceBuffer - Reference a buffer.
  470. //
  471. // Called when we need to update the count of a BufferReference strucutre, either
  472. // by a positive or negative value. If the count goes to 0, we'll free the buffer
  473. // reference and return success. Otherwise we'll return pending.
  474. //
  475. // Entry: BR - Pointer to buffer reference.
  476. // Count - Amount to adjust refcount by.
  477. //
  478. // Returns: Success, or pending.
  479. //
  480. int
  481. ReferenceBuffer(BufferReference * BR, int Count)
  482. {
  483. CTELockHandle handle;
  484. int NewCount;
  485. if (BR == NULL) {
  486. return 0;
  487. }
  488. CTEGetLock(&BR->br_lock, &handle);
  489. BR->br_refcount += Count;
  490. NewCount = BR->br_refcount;
  491. CTEFreeLock(&BR->br_lock, handle);
  492. return NewCount;
  493. }
  494. //* IPSendComplete - IP send complete handler.
  495. //
  496. // Called by the link layer when a send completes. We're given a pointer to a
  497. // net structure, as well as the completing send packet and the final status of
  498. // the send.
  499. //
  500. // Entry: Context - Context we gave to the link layer.
  501. // Packet - Completing send packet.
  502. // Status - Final status of send.
  503. //
  504. // Returns: Nothing.
  505. //
  506. void
  507. __stdcall
  508. IPSendComplete(void *Context, PNDIS_PACKET Packet, NDIS_STATUS Status)
  509. {
  510. NetTableEntry *NTE = (NetTableEntry *) Context;
  511. PacketContext *PContext = (PacketContext *) Packet->ProtocolReserved;
  512. void (*xmitdone) (void *, PNDIS_BUFFER, IP_STATUS);
  513. void *UContext; // Upper layer context.
  514. BufferReference *BufRef; // Buffer reference, if any.
  515. PNDIS_BUFFER Buffer;
  516. PNDIS_PACKET_EXTENSION PktExt;
  517. Interface *IF; // The interface on which this completed.
  518. BOOLEAN fIpsec = (PContext->pc_common.pc_IpsecCtx != NULL);
  519. PNDIS_BUFFER PC_firewall;
  520. struct IPRcvBuf *PC_firewall2;
  521. PNDIS_BUFFER PC_hdrincl;
  522. LinkEntry *Link;
  523. IP_STATUS SendStatus;
  524. // Copy useful information from packet.
  525. xmitdone = PContext->pc_pi->pi_xmitdone;
  526. UContext = PContext->pc_context;
  527. BufRef = PContext->pc_br;
  528. PC_firewall = PContext->pc_firewall;
  529. PC_firewall2 = PContext->pc_firewall2;
  530. PC_hdrincl = PContext->pc_hdrincl;
  531. IF = PContext->pc_if;
  532. Link = PContext->pc_iflink;
  533. SendStatus = (Status == NDIS_STATUS_FAILURE) ? IP_GENERAL_FAILURE
  534. : IP_SUCCESS;
  535. PktExt = NDIS_PACKET_EXTENSION_FROM_PACKET(Packet);
  536. if (PtrToUlong(PktExt->NdisPacketInfo[TcpLargeSendPacketInfo])) {
  537. //We are sure that this is tcp.
  538. // get its context and pass on this info.
  539. ((SendCmpltContext *) UContext)->scc_ByteSent =
  540. PtrToUlong(PktExt->NdisPacketInfo[TcpLargeSendPacketInfo]);
  541. }
  542. if (BufRef == (BufferReference *) NULL) {
  543. // If this is a header include packet
  544. // make sure that duped data part is
  545. // freed here.
  546. Buffer = FreeIPPacket(Packet, TRUE, SendStatus);
  547. if (!Buffer) {
  548. //
  549. // if NULL was returned by IPSEC, it is ok since IPSEC
  550. // might have released all the MDLs.
  551. //
  552. if (fIpsec) {
  553. // We're done with the packet now, we may need to dereference
  554. // the interface.
  555. if (Link) {
  556. DerefLink(Link);
  557. }
  558. if (IF) {
  559. DerefIF(IF);
  560. }
  561. return;
  562. } else {
  563. ASSERT(FALSE);
  564. }
  565. }
  566. ASSERT(Buffer);
  567. (*xmitdone) (UContext, Buffer, SendStatus);
  568. } else {
  569. // Check if this is the last refcnt on this buffer.
  570. // Decrement this reference only after all the operations are
  571. // done on this packet.
  572. if (ReferenceBuffer(BufRef, -1) == 0) {
  573. PContext->pc_ipsec_flags |= IPSEC_FLAG_FRAG_DONE;
  574. // Check for header include option on the packet.
  575. // If true, then original buffer needs to be hooked
  576. // back in to the chain freeing the one allocated by us.
  577. // Note that this pc_hdrincl will be true only if the packet
  578. // traversed thru slow path in ipxmit.
  579. FreeIPPacket(Packet, TRUE, SendStatus);
  580. Buffer = BufRef->br_buffer;
  581. if (!Buffer) {
  582. //
  583. // if NULL was returned by IPSEC, it is ok since IPSEC
  584. // might have released all the MDLs.
  585. //
  586. if (fIpsec) {
  587. // We're done with the packet now, we may need to dereference
  588. // the interface.
  589. if (Link) {
  590. DerefLink(Link);
  591. }
  592. if (IF) {
  593. DerefIF(IF);
  594. }
  595. CTEFreeMem(BufRef);
  596. return;
  597. } else {
  598. ASSERT(FALSE);
  599. }
  600. }
  601. ASSERT(Buffer);
  602. if (PC_firewall) {
  603. PNDIS_BUFFER FirewallBuffer;
  604. FirewallBuffer = PC_firewall;
  605. FreeIPBufferChain(Buffer);
  606. Buffer = FirewallBuffer;
  607. ASSERT(PC_firewall2);
  608. IPFreeBuff(PC_firewall2);
  609. if (PC_hdrincl) {
  610. FreeIPPayloadBuffer(Buffer,PC_hdrincl);
  611. }
  612. }
  613. CTEFreeMem(BufRef);
  614. (*xmitdone) (UContext, Buffer, SendStatus);
  615. } else {
  616. // Since there are more outstanding packets using the headers
  617. // in attached to this packet, do not restore them now.
  618. Buffer = FreeIPPacket(Packet, FALSE, SendStatus);
  619. // We're not done with the send yet, so NULL the IF to
  620. // prevent dereferencing it.
  621. IF = NULL;
  622. Link = NULL;
  623. }
  624. }
  625. // We're done with the packet now, we may need to dereference
  626. // the interface.
  627. if (Link != NULL) {
  628. DerefLink(Link);
  629. }
  630. if (IF == NULL) {
  631. return;
  632. } else {
  633. DerefIF(IF);
  634. }
  635. }
  636. #if DBG
  637. ULONG DebugLockdown = 0;
  638. #endif
  639. //** SendIPPacket - Send an IP packet.
  640. //
  641. // Called when we have a filled in IP packet we need to send. Basically, we
  642. // compute the xsum and send the thing.
  643. //
  644. // Entry: IF - Interface to send it on.
  645. // FirstHop - First hop address to send it to.
  646. // Packet - Packet to be sent.
  647. // Buffer - Buffer to be sent.
  648. // Header - Pointer to IP Header of packet.
  649. // Options - Pointer to option buffer.
  650. // OptionLength - Length of options.
  651. //
  652. // Returns: IP_STATUS of attempt to send.
  653. IP_STATUS
  654. SendIPPacket(Interface * IF, IPAddr FirstHop, PNDIS_PACKET Packet,
  655. PNDIS_BUFFER Buffer, IPHeader * Header, uchar * Options,
  656. uint OptionSize, BOOLEAN IPSeced, void *ArpCtxt,
  657. BOOLEAN DontFreePacket)
  658. {
  659. ulong csum;
  660. NDIS_STATUS Status;
  661. IP_STATUS SendStatus;
  662. #if DBG
  663. //
  664. // If DebugLockdown is set to 1, this means no unicast packets with
  665. // protocol other than AH or ESP can be sent out; and we assert if so.
  666. //
  667. if (DebugLockdown) {
  668. USHORT *pPort = NULL;
  669. ULONG Length = 0;
  670. USHORT IsakmpPort = net_short(500);
  671. USHORT KerberosPort = net_short(88);
  672. NdisQueryBuffer(Buffer, &pPort, &Length);
  673. if (pPort &&
  674. Header->iph_protocol != PROTOCOL_AH &&
  675. Header->iph_protocol != PROTOCOL_ESP &&
  676. IPGetAddrType(Header->iph_dest) == DEST_REMOTE) {
  677. //
  678. // We assert here unless this is exempt traffic.
  679. //
  680. ASSERT(Header->iph_protocol == PROTOCOL_RSVP ||
  681. (Header->iph_protocol == PROTOCOL_UDP &&
  682. (pPort[1] == IsakmpPort ||
  683. pPort[0] == KerberosPort ||
  684. pPort[1] == KerberosPort)) ||
  685. (Header->iph_protocol == PROTOCOL_TCP &&
  686. (pPort[0] == KerberosPort ||
  687. pPort[1] == KerberosPort)));
  688. }
  689. }
  690. #endif
  691. ASSERT(IF->if_refcount != 0);
  692. DEBUGMSG(DBG_TRACE && DBG_IP && DBG_TX,
  693. (DTEXT("+SendIPPacket(%x, %x, %x, %x, %x, %x, %x, %X, %X, %x)\n"),
  694. IF, FirstHop, Packet, Buffer, Header, Options, OptionSize, IPSeced,
  695. ArpCtxt, DontFreePacket));
  696. //
  697. // If we IPSECed this buffer, then the packet is ready to go courtesy IPSEC
  698. //
  699. if (!IPSeced) {
  700. csum = xsum(Header, sizeof(IPHeader));
  701. if (Options) { // We have options, oh boy.
  702. PNDIS_BUFFER OptBuffer;
  703. PacketContext *pc = (PacketContext *) Packet->ProtocolReserved;
  704. NdisAllocateBuffer(&Status, &OptBuffer, BufferPool,
  705. Options, OptionSize);
  706. if (Status != NDIS_STATUS_SUCCESS) { // Couldn't get the needed
  707. // option buffer.
  708. CTEFreeMem(Options);
  709. if (!DontFreePacket) {
  710. NdisChainBufferAtBack(Packet, Buffer);
  711. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  712. }
  713. return IP_NO_RESOURCES;
  714. }
  715. pc->pc_common.pc_flags |= PACKET_FLAG_OPTIONS;
  716. NdisChainBufferAtBack(Packet, OptBuffer);
  717. csum += xsum(Options, OptionSize);
  718. csum = (csum >> 16) + (csum & 0xffff);
  719. csum += (csum >> 16);
  720. }
  721. Header->iph_xsum = ~(ushort) csum;
  722. NdisChainBufferAtBack(Packet, Buffer);
  723. } else {
  724. // Make sure that packet tail is pointing to the
  725. // last MDL.
  726. PNDIS_BUFFER tmp = Buffer;
  727. if (tmp) {
  728. while(NDIS_BUFFER_LINKAGE(tmp)) {
  729. tmp = NDIS_BUFFER_LINKAGE(tmp);
  730. }
  731. Packet->Private.Tail = tmp;
  732. }
  733. }
  734. if (CLASSD_ADDR(Header->iph_dest)) {
  735. IF->if_OutMcastPkts++;
  736. IF->if_OutMcastOctets += net_short(Header->iph_length) - sizeof(IPHeader);
  737. }
  738. Status = (*(IF->if_xmit)) (IF->if_lcontext, &Packet, 1, FirstHop,
  739. NULL, ArpCtxt);
  740. if (Status == NDIS_STATUS_PENDING) {
  741. PacketContext *pc = (PacketContext *) Packet->ProtocolReserved;
  742. return IP_PENDING;
  743. }
  744. // Status wasn't pending. Free the packet, and map the status.
  745. if (Status == NDIS_STATUS_SUCCESS)
  746. SendStatus = IP_SUCCESS;
  747. else {
  748. if (Status == NDIS_STATUS_FAILURE)
  749. SendStatus = IP_GENERAL_FAILURE;
  750. else
  751. SendStatus = IP_HW_ERROR;
  752. }
  753. if (!DontFreePacket)
  754. FreeIPPacket(Packet, TRUE, SendStatus);
  755. return SendStatus;
  756. }
  757. //* SendDHCPPacket - Send a broadcast for DHCP.
  758. //
  759. // Called when somebody is sending a broadcast packet with a NULL source
  760. // address. We assume this means they're sending a DHCP packet. We loop
  761. // through the NTE table, and when we find an entry that's not valid we
  762. // send out the interface associated with that entry.
  763. //
  764. // Input: Dest - Destination of packet.
  765. // Packet - Packet to be send.
  766. // Buffer - Buffer chain to be sent.
  767. // Header - Pointer to header buffer being sent.
  768. //
  769. // Return: Status of send attempt.
  770. //
  771. IP_STATUS
  772. SendDHCPPacket(IPAddr Dest, PNDIS_PACKET Packet, PNDIS_BUFFER Buffer,
  773. IPHeader * IPH, void *ArpCtxt)
  774. {
  775. if (DHCPNTE != NULL && (DHCPNTE->nte_flags & NTE_ACTIVE)) {
  776. // The DHCP NTE is currently invalid, and active. Send on that
  777. // interface.
  778. return SendIPPacket(DHCPNTE->nte_if, Dest, Packet, Buffer, IPH, NULL,
  779. 0, (BOOLEAN) (IPSecHandlerPtr != NULL),
  780. ArpCtxt, FALSE);
  781. }
  782. // Didn't find an invalid NTE! Free the resources, and return the failure.
  783. FreeIPPacket(Packet, TRUE, IP_DEST_HOST_UNREACHABLE);
  784. IPSInfo.ipsi_outdiscards++;
  785. return IP_DEST_HOST_UNREACHABLE;
  786. }
  787. //* IPCopyBuffer - Copy an NDIS buffer chain at a specific offset.
  788. //
  789. // This is the IP version of the function NdisCopyBuffer, which didn't
  790. // get done properly in NDIS3. We take in an NDIS buffer chain, an offset,
  791. // and a length, and produce a buffer chain describing that subset of the
  792. // input buffer chain.
  793. //
  794. // This routine is not particularly efficient. Since only IPFragment uses
  795. // it currently, it might be better to just incorporate this functionality
  796. // directly into IPFragment.
  797. //
  798. // Input: OriginalBuffer - Original buffer chain to copy from.
  799. // Offset - Offset from start to dup.
  800. // Length - Length in bytes to dup.
  801. //
  802. // Returns: Pointer to new chain if we can make one, NULL if we can't.
  803. //
  804. PNDIS_BUFFER
  805. IPCopyBuffer(PNDIS_BUFFER OriginalBuffer, uint Offset, uint Length)
  806. {
  807. PNDIS_BUFFER CurrentBuffer; // Pointer to current buffer.
  808. PNDIS_BUFFER *NewBuffer; // Pointer to pointer to current new buffer.
  809. PNDIS_BUFFER FirstBuffer; // First buffer in new chain.
  810. UINT CopyLength; // Length of current copy.
  811. NDIS_STATUS NewStatus; // Status of NdisAllocateBuffer operation.
  812. PVOID pvBuffer;
  813. // First skip over the number of buffers we need to to reach Offset.
  814. CurrentBuffer = OriginalBuffer;
  815. while (Offset >= NdisBufferLength(CurrentBuffer)) {
  816. Offset -= NdisBufferLength(CurrentBuffer);
  817. CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
  818. if (CurrentBuffer == (PNDIS_BUFFER) NULL)
  819. return NULL;
  820. }
  821. // Now CurrentBuffer is the buffer from which we start building the new chain, and
  822. // Offset is the offset into CurrentBuffer from which to start.
  823. FirstBuffer = NULL;
  824. NewBuffer = &FirstBuffer;
  825. do {
  826. CopyLength = MIN(Length, NdisBufferLength(CurrentBuffer) - Offset);
  827. pvBuffer = TcpipBufferVirtualAddress(CurrentBuffer, NormalPagePriority);
  828. if (pvBuffer == NULL) {
  829. break;
  830. }
  831. NdisAllocateBuffer(&NewStatus, NewBuffer, BufferPool,
  832. ((uchar *) pvBuffer) + Offset,
  833. CopyLength);
  834. if (NewStatus != NDIS_STATUS_SUCCESS)
  835. break;
  836. Offset = 0; // No offset from next buffer.
  837. NewBuffer = &(NDIS_BUFFER_LINKAGE(*NewBuffer));
  838. CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
  839. Length -= CopyLength;
  840. } while (Length != 0 && CurrentBuffer != (PNDIS_BUFFER) NULL);
  841. if (Length == 0) { // We succeeded
  842. return FirstBuffer;
  843. } else { // We exited the loop because of an error.
  844. // We need to free any allocated buffers, and return.
  845. CurrentBuffer = FirstBuffer;
  846. while (CurrentBuffer != (PNDIS_BUFFER) NULL) {
  847. PNDIS_BUFFER Temp = CurrentBuffer;
  848. CurrentBuffer = NDIS_BUFFER_LINKAGE(CurrentBuffer);
  849. NdisFreeBuffer(Temp);
  850. }
  851. return NULL;
  852. }
  853. }
  854. //** IPFragment - Fragment and send an IP datagram.
  855. //
  856. // Called when an outgoing datagram is larger than the local MTU, and needs
  857. // to be fragmented. This is a somewhat complicated operation. The caller
  858. // gives us a prebuilt IP header, packet, and options. We use the header and
  859. // packet on the last fragment of the send, as the passed in header already
  860. // has the more fragments bit set correctly for the last fragment.
  861. //
  862. // The basic idea is to figure out the maximum size which we can send as a
  863. // multiple of 8. Then, while we can send a maximum size fragment we'll
  864. // allocate a header, packet, etc. and send it. At the end we'll send the
  865. // final fragment using the provided header and packet.
  866. //
  867. // Entry: DestIF - Outbound interface of datagram.
  868. // MTU - MTU to use in transmitting.
  869. // FirstHop - First (or next) hop for this datagram.
  870. // Packet - Packet to be sent.
  871. // Header - Prebuilt IP header.
  872. // Buffer - Buffer chain for data to be sent.
  873. // DataSize - Size in bytes of data.
  874. // Options - Pointer to option buffer, if any.
  875. // OptionSize - Size in bytes of option buffer.
  876. // SentCount - Pointer to where to return pending send count (may be NULL).
  877. // bDontLoopback - Determines whether NDIS_FLAGS_DONT_LOOPBACK needs
  878. // to be set
  879. //
  880. // Returns: IP_STATUS of send.
  881. //
  882. IP_STATUS
  883. IPFragment(Interface * DestIF, uint MTU, IPAddr FirstHop,
  884. PNDIS_PACKET Packet, IPHeader * Header, PNDIS_BUFFER Buffer, uint DataSize,
  885. uchar * Options, uint OptionSize, int *SentCount, BOOLEAN bDontLoopback, void *ArpCtxt)
  886. {
  887. BufferReference *BR; // Buffer reference we'll use.
  888. PacketContext *PContext = (PacketContext *) Packet->ProtocolReserved;
  889. FWContext *FWC = (FWContext *) Packet->ProtocolReserved;
  890. PacketContext *CurrentContext; // Current Context in use.
  891. uint MaxSend; // Maximum size (in bytes) we can send here.
  892. uint PendingSends = 0; // Counter of how many pending sends we have.
  893. PNDIS_BUFFER CurrentBuffer; // Current buffer to be sent.
  894. PNDIS_PACKET CurrentPacket; // Current packet we're using.
  895. IP_STATUS SendStatus; // Status of send command.
  896. IPHeader *CurrentHeader; // Current header buffer we're using.
  897. ushort Offset = 0; // Current offset into fragmented packet.
  898. ushort StartOffset; // Starting offset of packet.
  899. ushort RealOffset; // Offset of new fragment.
  900. uint FragOptSize = 0; // Size (in bytes) of fragment options.
  901. uchar FragmentOptions[MAX_OPT_SIZE]; // Master copy of options sent for fragments.
  902. uchar Error = FALSE; // Set if we get an error in our main loop.
  903. BOOLEAN NukeFwPktOptions = FALSE;
  904. PNDIS_BUFFER HdrIncl = NULL;
  905. uint FirewallMode = 0;
  906. PNDIS_BUFFER TempBuffer, PC_Firewall;
  907. struct IPRcvBuf *PC_Firewall2;
  908. PNDIS_PACKET LastPacket = NULL;
  909. PIPSEC_SEND_COMPLETE_CONTEXT pIpsecCtx;
  910. BOOLEAN PC_reinject = FALSE;
  911. PVOID PC_context;
  912. void (*xmitdone) (void *, PNDIS_BUFFER, IP_STATUS);
  913. MaxSend = (MTU - OptionSize) & ~7; // Determine max send size.
  914. ASSERT(MaxSend < DataSize);
  915. BR = PContext->pc_br; // Get the buffer reference we'll need.
  916. ASSERT(BR);
  917. FirewallMode = ProcessFirewallQ();
  918. TempBuffer = BR->br_buffer;
  919. PC_Firewall = PContext->pc_firewall;
  920. PC_Firewall2 = PContext->pc_firewall2;
  921. pIpsecCtx = PContext->pc_common.pc_IpsecCtx;
  922. if (pIpsecCtx && (pIpsecCtx->Flags & SCF_FLUSH)) {
  923. PC_reinject = TRUE;
  924. PC_context = PContext->pc_context;
  925. }
  926. HdrIncl = PContext->pc_hdrincl;
  927. xmitdone = PContext->pc_pi->pi_xmitdone;
  928. if (Header->iph_offset & IP_DF_FLAG) { // Don't fragment flag set.
  929. // Error out.
  930. //
  931. // If options are already linked in, dont free them. FreeIPPacket will.
  932. //
  933. if (Options &&
  934. !(PContext->pc_common.pc_flags & PACKET_FLAG_OPTIONS)) {
  935. CTEFreeMem(Options);
  936. }
  937. PContext->pc_ipsec_flags |= (IPSEC_FLAG_FRAG_DONE | IPSEC_FLAG_FLUSH);
  938. FreeIPPacket(Packet, TRUE, IP_PACKET_TOO_BIG);
  939. if (SentCount == (int *)NULL) // No sent count is to be
  940. // returned.
  941. CTEFreeMem(BR);
  942. IPSInfo.ipsi_fragfails++;
  943. return IP_PACKET_TOO_BIG;
  944. }
  945. #if DBG && GPC
  946. if (PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(Packet,
  947. ClassificationHandlePacketInfo))) {
  948. IF_IPDBG(IP_DEBUG_GPC)
  949. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPFrag: Packet %p with CH\n", Packet));
  950. }
  951. #endif
  952. StartOffset = Header->iph_offset & IP_OFFSET_MASK;
  953. StartOffset = net_short(StartOffset) * 8;
  954. // If we have any options, copy the ones that need to be copied, and figure
  955. // out the size of these new copied options.
  956. if (Options != (uchar *) NULL) { // We have options.
  957. uchar *TempOptions = Options;
  958. const uchar *EndOptions = (const uchar *)(Options + OptionSize);
  959. // Copy the options into the fragment options buffer.
  960. NdisFillMemory(FragmentOptions, MAX_OPT_SIZE, IP_OPT_EOL);
  961. while ((TempOptions[IP_OPT_TYPE] != IP_OPT_EOL) &&
  962. (TempOptions < EndOptions)) {
  963. if (TempOptions[IP_OPT_TYPE] & IP_OPT_COPIED) {
  964. // This option needs to be copied.
  965. uint TempOptSize;
  966. TempOptSize = TempOptions[IP_OPT_LENGTH];
  967. RtlCopyMemory(&FragmentOptions[FragOptSize], TempOptions,
  968. TempOptSize);
  969. FragOptSize += TempOptSize;
  970. TempOptions += TempOptSize;
  971. } else {
  972. // A non-copied option, just skip over it.
  973. if (TempOptions[IP_OPT_TYPE] == IP_OPT_NOP)
  974. TempOptions++;
  975. else
  976. TempOptions += TempOptions[IP_OPT_LENGTH];
  977. }
  978. }
  979. // Round the copied size up to a multiple of 4.
  980. FragOptSize = ((FragOptSize & 3) ? ((FragOptSize & ~3) + 4) : FragOptSize);
  981. //Is this from FW path?
  982. if (PContext->pc_common.pc_flags & PACKET_FLAG_FW) {
  983. //Nuke PContext->fc_options after first IpsendPacket
  984. //To prevent double freeing of option buffer
  985. NukeFwPktOptions = TRUE;
  986. }
  987. }
  988. PContext->pc_common.pc_flags |= PACKET_FLAG_IPBUF;
  989. // Now, while we can build maximum size fragments, do so.
  990. do {
  991. PVOID CancelId;
  992. uchar Owner;
  993. if ((CurrentHeader = GetIPHeader(&CurrentPacket)) == (IPHeader *) NULL) {
  994. // Couldn't get a buffer. Break out, since no point in sending others.
  995. SendStatus = IP_NO_RESOURCES;
  996. Error = TRUE;
  997. break;
  998. }
  999. NDIS_PER_PACKET_INFO_FROM_PACKET(CurrentPacket, ClassificationHandlePacketInfo) =
  1000. NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ClassificationHandlePacketInfo);
  1001. #if !MILLEN
  1002. // Set the cancel requestID from parent packet.
  1003. CancelId = NDIS_GET_PACKET_CANCEL_ID(Packet);
  1004. NDIS_SET_PACKET_CANCEL_ID(CurrentPacket, CancelId);
  1005. #endif
  1006. // Copy the buffer into a new one, if we can.
  1007. CurrentBuffer = IPCopyBuffer(Buffer, Offset, MaxSend);
  1008. if (CurrentBuffer == NULL) { // No buffer, free resources and
  1009. // break.
  1010. // header cleanup will be done in error handling
  1011. // routine
  1012. SendStatus = IP_NO_RESOURCES;
  1013. FreeIPPacket(CurrentPacket, FALSE, SendStatus);
  1014. Error = TRUE;
  1015. break;
  1016. }
  1017. //
  1018. // Options for this send are set up when we get here, either from the
  1019. // entry from the loop, or from the allocation below.
  1020. // We have all the pieces we need. Put the packet together and send it.
  1021. //
  1022. CurrentContext = (PacketContext *) CurrentPacket->ProtocolReserved;
  1023. Owner = CurrentContext->pc_common.pc_owner;
  1024. *CurrentContext = *PContext;
  1025. CurrentContext->pc_common.pc_owner = Owner;
  1026. *CurrentHeader = *Header;
  1027. CurrentContext->pc_common.pc_flags &= ~PACKET_FLAG_FW;
  1028. CurrentHeader->iph_verlen = IP_VERSION +
  1029. ((OptionSize + sizeof(IPHeader)) >> 2);
  1030. CurrentHeader->iph_length = net_short(MaxSend + OptionSize + sizeof(IPHeader));
  1031. RealOffset = (StartOffset + Offset) >> 3;
  1032. CurrentHeader->iph_offset = net_short(RealOffset) | IP_MF_FLAG;
  1033. if (bDontLoopback) {
  1034. NdisSetPacketFlags(CurrentPacket,
  1035. NDIS_FLAGS_DONT_LOOPBACK);
  1036. } else {
  1037. if (CurrentHeader->iph_ttl == 0) {
  1038. NdisSetPacketFlags(CurrentPacket, NDIS_FLAGS_LOOPBACK_ONLY);
  1039. }
  1040. }
  1041. // Clear Options flag if we are not sending any options
  1042. if (Options == NULL) {
  1043. CurrentContext->pc_common.pc_flags &= ~PACKET_FLAG_OPTIONS;
  1044. }
  1045. // Do not free the packet in SendIPPacket, as we may need
  1046. // to chain the buffer in case of IP_NO_RESOURCES
  1047. SendStatus = SendIPPacket(DestIF, FirstHop, CurrentPacket,
  1048. CurrentBuffer, CurrentHeader, Options,
  1049. OptionSize, FALSE, ArpCtxt, TRUE);
  1050. if (SendStatus == IP_PENDING) {
  1051. PendingSends++;
  1052. } else {
  1053. if(SendStatus == IP_NO_RESOURCES) {
  1054. // SendIPPacket has not chained the buffer..
  1055. NdisChainBufferAtBack(CurrentPacket, CurrentBuffer);
  1056. }
  1057. FreeIPPacket(CurrentPacket, FALSE, SendStatus);
  1058. }
  1059. IPSInfo.ipsi_fragcreates++;
  1060. Offset += (ushort) MaxSend;
  1061. DataSize -= MaxSend;
  1062. if (NukeFwPktOptions) {
  1063. //This is to avoid double frees of option
  1064. // in IpFreepacket and Freefwpacket.
  1065. FWC->fc_options = (uchar *) NULL;
  1066. FWC->fc_optlength = 0;
  1067. NukeFwPktOptions = FALSE;
  1068. }
  1069. // If we have any fragmented options, set up to use them next time.
  1070. if (FragOptSize) {
  1071. Options = CTEAllocMemN(OptionSize = FragOptSize, 'qiCT');
  1072. if (Options == (uchar *) NULL) { // Can't get an option buffer.
  1073. SendStatus = IP_NO_RESOURCES;
  1074. Error = TRUE;
  1075. break;
  1076. }
  1077. RtlCopyMemory(Options, FragmentOptions, OptionSize);
  1078. } else {
  1079. Options = (uchar *) NULL;
  1080. OptionSize = 0;
  1081. }
  1082. } while (DataSize > MaxSend);
  1083. // Clear Options flag if we are not sending any options
  1084. if (Options == NULL) {
  1085. PContext->pc_common.pc_flags &= ~PACKET_FLAG_OPTIONS;
  1086. }
  1087. //
  1088. // We've sent all of the previous fragments, now send the last one. We
  1089. // already have the packet and header buffer, as well as options if there
  1090. // are any - we need to copy the appropriate data.
  1091. //
  1092. if (!Error) { // Everything went OK above.
  1093. CurrentBuffer = IPCopyBuffer(Buffer, Offset, DataSize);
  1094. if (CurrentBuffer == NULL) { // No buffer, free resources
  1095. //
  1096. // If options are already linked in, dont free them. FreeIPPacket will.
  1097. //
  1098. if (Options &&
  1099. !(PContext->pc_common.pc_flags & PACKET_FLAG_OPTIONS)) {
  1100. CTEFreeMem(Options);
  1101. }
  1102. if (PC_reinject)
  1103. LastPacket = Packet;
  1104. else
  1105. FreeIPPacket(Packet, FALSE, IP_NO_RESOURCES);
  1106. IPSInfo.ipsi_outdiscards++;
  1107. } else { // Everything's OK, send it.
  1108. Header->iph_verlen = IP_VERSION + ((OptionSize + sizeof(IPHeader)) >> 2);
  1109. Header->iph_length = net_short(DataSize + OptionSize + sizeof(IPHeader));
  1110. RealOffset = (StartOffset + Offset) >> 3;
  1111. Header->iph_offset = net_short(RealOffset) | (Header->iph_offset & IP_MF_FLAG);
  1112. if (bDontLoopback) {
  1113. NdisSetPacketFlags(Packet,
  1114. NDIS_FLAGS_DONT_LOOPBACK);
  1115. } else {
  1116. if (Header->iph_ttl == 0) {
  1117. NdisSetPacketFlags(CurrentPacket, NDIS_FLAGS_LOOPBACK_ONLY);
  1118. }
  1119. }
  1120. // Do not free the packet in SendIPPacket, as we may need
  1121. // to chain the buffer in case of IP_NO_RESOURCES
  1122. SendStatus = SendIPPacket(DestIF, FirstHop, Packet,
  1123. CurrentBuffer, Header, Options,
  1124. OptionSize, FALSE, ArpCtxt, TRUE);
  1125. if (SendStatus == IP_PENDING) {
  1126. PendingSends++;
  1127. } else if (PC_reinject) {
  1128. LastPacket = Packet;
  1129. } else {
  1130. if (SendStatus == IP_NO_RESOURCES) {
  1131. // SendIPPacket has not chained the buffer..
  1132. NdisChainBufferAtBack(Packet, CurrentBuffer);
  1133. }
  1134. FreeIPPacket(Packet, FALSE, SendStatus);
  1135. }
  1136. IPSInfo.ipsi_fragcreates++;
  1137. IPSInfo.ipsi_fragoks++;
  1138. }
  1139. } else { // We had some sort of error.
  1140. // Free resources.
  1141. //
  1142. // If options are already linked in, dont free them. FreeIPPacket will.
  1143. //
  1144. if (Options &&
  1145. !(PContext->pc_common.pc_flags & PACKET_FLAG_OPTIONS)) {
  1146. CTEFreeMem(Options);
  1147. }
  1148. if (PC_reinject)
  1149. LastPacket = Packet;
  1150. else
  1151. FreeIPPacket(Packet, FALSE, SendStatus);
  1152. IPSInfo.ipsi_outdiscards++;
  1153. }
  1154. // Now, figure out what error code to return and whether or not we need to
  1155. // free the BufferReference.
  1156. if (SentCount == (int *)NULL) { // No sent count is to be
  1157. // returned.
  1158. if (ReferenceBuffer(BR, PendingSends) == 0) {
  1159. if (PC_reinject) {
  1160. if (LastPacket) {
  1161. PacketContext *pc = (PacketContext *) LastPacket->ProtocolReserved;
  1162. pc->pc_ipsec_flags |= (IPSEC_FLAG_FRAG_DONE | IPSEC_FLAG_FLUSH);
  1163. // This is the last packet that is being freed
  1164. // Fixup ipsec/firewall/hdrincl headers, if any
  1165. FreeIPPacket(LastPacket, TRUE, SendStatus);
  1166. } else if (PendingSends) {
  1167. //
  1168. // IPSEC reinject and last packet is NULL, but we still
  1169. // return success !!!!
  1170. // Also, pendingsends is +ve =>ipsendcomplete already
  1171. // called in same thread somebody has to free IPSEC's buffer
  1172. // freeippacket has been called by ipsendcomplete
  1173. // the only remaining way is calling xmitdone
  1174. // since ipsendcomplete won't have called xmit done as
  1175. // refcount would be -ve
  1176. //
  1177. (*IPSecSendCmpltPtr) (NULL, TempBuffer, pIpsecCtx,
  1178. IP_PACKET_TOO_BIG,
  1179. &TempBuffer);
  1180. (*xmitdone) (PC_context, TempBuffer, IP_SUCCESS);
  1181. }
  1182. } else {
  1183. // Need to undo ipsec, firewall and then
  1184. // header include changes to teh buffer list.
  1185. if (pIpsecCtx) {
  1186. (*IPSecSendCmpltPtr) (NULL, TempBuffer, pIpsecCtx,
  1187. IP_SUCCESS,&TempBuffer);
  1188. }
  1189. // If this is user header include packet,
  1190. // relink the original user buffer if necessary
  1191. if (PC_Firewall) {
  1192. BR->br_buffer = PC_Firewall;
  1193. }
  1194. if (BR->br_userbuffer) {
  1195. FreeIPPayloadBuffer(BR->br_buffer, BR->br_userbuffer);
  1196. }
  1197. }
  1198. CTEFreeMem(BR);
  1199. if (FirewallMode && PC_Firewall) {
  1200. FreeIPBufferChain(TempBuffer); // free the mdl chain
  1201. // allocated in firewall path
  1202. IPFreeBuff(PC_Firewall2); // free the rcvbuf chain
  1203. }
  1204. return IP_SUCCESS;
  1205. }
  1206. //
  1207. // This send is still pending. Call freepacket without setting
  1208. // pc_ipsec flag
  1209. //
  1210. if (LastPacket)
  1211. FreeIPPacket(LastPacket, FALSE, IP_PENDING);
  1212. return IP_PENDING;
  1213. } else
  1214. *SentCount += PendingSends;
  1215. // Just free the packet. Headers will be restored when the last packet completes.
  1216. if (LastPacket)
  1217. FreeIPPacket(LastPacket, FALSE, IP_PENDING);
  1218. return IP_PENDING;
  1219. }
  1220. //* UpdateRouteOption - Update a SR or RR options.
  1221. //
  1222. // Called by UpdateOptions when it needs to update a route option.
  1223. //
  1224. // Input: RTOption - Pointer to route option to be updated.
  1225. // Address - Address to update with.
  1226. //
  1227. // Returns: TRUE if we updated, FALSE if we didn't.
  1228. //
  1229. uchar
  1230. UpdateRouteOption(uchar * RTOption, IPAddr Address)
  1231. {
  1232. uchar Pointer; // Pointer value of option.
  1233. Pointer = RTOption[IP_OPT_PTR] - 1;
  1234. if (Pointer < RTOption[IP_OPT_LENGTH]) {
  1235. if ((RTOption[IP_OPT_LENGTH] - Pointer) < sizeof(IPAddr)) {
  1236. return FALSE;
  1237. }
  1238. *(IPAddr UNALIGNED *) & RTOption[Pointer] = Address;
  1239. RTOption[IP_OPT_PTR] += sizeof(IPAddr);
  1240. }
  1241. return TRUE;
  1242. }
  1243. //* UpdateOptions - Update an options buffer.
  1244. //
  1245. // Called when we need to update an options buffer outgoing. We stamp the indicated
  1246. // options with our local address.
  1247. //
  1248. // Input: Options - Pointer to options buffer to be updated.
  1249. // Index - Pointer to information about which ones to update.
  1250. // Address - Local address with which to update the options.
  1251. //
  1252. // Returns: Index of option causing the error, or MAX_OPT_SIZE if all goes well.
  1253. //
  1254. uchar
  1255. UpdateOptions(uchar * Options, OptIndex * Index, IPAddr Address)
  1256. {
  1257. uchar *LocalOption;
  1258. uchar LocalIndex;
  1259. // If we have both options and an index, update the options.
  1260. if (Options != (uchar *) NULL && Index != (OptIndex *) NULL) {
  1261. //
  1262. // If we have a source route to update, update it. If this
  1263. // fails return the index of the source route.
  1264. //
  1265. LocalIndex = Index->oi_srindex;
  1266. if (LocalIndex != MAX_OPT_SIZE)
  1267. if (!UpdateRouteOption(Options + LocalIndex, Address))
  1268. return LocalIndex;
  1269. // Do the same thing for any record route option.
  1270. LocalIndex = Index->oi_rrindex;
  1271. if (LocalIndex != MAX_OPT_SIZE)
  1272. if (!UpdateRouteOption(Options + LocalIndex, Address))
  1273. return LocalIndex;
  1274. // Now handle timestamp.
  1275. if ((LocalIndex = Index->oi_tsindex) != MAX_OPT_SIZE) {
  1276. uchar Flags, Length, Pointer;
  1277. LocalOption = Options + LocalIndex;
  1278. Pointer = LocalOption[IP_OPT_PTR] - 1;
  1279. Flags = LocalOption[IP_TS_OVFLAGS] & IP_TS_FLMASK;
  1280. // If we have room in the option, update it.
  1281. if (Pointer < (Length = LocalOption[IP_OPT_LENGTH])) {
  1282. ulong Now;
  1283. ulong UNALIGNED *TSPtr;
  1284. //
  1285. // Get the current time as milliseconds from midnight GMT,
  1286. // mod the number of milliseconds in 24 hours.
  1287. //
  1288. Now = ((TimeStamp + CTESystemUpTime()) | TSFlag) % (24 * 3600 * 1000);
  1289. Now = net_long(Now);
  1290. TSPtr = (ulong UNALIGNED *) & LocalOption[Pointer];
  1291. switch (Flags) {
  1292. //
  1293. // Just record the TS. If there is some room but not
  1294. // enough for an IP
  1295. // address we have an error.
  1296. //
  1297. case TS_REC_TS:
  1298. if ((Length - Pointer) < sizeof(IPAddr))
  1299. return LocalIndex; // Error - not enough room.
  1300. *TSPtr = Now;
  1301. LocalOption[IP_OPT_PTR] += sizeof(ulong);
  1302. break;
  1303. // Record only matching addresses.
  1304. case TS_REC_SPEC:
  1305. //
  1306. // If we're not the specified address, break out, else
  1307. // fall through to the record address case.
  1308. //
  1309. if (*(IPAddr UNALIGNED *) TSPtr != Address)
  1310. break;
  1311. //
  1312. // Record an address and timestamp pair. If there is some
  1313. // room but not enough for the address/timestamp pait, we
  1314. // have an error, so bail out.
  1315. //
  1316. case TS_REC_ADDR:
  1317. if ((Length - Pointer) < (sizeof(IPAddr) + sizeof(ulong)))
  1318. return LocalIndex; // Not enough room.
  1319. *(IPAddr UNALIGNED *) TSPtr = Address; // Store the address.
  1320. TSPtr++; // Update to where to put TS.
  1321. *TSPtr = Now; // Store TS
  1322. LocalOption[IP_OPT_PTR] += (sizeof(ulong) + sizeof(IPAddr));
  1323. break;
  1324. default: // Unknown flag type. Just ignore it.
  1325. break;
  1326. }
  1327. } else { // Have overflow.
  1328. //
  1329. // We have an overflow. If the overflow field isn't maxed,
  1330. // increment it. If it is maxed we have an error.
  1331. //
  1332. if ((LocalOption[IP_TS_OVFLAGS] & IP_TS_OVMASK) != IP_TS_MAXOV)
  1333. // This is not maxed, so increment it.
  1334. LocalOption[IP_TS_OVFLAGS] += IP_TS_INC;
  1335. else
  1336. return LocalIndex; // Would have overflowed.
  1337. }
  1338. }
  1339. }
  1340. return MAX_OPT_SIZE;
  1341. }
  1342. typedef struct {
  1343. IPAddr bsl_addr;
  1344. Interface *bsl_if;
  1345. uint bsl_mtu;
  1346. ushort bsl_flags;
  1347. ushort bsl_if_refs;
  1348. } BCastSendList;
  1349. VOID
  1350. FreeBCastSendList(BCastSendList * SendList, uint SendListSize)
  1351. {
  1352. uint i;
  1353. CTELockHandle LockHandle;
  1354. CTEGetLock(&RouteTableLock.Lock, &LockHandle);
  1355. for (i = 0; i < SendListSize / sizeof(BCastSendList); i++) {
  1356. if (SendList[i].bsl_if) {
  1357. LockedDerefIF(SendList[i].bsl_if);
  1358. }
  1359. }
  1360. CTEFreeLock(&RouteTableLock.Lock, LockHandle);
  1361. CTEFreeMem(SendList);
  1362. }
  1363. //** SendIPBcast - Send a local BCast IP packet.
  1364. //
  1365. // This routine is called when we need to send a bcast packet. This may
  1366. // involve sending on multiple interfaces. We figure out which interfaces
  1367. // to send on, then loop through sending on them.
  1368. //
  1369. // Some care is needed to avoid sending the packet onto the same physical media
  1370. // multiple times. What we do is loop through the NTE table, deciding in we
  1371. // should send on the interface. As we go through we build up a list of
  1372. // interfaces to send on. Then we loop through this list, sending on each
  1373. // interface. This is a little cumbersome, but allows us to localize the
  1374. // decision on where to send datagrams into one spot. If SendOnSource is FALSE
  1375. // coming in we assume we've already sent on the specified source NTE and
  1376. // initialize data structures accordingly. This feature is used in routing
  1377. // datagrams.
  1378. //
  1379. // Entry: SrcNTE - NTE for source of send (unused if SendOnSource == TRUE).
  1380. // Destination - Destination address
  1381. // Packet - Prebuilt packet to broadcast.
  1382. // IPH - Pointer to header buffer
  1383. // Buffer - Buffer of data to be sent.
  1384. // DataSize - Size of data to be sent.
  1385. // Options - Pointer to options buffer.
  1386. // OptionSize - Size in bytes of options.
  1387. // SendOnSource - Indicator of whether or not this should be sent on the source net.
  1388. // Index - Pointer to opt index array; may be NULL;
  1389. //
  1390. // Returns: Status of attempt to send.
  1391. //
  1392. IP_STATUS
  1393. SendIPBCast(NetTableEntry * SrcNTE, IPAddr Destination, PNDIS_PACKET Packet,
  1394. IPHeader * IPH, PNDIS_BUFFER Buffer, uint DataSize, uchar * Options,
  1395. uint OptionSize, uchar SendOnSource, OptIndex * Index)
  1396. {
  1397. BufferReference *BR; // Buffer reference to use for this
  1398. // buffer.
  1399. PacketContext *PContext = (PacketContext *) Packet->ProtocolReserved;
  1400. NetTableEntry *TempNTE;
  1401. uint i, j;
  1402. uint NeedFragment; // TRUE if we think we'll need to
  1403. // fragment.
  1404. int Sent = 0; // Count of how many we've sent.
  1405. IP_STATUS Status;
  1406. uchar *NewOptions; // Options we'll use on each send.
  1407. IPHeader *NewHeader;
  1408. PNDIS_BUFFER NewUserBuffer;
  1409. PNDIS_PACKET NewPacket;
  1410. BCastSendList *SendList;
  1411. uint NetsToSend;
  1412. IPAddr SrcAddr;
  1413. Interface *SrcIF;
  1414. IPHeader *Temp = NULL;
  1415. FORWARD_ACTION Action;
  1416. PNDIS_BUFFER TempBuffer, PC_Firewall;
  1417. struct IPRcvBuf *PC_Firewall2;
  1418. PIPSEC_SEND_COMPLETE_CONTEXT pIpsecCtx;
  1419. BOOLEAN PC_reinject = FALSE;
  1420. PVOID PC_context;
  1421. void (*xmitdone) (void *, PNDIS_BUFFER, IP_STATUS);
  1422. uint mtu;
  1423. uchar *NewOptions2; // Options we'll use on each send.
  1424. IPHeader *NewHeader2;
  1425. PNDIS_BUFFER NewUserBuffer2;
  1426. PNDIS_PACKET NewPacket2;
  1427. CTELockHandle LockHandle;
  1428. uint SendListSize = sizeof(BCastSendList) * NumNTE;
  1429. uint k;
  1430. NetTableEntry *NetTableList;
  1431. PVOID pvBuffer;
  1432. SendList = CTEAllocMemN(SendListSize, 'riCT');
  1433. if (SendList == NULL) {
  1434. if (PContext->pc_hdrincl) {
  1435. NdisChainBufferAtBack(Packet,Buffer);
  1436. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  1437. }
  1438. return IP_NO_RESOURCES;
  1439. }
  1440. RtlZeroMemory(SendList, SendListSize);
  1441. // If SendOnSource, initalize SrcAddr and SrcIF to be non-matching.
  1442. // Otherwise initialize them to the masked source address and source
  1443. // interface.
  1444. if (SendOnSource != DisableSendOnSource) {
  1445. SrcAddr = NULL_IP_ADDR;
  1446. SrcIF = NULL;
  1447. } else {
  1448. ASSERT(SrcNTE != NULL);
  1449. SrcAddr = (SrcNTE->nte_addr & SrcNTE->nte_mask);
  1450. SrcIF = SrcNTE->nte_if;
  1451. }
  1452. CTEGetLock(&RouteTableLock.Lock, &LockHandle);
  1453. NeedFragment = FALSE;
  1454. // Loop through the NTE table, making a list of interfaces and
  1455. // corresponding addresses to send on.
  1456. NetsToSend = 0;
  1457. for (k = 0; k < NET_TABLE_SIZE; k++) {
  1458. for (TempNTE = NewNetTableList[k]; TempNTE != NULL; TempNTE = TempNTE->nte_next) {
  1459. IPAddr TempAddr;
  1460. // Don't send through invalid or the loopback NTE.
  1461. if (!(TempNTE->nte_flags & NTE_VALID) || TempNTE == LoopNTE)
  1462. continue;
  1463. // If the broadcast-mode is source-only, skip all NTEs
  1464. // other than the source-NTE.
  1465. if (SendOnSource == OnlySendOnSource &&
  1466. !IP_ADDR_EQUAL(TempNTE->nte_addr, IPH->iph_src))
  1467. continue;
  1468. TempAddr = TempNTE->nte_addr & TempNTE->nte_mask;
  1469. // If he matches the source address or SrcIF, skip him.
  1470. if (IP_ADDR_EQUAL(TempAddr, SrcAddr) || TempNTE->nte_if == SrcIF)
  1471. continue;
  1472. // If the destination isn't a broadcast on this NTE, skip him.
  1473. if (!IS_BCAST_DEST(IsBCastOnNTE(Destination, TempNTE)))
  1474. continue;
  1475. // if this NTE is P2P then always add him to bcast list.
  1476. if ((TempNTE->nte_if)->if_flags & IF_FLAGS_P2P) {
  1477. j = NetsToSend;
  1478. } else {
  1479. //
  1480. // Go through the list we've already build, looking for a match.
  1481. //
  1482. for (j = 0; j < NetsToSend; j++) {
  1483. //
  1484. // if P2P NTE then skip it - we want to send bcasts to all
  1485. // P2P interfaces in addition to 1 non P2P interface even
  1486. // if they are on the same subnet.
  1487. //
  1488. if ((SendList[j].bsl_if)->if_flags & IF_FLAGS_P2P)
  1489. continue;
  1490. if ((SendList[j].bsl_if)->if_flags & IF_FLAGS_P2MP)
  1491. continue;
  1492. if (IP_ADDR_EQUAL(SendList[j].bsl_addr & TempNTE->nte_mask, TempAddr)
  1493. || SendList[j].bsl_if == TempNTE->nte_if) {
  1494. // He matches this send list element. Shrink the MSS if
  1495. // we need to, and then break out.
  1496. SendList[j].bsl_mtu = MIN(SendList[j].bsl_mtu, TempNTE->nte_mss);
  1497. if ((DataSize + OptionSize) > SendList[j].bsl_mtu)
  1498. NeedFragment = TRUE;
  1499. break;
  1500. }
  1501. }
  1502. }
  1503. if (j == NetsToSend) {
  1504. // This is a new one. Fill him in, and bump NetsToSend.
  1505. SendList[j].bsl_addr = TempNTE->nte_addr;
  1506. SendList[j].bsl_if = TempNTE->nte_if;
  1507. SendList[j].bsl_mtu = TempNTE->nte_mss;
  1508. SendList[j].bsl_flags = TempNTE->nte_flags;
  1509. SendList[j].bsl_if_refs++;
  1510. ASSERT(SendList[j].bsl_if_refs <= 1);
  1511. LOCKED_REFERENCE_IF(TempNTE->nte_if);
  1512. if ((DataSize + OptionSize) > SendList[j].bsl_mtu)
  1513. NeedFragment = TRUE;
  1514. NetsToSend++;
  1515. }
  1516. }
  1517. }
  1518. CTEFreeLock(&RouteTableLock.Lock, LockHandle);
  1519. if (NetsToSend == 0) {
  1520. CTEFreeMem(SendList);
  1521. if (PContext->pc_hdrincl) {
  1522. NdisChainBufferAtBack(Packet,Buffer);
  1523. FreeIPPacket(Packet, TRUE, IP_SUCCESS);
  1524. }
  1525. return IP_SUCCESS; // Nothing to send on.
  1526. }
  1527. // OK, we've got the list. If we've got more than one interface to send
  1528. // on or we need to fragment, get a BufferReference.
  1529. if (NetsToSend > 1 || NeedFragment) {
  1530. if ((BR = CTEAllocMemN(sizeof(BufferReference), 'siCT')) ==
  1531. (BufferReference *) NULL) {
  1532. FreeBCastSendList(SendList, SendListSize);
  1533. if (PContext->pc_hdrincl) {
  1534. NdisChainBufferAtBack(Packet,Buffer);
  1535. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  1536. }
  1537. return IP_NO_RESOURCES;
  1538. }
  1539. BR->br_buffer = Buffer;
  1540. BR->br_refcount = 0;
  1541. CTEInitLock(&BR->br_lock);
  1542. PContext->pc_br = BR;
  1543. BR->br_userbuffer = PContext->pc_hdrincl;
  1544. TempBuffer = BR->br_buffer;
  1545. PC_Firewall = PContext->pc_firewall;
  1546. PC_Firewall2 = PContext->pc_firewall2;
  1547. pIpsecCtx = PContext->pc_common.pc_IpsecCtx;
  1548. if (pIpsecCtx && (pIpsecCtx->Flags & SCF_FLUSH)) {
  1549. PC_reinject = TRUE;
  1550. PC_context = PContext->pc_context;
  1551. }
  1552. xmitdone = PContext->pc_pi->pi_xmitdone;
  1553. } else {
  1554. BR = NULL;
  1555. PContext->pc_br = NULL;
  1556. }
  1557. //
  1558. // We need to pass up the options and IP hdr in a contiguous buffer.
  1559. // Allocate the buffer once and re-use later.
  1560. //
  1561. if (ForwardFilterEnabled) {
  1562. if (Options == NULL) {
  1563. #if FWD_DBG
  1564. DbgPrint("Options==NULL\n");
  1565. #endif
  1566. Temp = IPH;
  1567. } else {
  1568. Temp = CTEAllocMemN(sizeof(IPHeader) + OptionSize, 'tiCT');
  1569. if (Temp == NULL) {
  1570. FreeBCastSendList(SendList, SendListSize);
  1571. if (PContext->pc_hdrincl) {
  1572. NdisChainBufferAtBack(Packet,Buffer);
  1573. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  1574. }
  1575. return IP_NO_RESOURCES;
  1576. }
  1577. *Temp = *IPH;
  1578. #if FWD_DBG
  1579. DbgPrint("Options!=NULL : alloced temp @ %lx\n", Temp);
  1580. #endif
  1581. //
  1582. // done later...
  1583. // RtlCopyMemory((uchar *)(Temp + 1), Options, OptionSize);
  1584. }
  1585. }
  1586. // Now, loop through the list. For each entry, send.
  1587. // Header fixup is needed in FreeIPPacket called within this loop
  1588. // If number of nets is one
  1589. for (i = 0; i < NetsToSend; i++) {
  1590. //
  1591. // For all nets except the last one we're going to send on we need
  1592. // to make a copy of the header, packet, buffers, and any options.
  1593. // On the last net we'll use the user provided information.
  1594. //
  1595. if (i != (NetsToSend - 1)) {
  1596. PVOID CancelId;
  1597. if ((NewHeader = GetIPHeader(&NewPacket)) == (IPHeader *) NULL) {
  1598. IPSInfo.ipsi_outdiscards++;
  1599. continue; // Couldn't get a header, skip this send.
  1600. }
  1601. NewUserBuffer = IPCopyBuffer(Buffer, 0, DataSize);
  1602. if (NewUserBuffer == NULL) {
  1603. // Couldn't get user buffer copied.
  1604. FreeIPPacket(NewPacket, FALSE, IP_NO_RESOURCES);
  1605. IPSInfo.ipsi_outdiscards++;
  1606. continue;
  1607. }
  1608. *(PacketContext *) NewPacket->ProtocolReserved = *PContext;
  1609. *NewHeader = *IPH;
  1610. (*(PacketContext *) NewPacket->ProtocolReserved).pc_common.pc_flags |= PACKET_FLAG_IPBUF;
  1611. (*(PacketContext *) NewPacket->ProtocolReserved).pc_common.pc_flags &= ~PACKET_FLAG_FW;
  1612. if (Options) {
  1613. // We have options, make a copy.
  1614. if ((NewOptions = CTEAllocMemN(OptionSize, 'uiCT')) == (uchar *) NULL) {
  1615. FreeIPBufferChain(NewUserBuffer);
  1616. FreeIPPacket(NewPacket, FALSE, IP_NO_RESOURCES);
  1617. IPSInfo.ipsi_outdiscards++;
  1618. continue;
  1619. }
  1620. RtlCopyMemory(NewOptions, Options, OptionSize);
  1621. } else {
  1622. NewOptions = NULL;
  1623. }
  1624. #if !MILLEN
  1625. // Set the cancel requestID from parent packet.
  1626. CancelId = NDIS_GET_PACKET_CANCEL_ID(Packet);
  1627. NDIS_SET_PACKET_CANCEL_ID(NewPacket, CancelId);
  1628. #endif
  1629. } else {
  1630. NewHeader = IPH;
  1631. NewPacket = Packet;
  1632. NewOptions = Options;
  1633. NewUserBuffer = Buffer;
  1634. }
  1635. UpdateOptions(NewOptions, Index, SendList[i].bsl_addr);
  1636. // See if we need to filter this packet. If we
  1637. // do, call the filter routine to see if it's
  1638. // OK to send it.
  1639. if (ForwardFilterEnabled) {
  1640. //
  1641. // Copy over the options.
  1642. //
  1643. if (NewOptions) {
  1644. RtlCopyMemory((uchar *) (Temp + 1), NewOptions, OptionSize);
  1645. }
  1646. pvBuffer = TcpipBufferVirtualAddress(NewUserBuffer, NormalPagePriority);
  1647. if (pvBuffer == NULL) {
  1648. if (i != (NetsToSend - 1)) {
  1649. FreeIPBufferChain(NewUserBuffer);
  1650. IPSInfo.ipsi_outdiscards++;
  1651. if (NewOptions) {
  1652. CTEFreeMem(NewOptions);
  1653. }
  1654. }
  1655. FreeIPPacket(NewPacket, FALSE, IP_GENERAL_FAILURE);
  1656. continue;
  1657. }
  1658. if ((SendList[i].bsl_if)->if_flags & IF_FLAGS_P2MP) {
  1659. if ((SendList[i].bsl_if)->if_flags & IF_FLAGS_NOLINKBCST) {
  1660. // what filtercontext to use ?
  1661. #if FWD_DBG
  1662. DbgPrint("ForwardFilterPtr not called for IF %lx since IF_FLAGS_NOLINKBCST not set\n", SendList[i].bsl_if);
  1663. #endif
  1664. Action = FORWARD;
  1665. } else {
  1666. //scan all the links on this interface and deliver them to the forwardfilter
  1667. Interface *IF = SendList[i].bsl_if;
  1668. LinkEntry *tmpLink = IF->if_link;
  1669. // ASSERT(tmpLink);
  1670. while (tmpLink) {
  1671. tmpLink->link_Action = FORWARD;
  1672. CTEInterlockedIncrementLong(&ForwardFilterRefCount);
  1673. Action = (*ForwardFilterPtr) (Temp,
  1674. pvBuffer,
  1675. NdisBufferLength(NewUserBuffer),
  1676. INVALID_IF_INDEX,
  1677. IF->if_index,
  1678. NULL_IP_ADDR,
  1679. tmpLink->link_NextHop);
  1680. DerefFilterPtr();
  1681. tmpLink->link_Action = Action;
  1682. tmpLink = tmpLink->link_next;
  1683. }
  1684. }
  1685. } else {
  1686. CTEInterlockedIncrementLong(&ForwardFilterRefCount);
  1687. Action = (*ForwardFilterPtr) (Temp,
  1688. pvBuffer,
  1689. NdisBufferLength(NewUserBuffer),
  1690. INVALID_IF_INDEX,
  1691. SendList[i].bsl_if->if_index,
  1692. NULL_IP_ADDR, NULL_IP_ADDR);
  1693. DerefFilterPtr();
  1694. }
  1695. #if FWD_DBG
  1696. DbgPrint("ForwardFilterPtr: %lx, FORWARD is %lx\n", Action, FORWARD);
  1697. #endif
  1698. if (!(SendList[i].bsl_if->if_flags & IF_FLAGS_P2MP) ||
  1699. (SendList[i].bsl_if->if_flags & IF_FLAGS_P2MP) &&
  1700. (SendList[i].bsl_if->if_flags & IF_FLAGS_NOLINKBCST)) {
  1701. if (Action != FORWARD) {
  1702. if (i != (NetsToSend - 1)) {
  1703. FreeIPBufferChain(NewUserBuffer);
  1704. if (NewOptions) {
  1705. CTEFreeMem(NewOptions);
  1706. }
  1707. }
  1708. FreeIPPacket(NewPacket, FALSE, IP_GENERAL_FAILURE);
  1709. continue;
  1710. }
  1711. }
  1712. }
  1713. if ((SendList[i].bsl_if->if_flags & IF_FLAGS_P2MP) &&
  1714. (SendList[i].bsl_if->if_flags & IF_FLAGS_NOLINKBCST)) {
  1715. //Determine the minimum MTU
  1716. Interface *tmpIF = SendList[i].bsl_if;
  1717. LinkEntry *tmpLink = tmpIF->if_link;
  1718. // int mtu;
  1719. if (!tmpLink) {
  1720. if (i != (NetsToSend - 1)) {
  1721. FreeIPBufferChain(NewUserBuffer);
  1722. if (NewOptions) {
  1723. CTEFreeMem(NewOptions);
  1724. }
  1725. }
  1726. FreeIPPacket(NewPacket, FALSE, IP_GENERAL_FAILURE);
  1727. continue;
  1728. }
  1729. ASSERT(tmpLink);
  1730. mtu = tmpLink->link_mtu;
  1731. while (tmpLink) {
  1732. if (tmpLink->link_mtu < mtu)
  1733. mtu = tmpLink->link_mtu;
  1734. tmpLink = tmpLink->link_next;
  1735. }
  1736. if ((DataSize + OptionSize) > mtu) { // This is too big
  1737. //
  1738. // Don't need to update Sent when fragmenting, as IPFragment
  1739. // will update the br_refcount field itself. It will also free
  1740. // the option buffer.
  1741. //
  1742. Status = IPFragment(SendList[i].bsl_if, mtu,
  1743. Destination, NewPacket, NewHeader,
  1744. NewUserBuffer, DataSize, NewOptions,
  1745. OptionSize, &Sent, FALSE, NULL);
  1746. //
  1747. // IPFragment is done with the descriptor chain, so if this is
  1748. // a locally allocated chain free it now.
  1749. //
  1750. if (i != (NetsToSend - 1))
  1751. FreeIPBufferChain(NewUserBuffer);
  1752. } else {
  1753. NewHeader->iph_xsum = 0;
  1754. // Do not free the packet in SendIPPacket, as we may need
  1755. // to chain the buffer in case of IP_NO_RESOURCES
  1756. Status = SendIPPacket(SendList[i].bsl_if, Destination,
  1757. NewPacket, NewUserBuffer, NewHeader,
  1758. NewOptions, OptionSize, FALSE, NULL, TRUE);
  1759. if (Status == IP_PENDING) {
  1760. Sent++;
  1761. } else {
  1762. if (Status == IP_NO_RESOURCES) {
  1763. // SendIPPacket has not chained the buffer..
  1764. NdisChainBufferAtBack(NewPacket, NewUserBuffer);
  1765. }
  1766. if (NetsToSend == 1) {
  1767. FreeIPPacket(NewPacket, TRUE, Status);
  1768. } else {
  1769. FreeIPPacket(NewPacket, FALSE, Status);
  1770. }
  1771. }
  1772. }
  1773. } else if (SendList[i].bsl_if->if_flags & IF_FLAGS_P2MP) {
  1774. // broadcast on all the links
  1775. Interface *tmpIF = SendList[i].bsl_if;
  1776. LinkEntry *tmpLink = tmpIF->if_link;
  1777. ASSERT(!(SendList[i].bsl_if->if_flags & IF_FLAGS_NOLINKBCST));
  1778. if (!tmpLink) {
  1779. if (i != (NetsToSend - 1)) {
  1780. FreeIPBufferChain(NewUserBuffer);
  1781. if (NewOptions) {
  1782. CTEFreeMem(NewOptions);
  1783. }
  1784. }
  1785. FreeIPPacket(NewPacket, FALSE, IP_GENERAL_FAILURE);
  1786. continue;
  1787. }
  1788. ASSERT(tmpLink);
  1789. while (tmpLink) {
  1790. //
  1791. //Go thru the send motion for all the links
  1792. //Passing the link context and checking whether it was
  1793. //forward for that link. For all link except the last one
  1794. //we're going to send on we need to make a copy of the header,
  1795. //packet, buffers, and any options.
  1796. // On the last net we'll use the user provided information.
  1797. //
  1798. if (tmpLink->link_next) {
  1799. if ((NewHeader2 = GetIPHeader(&NewPacket2)) == (IPHeader *) NULL) {
  1800. IPSInfo.ipsi_outdiscards++;
  1801. // free the packet etc. we made for the interface
  1802. if (i != (NetsToSend - 1)) {
  1803. FreeIPBufferChain(NewUserBuffer);
  1804. if (NewOptions) {
  1805. CTEFreeMem(NewOptions);
  1806. }
  1807. }
  1808. FreeIPPacket(NewPacket, FALSE, IP_NO_RESOURCES);
  1809. continue; // Couldn't get a header, skip this send.
  1810. }
  1811. NewUserBuffer2 = IPCopyBuffer(Buffer, 0, DataSize);
  1812. if (NewUserBuffer2 == NULL) {
  1813. // Couldn't get user buffer copied.
  1814. FreeIPPacket(NewPacket2, FALSE, IP_NO_RESOURCES);
  1815. IPSInfo.ipsi_outdiscards++;
  1816. if (i != (NetsToSend - 1)) {
  1817. FreeIPBufferChain(NewUserBuffer);
  1818. if (NewOptions) {
  1819. CTEFreeMem(NewOptions);
  1820. }
  1821. }
  1822. continue;
  1823. }
  1824. *(PacketContext *) NewPacket2->ProtocolReserved = *PContext;
  1825. *NewHeader2 = *IPH;
  1826. (*(PacketContext *) NewPacket2->ProtocolReserved).pc_common.pc_flags |= PACKET_FLAG_IPBUF;
  1827. (*(PacketContext *) NewPacket2->ProtocolReserved).pc_common.pc_flags &= ~PACKET_FLAG_FW;
  1828. if (Options) {
  1829. // We have options, make a copy.
  1830. if ((NewOptions2 = CTEAllocMemN(OptionSize, 'viCT')) == (uchar *) NULL) {
  1831. FreeIPBufferChain(NewUserBuffer2);
  1832. FreeIPPacket(NewPacket2, FALSE, IP_NO_RESOURCES);
  1833. IPSInfo.ipsi_outdiscards++;
  1834. if (i != (NetsToSend - 1)) {
  1835. FreeIPBufferChain(NewUserBuffer);
  1836. if (NewOptions) {
  1837. CTEFreeMem(NewOptions);
  1838. }
  1839. }
  1840. continue;
  1841. }
  1842. RtlCopyMemory(NewOptions2, Options, OptionSize);
  1843. } else {
  1844. NewOptions2 = NULL;
  1845. }
  1846. } else { // last link
  1847. NewHeader2 = NewHeader;
  1848. NewPacket2 = NewPacket;
  1849. NewOptions2 = NewOptions;
  1850. NewUserBuffer2 = NewUserBuffer;
  1851. }
  1852. UpdateOptions(NewOptions2, Index, SendList[i].bsl_addr);
  1853. if (tmpLink->link_Action) {
  1854. if ((DataSize + OptionSize) > tmpLink->link_mtu) {
  1855. //
  1856. // This is too big
  1857. // Don't need to update Sent when fragmenting, as
  1858. // IPFragment will update the br_refcount field itself.
  1859. // It will also free the option buffer.
  1860. //
  1861. Status = IPFragment(SendList[i].bsl_if,
  1862. tmpLink->link_mtu,
  1863. Destination, NewPacket2,
  1864. NewHeader2, NewUserBuffer2,
  1865. DataSize,
  1866. NewOptions2, OptionSize, &Sent,
  1867. FALSE, tmpLink->link_arpctxt);
  1868. //
  1869. // IPFragment is done with the descriptor chain, so
  1870. // if this is a locally allocated chain free it now.
  1871. //
  1872. if ((i != (NetsToSend - 1)) || (tmpLink->link_next))
  1873. FreeIPBufferChain(NewUserBuffer2);
  1874. } else {
  1875. NewHeader2->iph_xsum = 0;
  1876. // Do not free the packet in SendIPPacket, as we may need
  1877. // to chain the buffer in case of IP_NO_RESOURCES
  1878. Status = SendIPPacket(SendList[i].bsl_if,
  1879. Destination, NewPacket2,
  1880. NewUserBuffer2, NewHeader2,
  1881. NewOptions2, OptionSize, FALSE,
  1882. tmpLink->link_arpctxt, TRUE);
  1883. if (Status == IP_PENDING) {
  1884. Sent++;
  1885. } else {
  1886. if (Status == IP_NO_RESOURCES) {
  1887. // SendIPPacket has not chained the buffer..
  1888. NdisChainBufferAtBack(NewPacket2, NewUserBuffer2);
  1889. }
  1890. if (NetsToSend == 1) {
  1891. FreeIPPacket(NewPacket2, TRUE, Status);
  1892. } else {
  1893. FreeIPPacket(NewPacket2, FALSE, Status);
  1894. }
  1895. }
  1896. }
  1897. } else { // Action != FORWARD
  1898. if ((i != (NetsToSend - 1)) || (tmpLink->link_next)) {
  1899. FreeIPBufferChain(NewUserBuffer2);
  1900. if (NewOptions2) {
  1901. CTEFreeMem(NewOptions2);
  1902. }
  1903. }
  1904. continue;
  1905. }
  1906. }
  1907. } else { // Normal path
  1908. if ((DataSize + OptionSize) > SendList[i].bsl_mtu) {
  1909. //
  1910. // This is too big
  1911. // Don't need to update Sent when fragmenting, as IPFragment
  1912. // will update the br_refcount field itself. It will also free
  1913. // the option buffer.
  1914. //
  1915. Status = IPFragment(SendList[i].bsl_if,
  1916. SendList[i].bsl_mtu,
  1917. Destination, NewPacket, NewHeader,
  1918. NewUserBuffer, DataSize,
  1919. NewOptions, OptionSize, &Sent, FALSE, NULL);
  1920. //
  1921. // IPFragment is done with the descriptor chain, so if this is
  1922. // a locally allocated chain free it now.
  1923. //
  1924. if (i != (NetsToSend - 1)) {
  1925. FreeIPBufferChain(NewUserBuffer);
  1926. }
  1927. } else {
  1928. NewHeader->iph_xsum = 0;
  1929. // Do not free the packet in SendIPPacket, as we may need
  1930. // to chain the buffer in case of IP_NO_RESOURCES
  1931. Status = SendIPPacket(SendList[i].bsl_if,
  1932. Destination, NewPacket,
  1933. NewUserBuffer, NewHeader, NewOptions,
  1934. OptionSize, FALSE, NULL, TRUE);
  1935. if (Status == IP_PENDING) {
  1936. Sent++;
  1937. } else {
  1938. if (Status == IP_NO_RESOURCES) {
  1939. // SendIPPacket has not chained the buffer..
  1940. NdisChainBufferAtBack(NewPacket, NewUserBuffer);
  1941. }
  1942. if (NetsToSend == 1) {
  1943. FreeIPPacket(NewPacket, TRUE, Status);
  1944. } else {
  1945. FreeIPPacket(NewPacket, FALSE, Status);
  1946. }
  1947. }
  1948. }
  1949. }
  1950. }
  1951. if (Temp && Temp != IPH) {
  1952. CTEFreeMem(Temp);
  1953. }
  1954. //
  1955. // Alright, we've sent everything we need to. We'll adjust the reference
  1956. // count by the number we've sent. IPFragment may also have put some
  1957. // references on it. If the reference count goes to 0, we're done and
  1958. // we'll free the BufferReference structure.
  1959. //
  1960. if (BR != NULL) {
  1961. if (ReferenceBuffer(BR, Sent) == 0) {
  1962. FreeBCastSendList(SendList, SendListSize);
  1963. // Need to undo ipsec/firewall/Hdrincl header munging
  1964. if (PC_reinject) {
  1965. //
  1966. // the only remaining way is calling xmitdone
  1967. // since ipsendcomplete won't have called xmit done as
  1968. // refcount would be -ve
  1969. //
  1970. (*IPSecSendCmpltPtr) (NULL, TempBuffer, pIpsecCtx,
  1971. IP_SUCCESS,&TempBuffer);
  1972. (*xmitdone) (PC_context, TempBuffer, IP_SUCCESS);
  1973. } else {
  1974. // Need to undo ipsec, firewall and then
  1975. // header include changes to the buffer list.
  1976. if (pIpsecCtx) {
  1977. (*IPSecSendCmpltPtr) (NULL, TempBuffer, pIpsecCtx,
  1978. IP_SUCCESS, &TempBuffer);
  1979. }
  1980. // If this is user header include packet,
  1981. // relink the original user buffer if necessary
  1982. if (PC_Firewall) {
  1983. BR->br_buffer = PC_Firewall;
  1984. }
  1985. if (BR->br_userbuffer) {
  1986. FreeIPPayloadBuffer(BR->br_buffer, BR->br_userbuffer);
  1987. }
  1988. }
  1989. CTEFreeMem(BR); // Reference is 0, free the BR structure.
  1990. return IP_SUCCESS;
  1991. } else {
  1992. FreeBCastSendList(SendList, SendListSize);
  1993. return IP_PENDING;
  1994. }
  1995. } else {
  1996. // Had only one I/F to send on. Just return the status.
  1997. FreeBCastSendList(SendList, SendListSize);
  1998. return Status;
  1999. }
  2000. }
  2001. //** IPCancelPacket - Cancels packets that are pending
  2002. //
  2003. // Called by upper layer, when a send request is cancelled.
  2004. // Check for validity of the interface and call link layer
  2005. // cancel routine, if it is registered.
  2006. //
  2007. // Entry: IPIF - Interface on which the cancel needs to be issued
  2008. // Ctxt - Pointer to the cancel ID.
  2009. //
  2010. // Returns: None
  2011. //
  2012. VOID
  2013. IPCancelPackets(void *IPIF, void * Ctxt)
  2014. {
  2015. Interface *IF;
  2016. CTELockHandle Handle;
  2017. BOOLEAN Done=FALSE;
  2018. CTEGetLock(&RouteTableLock.Lock, &Handle);
  2019. if ((Interface *)IPIF != NULL) {
  2020. IF = IFList;
  2021. if (IPIF != BCAST_IF_CTXT) {
  2022. while(IF && (IF != IPIF)) {
  2023. IF= IF->if_next;
  2024. }
  2025. if (IF && !(IF->if_flags & IF_FLAGS_DELETING) && IF->if_cancelpackets) {
  2026. LOCKED_REFERENCE_IF(IF);
  2027. CTEFreeLock(&RouteTableLock.Lock, Handle);
  2028. (*(IF->if_cancelpackets)) (IF->if_lcontext, Ctxt);
  2029. DerefIF(IF);
  2030. } else {
  2031. CTEFreeLock(&RouteTableLock.Lock, Handle);
  2032. }
  2033. } else {
  2034. //Bcast cancel!. Issue cancel on all interfaces
  2035. uint CancelListSize, CancelIFs,i=0;
  2036. Interface **CancelList;
  2037. CancelListSize = sizeof(Interface *)*(NumIF +1);
  2038. CancelList = CTEAllocMemN(CancelListSize, 'riCT');
  2039. if (!CancelList) {
  2040. CTEFreeLock(&RouteTableLock.Lock, Handle);
  2041. return;
  2042. }
  2043. //refcnt valid interfaces
  2044. while(IF){
  2045. if (IF->if_refcount && IF->if_cancelpackets) {
  2046. LOCKED_REFERENCE_IF(IF);
  2047. CancelList[++i] = IF;
  2048. }
  2049. IF = IF->if_next;
  2050. }
  2051. CTEFreeLock(&RouteTableLock.Lock, Handle);
  2052. //call cancel and deref if
  2053. CancelIFs = i;
  2054. while (i) {
  2055. (*(CancelList[i]->if_cancelpackets))(CancelList[i]->if_lcontext, Ctxt);
  2056. i--;
  2057. }
  2058. while (CancelIFs) {
  2059. DerefIF(CancelList[CancelIFs]);
  2060. CancelIFs--;
  2061. }
  2062. CTEFreeMem(CancelList);
  2063. }
  2064. } else {
  2065. CTEFreeLock(&RouteTableLock.Lock, Handle);
  2066. }
  2067. }
  2068. IP_STATUS
  2069. ARPResolve(IPAddr Dest, IPAddr Source, ARPControlBlock * controlBlock,
  2070. ArpRtn Callback)
  2071. {
  2072. NDIS_STATUS status;
  2073. Interface *DestIF;
  2074. IPAddr NextHop;
  2075. uint MTU, size;
  2076. status = IP_DEST_HOST_UNREACHABLE;
  2077. DestIF = LookupNextHop(Dest, Source, &NextHop, &MTU);
  2078. if (DestIF == &LoopInterface) {
  2079. Interface *IF = NULL;
  2080. NetTableEntry *NTE;
  2081. NetTableEntry *NetTableList = NewNetTableList[NET_TABLE_HASH(Dest)];
  2082. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
  2083. if (NTE != LoopNTE && IP_ADDR_EQUAL(NTE->nte_addr, Dest)) {
  2084. // Found one. Save it and break out.
  2085. IF = NTE->nte_if;
  2086. break;
  2087. }
  2088. }
  2089. if (IF) {
  2090. if (controlBlock->PhyAddrLen < IF->if_addrlen) {
  2091. size = controlBlock->PhyAddrLen;
  2092. status = IP_NO_RESOURCES;
  2093. } else {
  2094. size = IF->if_addrlen;
  2095. status = IP_SUCCESS;
  2096. }
  2097. RtlCopyMemory(controlBlock->PhyAddr, IF->if_addr, size);
  2098. }
  2099. DerefIF(DestIF);
  2100. return status;
  2101. }
  2102. controlBlock->CompletionRtn = Callback;
  2103. if (DestIF != NULL) {
  2104. if (!DestIF->if_arpresolveip) {
  2105. DerefIF(DestIF);
  2106. return IP_GENERAL_FAILURE;
  2107. }
  2108. if (!IP_ADDR_EQUAL(NextHop, Dest)) {
  2109. //We do not arp on non local address(via gateway)
  2110. DerefIF(DestIF);
  2111. return IP_BAD_DESTINATION;
  2112. }
  2113. status = (*(DestIF->if_arpresolveip)) (DestIF->if_lcontext, Dest,
  2114. controlBlock);
  2115. if (NDIS_STATUS_PENDING == status) {
  2116. status = IP_PENDING;
  2117. } else if (NDIS_STATUS_SUCCESS == status) {
  2118. status = IP_SUCCESS;
  2119. } else {
  2120. status = IP_GENERAL_FAILURE;
  2121. }
  2122. DerefIF(DestIF);
  2123. }
  2124. return status;
  2125. }
  2126. //** IPLargeXmit - Large Send
  2127. //
  2128. // This is the main transmit routine called by the upper layer. Conceptually,
  2129. // we process any options, look up the route to the destination, fragment the
  2130. // packet if needed, and send it. In reality, we use an RCE to cache the best
  2131. // route, and we have special case code here for dealing with the common
  2132. // case of no options, with everything fitting into one buffer.
  2133. //
  2134. // Entry: Context - Pointer to ProtInfo struc for protocol.
  2135. // SendContext - User provided send context, passed back on send cmplt.
  2136. // Protocol - Protocol field for packet.
  2137. // Buffer - NDIS_BUFFER chain of data to be sent.
  2138. // DataSize - Size in bytes of data to be sent.
  2139. // OptInfo - Pointer to optinfo structure.
  2140. // Dest - Destination to send to.
  2141. // Source - Source address to use.
  2142. // RCE - Pointer to an RCE structure that caches info. about path.
  2143. // SentBytes - pointer to return the number of bytes xmited
  2144. //
  2145. // Returns: Status of transmit command.
  2146. //
  2147. IP_STATUS
  2148. IPLargeXmit(void *Context, void *SendContext, PNDIS_BUFFER Buffer, uint DataSize,
  2149. IPAddr Dest, IPAddr Source, IPOptInfo * OptInfo, RouteCacheEntry * RCE,
  2150. uchar Protocol, ulong * SentBytes, ulong mss)
  2151. {
  2152. ProtInfo *PInfo = (ProtInfo *) Context;
  2153. PacketContext *pc;
  2154. Interface *DestIF; // Outgoing interface to use.
  2155. IPAddr FirstHop; // First hop address of
  2156. // destination.
  2157. NDIS_STATUS Status = IP_GENERAL_FAILURE;
  2158. IPHeader *IPH;
  2159. PNDIS_PACKET Packet;
  2160. PNDIS_BUFFER HeaderBuffer;
  2161. PNDIS_BUFFER OptBuffer = NULL;
  2162. CTELockHandle LockHandle;
  2163. uchar *Options;
  2164. uint OptionSize = 0;
  2165. RouteTableEntry *RTE;
  2166. uchar DType;
  2167. IP_STATUS SendStatus;
  2168. uint FirewallMode = 0;
  2169. IPSInfo.ipsi_outrequests++;
  2170. //
  2171. // Allocate a packet that we need for all cases, and fill
  2172. // in the common stuff. If everything goes well, we'll send it
  2173. // here. Otherwise we'll break out into special case code for
  2174. // broadcasts, fragments, etc.
  2175. //
  2176. // Make sure that we have an RCE, that it's valid, etc.
  2177. FirewallMode = ProcessFirewallQ();
  2178. if (ForwardFilterEnabled || FirewallMode) {
  2179. return Status;
  2180. }
  2181. if (RCE != NULL) {
  2182. // We have an RCE. Make sure it's valid.
  2183. if ((Packet = GetIPPacket()) != (PNDIS_PACKET) NULL) { // Got a packet.
  2184. PNDIS_PACKET_EXTENSION PktExt;
  2185. pc = (PacketContext *) Packet->ProtocolReserved;
  2186. pc->pc_br = (BufferReference *) NULL;
  2187. pc->pc_pi = PInfo;
  2188. pc->pc_context = SendContext;
  2189. ASSERT(pc->pc_if == NULL);
  2190. ASSERT(pc->pc_iflink == NULL);
  2191. CTEGetLock(&RCE->rce_lock, &LockHandle);
  2192. if (RCE->rce_flags == RCE_ALL_VALID) {
  2193. // The RTE is valid.
  2194. CTEInterlockedIncrementLong(&RCE->rce_usecnt);
  2195. RTE = RCE->rce_rte;
  2196. FirstHop = ADDR_FROM_RTE(RTE, Dest);
  2197. DestIF = IF_FROM_RTE(RTE);
  2198. CTEFreeLock(&RCE->rce_lock, LockHandle);
  2199. if (RCE->rce_dtype != DEST_BCAST) {
  2200. if (!OptInfo->ioi_options) {
  2201. // Construct the IP header in the backfill space
  2202. // provided by the transport
  2203. NdisAdjustBufferLength(Buffer, NdisBufferLength(Buffer) + sizeof(IPHeader));
  2204. NdisChainBufferAtBack(Packet, Buffer);
  2205. IPH = (IPHeader *)TcpipBufferVirtualAddress(Buffer, NormalPagePriority);
  2206. } else {
  2207. // Allocate a separate buffer for the IP header
  2208. // and chain to it the packet, followed by a separate
  2209. // buffer allocated for the packet's IP options.
  2210. OptionSize = OptInfo->ioi_optlength;
  2211. HeaderBuffer = GetIPHdrBuffer(&IPH);
  2212. if (HeaderBuffer) {
  2213. pc->pc_common.pc_flags |= PACKET_FLAG_IPHDR;
  2214. NdisChainBufferAtBack(Packet, HeaderBuffer);
  2215. Options = CTEAllocMemN(OptionSize, 'xiCT');
  2216. if (!Options) {
  2217. IPH = NULL;
  2218. } else {
  2219. NDIS_STATUS Status;
  2220. // Copy the options to the allocated block
  2221. // and obtain an NDIS_BUFFER to map the block.
  2222. RtlCopyMemory(Options, OptInfo->ioi_options,
  2223. OptionSize);
  2224. NdisAllocateBuffer(&Status, &OptBuffer,
  2225. BufferPool, Options,
  2226. OptionSize);
  2227. if (Status != NDIS_STATUS_SUCCESS) {
  2228. CTEFreeMem(Options);
  2229. IPH = NULL;
  2230. } else {
  2231. uchar* ULData;
  2232. // Mark the packet as carrying options,
  2233. // and chain both the options-buffer and
  2234. // the application data to the packet.
  2235. pc->pc_common.pc_flags |=
  2236. PACKET_FLAG_OPTIONS;
  2237. NdisChainBufferAtBack(Packet, OptBuffer);
  2238. // Copy the upper layer data forward.
  2239. // Note that the upper-layer header is
  2240. // assumed to be in non-paged pool, so
  2241. // TcpipBufferVirtualAddress cannot fail.
  2242. ULData = TcpipBufferVirtualAddress(Buffer, NormalPagePriority);
  2243. RtlCopyMemory(ULData,
  2244. ULData + sizeof(IPHeader),
  2245. NdisBufferLength(Buffer));
  2246. NdisChainBufferAtBack(Packet, Buffer);
  2247. }
  2248. }
  2249. }
  2250. }
  2251. if (IPH == NULL) {
  2252. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  2253. IPSInfo.ipsi_outdiscards++;
  2254. CTEInterlockedDecrementLong(&RCE->rce_usecnt);
  2255. return IP_NO_RESOURCES;
  2256. }
  2257. IPH->iph_protocol = Protocol;
  2258. IPH->iph_xsum = 0;
  2259. if (IP_ADDR_EQUAL(OptInfo->ioi_addr, NULL_IP_ADDR)) {
  2260. IPH->iph_dest = Dest;
  2261. } else {
  2262. IPH->iph_dest = OptInfo->ioi_addr;
  2263. }
  2264. IPH->iph_src = Source;
  2265. IPH->iph_ttl = OptInfo->ioi_ttl;
  2266. if (OptInfo->ioi_ttl == 0) {
  2267. NdisSetPacketFlags(Packet, NDIS_FLAGS_LOOPBACK_ONLY);
  2268. } else {
  2269. // Set DONT_LOOPBACK flags for unicast packets
  2270. // to save few cycles in ndis
  2271. NdisSetPacketFlags(Packet, NDIS_FLAGS_DONT_LOOPBACK);
  2272. }
  2273. IPH->iph_tos = OptInfo->ioi_tos;
  2274. IPH->iph_offset = net_short((OptInfo->ioi_flags & IP_FLAG_DF) << 13);
  2275. IPH->iph_id =
  2276. (ushort) InterlockedExchangeAdd(&IPIDCacheLine.Value,
  2277. (DataSize + mss - 1) / mss);
  2278. IPH->iph_id = net_short(IPH->iph_id);
  2279. IPH->iph_verlen =
  2280. IP_VERSION + ((OptionSize + sizeof(IPHeader)) >> 2);
  2281. IPH->iph_length =
  2282. net_short(DataSize + OptionSize + sizeof(IPHeader));
  2283. PktExt = NDIS_PACKET_EXTENSION_FROM_PACKET(Packet);
  2284. PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] = UlongToPtr(mss);
  2285. Status = (*(DestIF->if_xmit)) (DestIF->if_lcontext,
  2286. &Packet, 1, FirstHop, RCE, NULL);
  2287. CTEInterlockedDecrementLong(&RCE->rce_usecnt);
  2288. if (Status != NDIS_STATUS_PENDING) {
  2289. *SentBytes = PtrToUlong(PktExt->NdisPacketInfo[TcpLargeSendPacketInfo]);
  2290. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Largesend status not pending!\n"));
  2291. FreeIPPacket(Packet, TRUE, Status);
  2292. if (Status == NDIS_STATUS_SUCCESS) {
  2293. return IP_SUCCESS;
  2294. } else {
  2295. return IP_GENERAL_FAILURE;
  2296. }
  2297. } else {
  2298. return IP_PENDING;
  2299. }
  2300. } else {
  2301. FreeIPPacket(Packet, TRUE, IP_GENERAL_FAILURE);
  2302. Status = IP_GENERAL_FAILURE;
  2303. }
  2304. } else {
  2305. // large send is not possible
  2306. CTEFreeLock(&RCE->rce_lock, LockHandle);
  2307. Status = IP_GENERAL_FAILURE;
  2308. }
  2309. } else {
  2310. //could not get the packet
  2311. Status = IP_NO_RESOURCES;
  2312. }
  2313. } //RCE NULL
  2314. return Status;
  2315. }
  2316. //** IPTransmit - Transmit a packet.
  2317. //
  2318. // This is the main transmit routine called by the upper layer. Conceptually,
  2319. // we process any options, look up the route to the destination, fragment the
  2320. // packet if needed, and send it. In reality, we use an RCE to cache the best
  2321. // route, and we have special case code here for dealing with the common
  2322. // case of no options, with everything fitting into one buffer.
  2323. //
  2324. // Entry: Context - Pointer to ProtInfo struc for protocol.
  2325. // SendContext - User provided send context, passed back on send cmplt.
  2326. // Protocol - Protocol field for packet.
  2327. // Buffer - NDIS_BUFFER chain of data to be sent.
  2328. // DataSize - Size in bytes of data to be sent.
  2329. // OptInfo - Pointer to optinfo structure.
  2330. // Dest - Destination to send to.
  2331. // Source - Source address to use.
  2332. // RCE - Pointer to an RCE structure that caches info. about path.
  2333. // Protocol - Transport layer protcol number
  2334. // Irp - Pointer to Irp which generated this request, used
  2335. // for cancellation purpose
  2336. //
  2337. // Returns: Status of transmit command.
  2338. //
  2339. IP_STATUS
  2340. IPTransmit(void *Context, void *SendContext, PNDIS_BUFFER Buffer, uint DataSize,
  2341. IPAddr Dest, IPAddr Source, IPOptInfo *OptInfo, RouteCacheEntry *RCE,
  2342. uchar Protocol, IRP *Irp)
  2343. {
  2344. ProtInfo *PInfo = (ProtInfo *) Context;
  2345. PacketContext *pc;
  2346. Interface *DestIF; // Outgoing interface to use.
  2347. IPAddr FirstHop; // First hop address of destination.
  2348. uint MTU; // MTU of route.
  2349. NDIS_STATUS Status;
  2350. IPHeader *IPH;
  2351. UCHAR saveIPH[MAX_IP_HDR_SIZE + ICMP_HEADER_SIZE];
  2352. IPAddr SrcRouteOrigDest;
  2353. IPAddr SrcRouteFirstHop;
  2354. BOOLEAN fSrcRoute = FALSE;
  2355. ULONG ipsecFlags = 0;
  2356. PNDIS_PACKET Packet;
  2357. PNDIS_BUFFER HeaderBuffer;
  2358. PNDIS_BUFFER OptBuffer = NULL;
  2359. CTELockHandle LockHandle;
  2360. uchar *Options;
  2361. uint OptionSize = 0;
  2362. BufferReference *BR;
  2363. RouteTableEntry *RTE;
  2364. uchar DType;
  2365. IP_STATUS SendStatus;
  2366. Interface *RoutedIF;
  2367. BOOLEAN fIpsec; // is this an IPSEC generated packet?
  2368. FORWARD_ACTION Action = FORWARD;
  2369. ULONG ipsecByteCount = 0;
  2370. ULONG ipsecMTU;
  2371. PNDIS_BUFFER newBuf = NULL;
  2372. IPRcvBuf *pInRcvBuf = NULL;
  2373. uint FirewallMode = 0;
  2374. uint FirewallRef;
  2375. Queue* FirewallQ;
  2376. uint BufferChanged = 0; // used by firewall
  2377. UINT HdrInclOptions = FALSE;
  2378. LinkEntry *Link = NULL;
  2379. IPAddr LinkNextHop;
  2380. void *ArpCtxt = NULL;
  2381. RouteCacheEntry *RoutedRCE = NULL;
  2382. void *pvTmpBuffer;
  2383. uint ConstrainIF;
  2384. IPSInfo.ipsi_outrequests++;
  2385. // Check the request length. If it is > max that can be sent
  2386. // in IP fail this request.
  2387. if ((int)DataSize >
  2388. (MAX_TOTAL_LENGTH - (sizeof(IPHeader) + (OptInfo->ioi_options ? OptInfo->ioi_optlength : 0)))) {
  2389. IPSInfo.ipsi_outdiscards++;
  2390. return IP_PACKET_TOO_BIG;
  2391. }
  2392. if ((DataSize == 0) && OptInfo->ioi_hdrincl) {
  2393. // There is nothing to send, not even just IP header!
  2394. IPSInfo.ipsi_outdiscards++;
  2395. return IP_SUCCESS;
  2396. }
  2397. FirewallMode = ProcessFirewallQ();
  2398. DEBUGMSG(DBG_TRACE && DBG_IP && DBG_TX,
  2399. (DTEXT("+IPTransmit(%x, %x, %x, %d, %x, %x, %x, %x, %x)\n"),
  2400. Context, SendContext, Buffer, DataSize, Dest, Source,
  2401. OptInfo, RCE, Protocol));
  2402. //
  2403. // fIpsec is set if and only if this is called by IPSec driver.
  2404. //
  2405. fIpsec = (OptInfo->ioi_flags & IP_FLAG_IPSEC);
  2406. //
  2407. // Allocate a packet that we need for all cases, and fill
  2408. // in the common stuff. If everything goes well, we'll send it
  2409. // here. Otherwise we'll break out into special case code for
  2410. // broadcasts, fragments, etc.
  2411. //
  2412. Packet = GetIPPacket();
  2413. if (Packet == NULL) {
  2414. // Need to call ipsec's xmitdone since it expects us to do so
  2415. if (fIpsec) {
  2416. (PInfo->pi_xmitdone)(SendContext, Buffer, IP_NO_RESOURCES);
  2417. }
  2418. IPSInfo.ipsi_outdiscards++;
  2419. return IP_NO_RESOURCES;
  2420. }
  2421. #if !MILLEN
  2422. //Enable this in Millennium when ndis5.1 is checked in
  2423. SET_CANCELID(Irp, Packet);
  2424. #endif
  2425. pc = (PacketContext *) Packet->ProtocolReserved;
  2426. ASSERT(pc->pc_firewall == NULL);
  2427. ASSERT(pc->pc_firewall2 == NULL);
  2428. pc->pc_br = (BufferReference *) NULL;
  2429. pc->pc_pi = PInfo;
  2430. pc->pc_context = SendContext;
  2431. ASSERT(pc->pc_if == NULL);
  2432. ASSERT(pc->pc_iflink == NULL);
  2433. pc->pc_firewall = NULL;
  2434. pc->pc_firewall2 = NULL;
  2435. pc->pc_ipsec_flags = 0;
  2436. pc->pc_hdrincl = NULL;
  2437. //
  2438. // This might be called from IPSEC also; in this case, Protocol will
  2439. // indicate so. The entire IP packet is in Buffer and all we need to
  2440. // do is find the best route and ship it.
  2441. //
  2442. if (fIpsec) {
  2443. ULONG len;
  2444. ASSERT(Context);
  2445. DEBUGMSG(DBG_INFO && DBG_IP && DBG_TX,
  2446. (DTEXT("IPTransmit: ipsec....\n")));
  2447. pc->pc_common.pc_IpsecCtx = SendContext;
  2448. pc->pc_common.pc_flags |= PACKET_FLAG_IPHDR;
  2449. FirstHop = NULL_IP_ADDR;
  2450. //
  2451. // IPH is at head of first buffer
  2452. //
  2453. TcpipQueryBuffer(Buffer, (PVOID) & IPH, &len, NormalPagePriority);
  2454. if (IPH == NULL) {
  2455. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  2456. return IP_NO_RESOURCES;
  2457. }
  2458. NdisChainBufferAtBack(Packet, Buffer);
  2459. //
  2460. // Save packet header in the reinject case for potential
  2461. // Path MTU discovery use. We need to save the original IPH since
  2462. // the header can be modified when going through IPSEC again.
  2463. //
  2464. if (IPH->iph_offset & IP_DF_FLAG) {
  2465. PUCHAR pTpt;
  2466. ULONG tptLen;
  2467. ULONG HeaderLength;
  2468. *((IPHeader *) saveIPH) = *IPH;
  2469. HeaderLength = (IPH->iph_verlen & (uchar) ~ IP_VER_FLAG) << 2;
  2470. if (HeaderLength > sizeof(IPHeader)) {
  2471. TcpipQueryBuffer(NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(Buffer)),
  2472. &pTpt,
  2473. &tptLen,
  2474. NormalPagePriority);
  2475. } else {
  2476. TcpipQueryBuffer(NDIS_BUFFER_LINKAGE(Buffer),
  2477. &pTpt,
  2478. &tptLen,
  2479. NormalPagePriority);
  2480. }
  2481. if (pTpt == NULL) {
  2482. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  2483. return IP_NO_RESOURCES;
  2484. }
  2485. RtlCopyMemory((PUCHAR) saveIPH + HeaderLength,
  2486. pTpt,
  2487. ICMP_HEADER_SIZE);
  2488. }
  2489. //
  2490. // Attach the IPSecPktInfo and/or TcpipPktInfo passed in to Packet's
  2491. // NDIS extension structure.
  2492. //
  2493. if (OptInfo->ioi_options) {
  2494. PNDIS_PACKET_EXTENSION PktExt;
  2495. PktExt = NDIS_PACKET_EXTENSION_FROM_PACKET(Packet);
  2496. PktExt->NdisPacketInfo[IpSecPacketInfo] =
  2497. ((PNDIS_PACKET_EXTENSION) OptInfo->ioi_options)->
  2498. NdisPacketInfo[IpSecPacketInfo];
  2499. PktExt->NdisPacketInfo[TcpIpChecksumPacketInfo] =
  2500. ((PNDIS_PACKET_EXTENSION) OptInfo->ioi_options)->
  2501. NdisPacketInfo[TcpIpChecksumPacketInfo];
  2502. OptInfo->ioi_options = NULL;
  2503. }
  2504. goto ipsec_jump;
  2505. } else {
  2506. pc->pc_common.pc_IpsecCtx = NULL;
  2507. }
  2508. // Make sure that we have an RCE, that it's valid, etc.
  2509. #if GPC
  2510. // Check GPC handle
  2511. if (OptInfo->ioi_GPCHandle) {
  2512. IF_IPDBG(IP_DEBUG_GPC)
  2513. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL," IPXmit: gpc - setting CH on %x\n ", Packet));
  2514. NDIS_PER_PACKET_INFO_FROM_PACKET(Packet,
  2515. ClassificationHandlePacketInfo) = IntToPtr(OptInfo->ioi_GPCHandle);
  2516. //tos info is handled in protocol
  2517. }
  2518. #endif
  2519. if ((RCE != NULL) && !(RCE->rce_flags & RCE_LINK_DELETED)) {
  2520. DEBUGMSG(DBG_INFO && DBG_IP && DBG_TX,
  2521. (DTEXT("IPTransmit: RCE %x\n"), RCE));
  2522. // We have an RCE. Make sure it's valid.
  2523. CTEGetLock(&RCE->rce_lock, &LockHandle);
  2524. if (RCE->rce_flags == RCE_ALL_VALID) {
  2525. ASSERT(RCE->rce_cnt > 0);
  2526. // The RTE is valid.
  2527. CTEInterlockedIncrementLong(&RCE->rce_usecnt);
  2528. RTE = RCE->rce_rte;
  2529. FirstHop = ADDR_FROM_RTE(RTE, Dest);
  2530. DestIF = IF_FROM_RTE(RTE);
  2531. RoutedRCE = RCE;
  2532. if (DestIF->if_flags & IF_FLAGS_P2MP) {
  2533. Link = RTE->rte_link;
  2534. if (!Link) {
  2535. ASSERT(Link);
  2536. CTEFreeLock(&RCE->rce_lock, LockHandle);
  2537. FreeIPPacket(Packet, TRUE,IP_GENERAL_FAILURE);
  2538. CTEInterlockedDecrementLong(&RCE->rce_usecnt);
  2539. return IP_GENERAL_FAILURE;
  2540. }
  2541. ArpCtxt = Link->link_arpctxt;
  2542. MTU = MIN(Link->link_mtu, DestIF->if_mtu);
  2543. // pc_iflink stores a pointer to Link since sendcomplete
  2544. // has to deref it
  2545. //
  2546. pc->pc_iflink = Link;
  2547. CTEInterlockedIncrementLong(&Link->link_refcount);
  2548. } else {
  2549. MTU = MTU_FROM_RTE(RTE);
  2550. }
  2551. CTEFreeLock(&RCE->rce_lock, LockHandle);
  2552. //
  2553. // Check that we have no options, this isn't a broadcast, and
  2554. // that everything will fit into one link level MTU. If this
  2555. // is the case, we'll send it in a hurry.
  2556. // if FirewallMode is set, bail out to slow path. The reason
  2557. // is that if firewall hook adds options or increases the
  2558. // buffer size to more than MTU in fast path, we have to go to
  2559. // slow path and things becomes messy.
  2560. //
  2561. if ((OptInfo->ioi_options == (uchar *) NULL) &&
  2562. (!(*IPSecQueryStatusPtr)(OptInfo->ioi_GPCHandle)) &&
  2563. (!FirewallMode)) {
  2564. if (!IS_BCAST_DEST(RCE->rce_dtype)) {
  2565. if (DataSize <= MTU) {
  2566. // update mcast counters
  2567. if (IS_MCAST_DEST(RCE->rce_dtype)){
  2568. DestIF->if_OutMcastPkts++;
  2569. DestIF->if_OutMcastOctets += DataSize;
  2570. } else {
  2571. // Set DONT_LOOPBACK flags for unicast packets
  2572. // to save few cycles in ndis
  2573. if (OptInfo->ioi_ttl) {
  2574. NdisSetPacketFlags(Packet,
  2575. NDIS_FLAGS_DONT_LOOPBACK);
  2576. }
  2577. }
  2578. // Check if user is supplying the IP header
  2579. if (!OptInfo->ioi_hdrincl) {
  2580. NdisAdjustBufferLength(Buffer,
  2581. NdisBufferLength(Buffer) + sizeof(IPHeader));
  2582. NdisChainBufferAtBack(Packet, Buffer);
  2583. IPH = (IPHeader *) TcpipBufferVirtualAddress(Buffer,
  2584. NormalPagePriority);
  2585. if (IPH == NULL) {
  2586. FreeIPPacket(Packet, TRUE,IP_NO_RESOURCES);
  2587. if (Link) {
  2588. DerefLink(Link);
  2589. }
  2590. CTEInterlockedDecrementLong(&RCE->rce_usecnt);
  2591. return IP_NO_RESOURCES;
  2592. }
  2593. IPH->iph_protocol = Protocol;
  2594. IPH->iph_xsum = 0;
  2595. IPH->iph_dest = Dest;
  2596. IPH->iph_src = Source;
  2597. IPH->iph_ttl = OptInfo->ioi_ttl;
  2598. if (OptInfo->ioi_ttl == 0) {
  2599. NdisSetPacketFlags(Packet,
  2600. NDIS_FLAGS_LOOPBACK_ONLY);
  2601. }
  2602. IPH->iph_tos = OptInfo->ioi_tos;
  2603. IPH->iph_offset = net_short((OptInfo->ioi_flags & IP_FLAG_DF) << 13);
  2604. IPH->iph_id = (ushort) InterlockedExchangeAdd(&IPIDCacheLine.Value, 1);
  2605. IPH->iph_id = net_short(IPH->iph_id);
  2606. IPH->iph_verlen = DEFAULT_VERLEN;
  2607. IPH->iph_length = net_short(DataSize + sizeof(IPHeader));
  2608. if (!IPSecStatus) {
  2609. RCE->rce_OffloadFlags = DestIF->if_OffloadFlags;
  2610. } else {
  2611. RCE->rce_OffloadFlags = 0;
  2612. }
  2613. if (IPSecStatus ||
  2614. !(DestIF->if_OffloadFlags & IP_XMT_CHECKSUM_OFFLOAD)) {
  2615. IPH->iph_xsum = ~xsum(IPH, sizeof(IPHeader));
  2616. }
  2617. if (!IPSecStatus &&
  2618. ((DestIF->if_OffloadFlags & IP_XMT_CHECKSUM_OFFLOAD) ||
  2619. (DestIF->if_OffloadFlags & TCP_XMT_CHECKSUM_OFFLOAD))) {
  2620. PNDIS_PACKET_EXTENSION PktExt;
  2621. NDIS_TCP_IP_CHECKSUM_PACKET_INFO ChksumPktInfo;
  2622. PktExt = NDIS_PACKET_EXTENSION_FROM_PACKET(Packet);
  2623. ChksumPktInfo.Value = 0;
  2624. ChksumPktInfo.Transmit.NdisPacketChecksumV4 = 1;
  2625. if (DestIF->if_OffloadFlags & IP_XMT_CHECKSUM_OFFLOAD) {
  2626. ChksumPktInfo.Transmit.NdisPacketIpChecksum = 1;
  2627. }
  2628. if (OptInfo->ioi_TcpChksum) {
  2629. ChksumPktInfo.Transmit.NdisPacketTcpChecksum = 1;
  2630. }
  2631. PktExt->NdisPacketInfo[TcpIpChecksumPacketInfo]
  2632. = UlongToPtr(ChksumPktInfo.Value);
  2633. #if DBG
  2634. DbgIPSendHwChkSum++;
  2635. #endif
  2636. }
  2637. } else { //hdrincl
  2638. PNDIS_BUFFER UserBuffer;
  2639. int len;
  2640. NdisChainBufferAtBack(Packet, Buffer);
  2641. UserBuffer = NDIS_BUFFER_LINKAGE(Buffer);
  2642. DataSize -= NdisBufferLength(Buffer);
  2643. ASSERT((long)DataSize >= 0);
  2644. NdisAdjustBufferLength(Buffer, 0);
  2645. ASSERT(UserBuffer != NULL);
  2646. IPH = (IPHeader *) TcpipBufferVirtualAddress(UserBuffer,
  2647. NormalPagePriority);
  2648. if (IPH == NULL ||
  2649. (DataSize < sizeof(IPHeader))) {
  2650. SendStatus = (IPH == NULL) ? IP_NO_RESOURCES
  2651. : IP_GENERAL_FAILURE;
  2652. FreeIPPacket(Packet, TRUE, SendStatus);
  2653. if (Link) {
  2654. DerefLink(Link);
  2655. }
  2656. CTEInterlockedDecrementLong(&RCE->rce_usecnt);
  2657. return SendStatus;
  2658. }
  2659. if (!IPH->iph_id) {
  2660. IPH->iph_id = (ushort)InterlockedExchangeAdd(&IPIDCacheLine.Value, 1);
  2661. IPH->iph_id = net_short(IPH->iph_id);
  2662. }
  2663. len = IPH->iph_verlen & 0xf;
  2664. IPH->iph_length = net_short(DataSize);
  2665. IPH->iph_tos = OptInfo->ioi_tos;
  2666. IPH->iph_xsum = 0;
  2667. IPH->iph_xsum = ~xsum(IPH, len * 4);
  2668. ASSERT(!dbg_hdrincl);
  2669. }
  2670. // See if we need to filter this packet. If we
  2671. // do, call the filter routine to see if it's
  2672. // OK to send it.
  2673. if (!ForwardFilterEnabled) {
  2674. // Set the cancellation context
  2675. // Once link level call is made,
  2676. // Irp can go away any time
  2677. SET_CANCEL_CONTEXT(Irp, DestIF);
  2678. Status = (*(DestIF->if_xmit)) (DestIF->if_lcontext,
  2679. &Packet, 1, FirstHop,
  2680. RCE, ArpCtxt);
  2681. CTEInterlockedDecrementLong(&RCE->rce_usecnt);
  2682. if (Status != NDIS_STATUS_PENDING) {
  2683. SendStatus = (Status == NDIS_STATUS_FAILURE)
  2684. ? IP_GENERAL_FAILURE : IP_SUCCESS;
  2685. FreeIPPacket(Packet, TRUE, SendStatus);
  2686. if (Link) {
  2687. DerefLink(Link);
  2688. }
  2689. return SendStatus;
  2690. }
  2691. return IP_PENDING;
  2692. } else {
  2693. PNDIS_BUFFER pDataBuffer;
  2694. PVOID pvBuf = NULL;
  2695. ULONG cbBuf = 0;
  2696. if (DestIF->if_flags & IF_FLAGS_P2MP) {
  2697. LinkNextHop = Link->link_NextHop;
  2698. } else {
  2699. LinkNextHop = NULL_IP_ADDR;
  2700. }
  2701. //
  2702. // There are three cases which need to be
  2703. // taken care of here:
  2704. // 1) Normal path. Buffer contains both
  2705. // IPHeader and header from TCP/UDP, etc.
  2706. // 2) Raw. Buffer contains IPHeader only.
  2707. // Need to get next data in chain from
  2708. // linked buffer.
  2709. // 3) Raw - iphdrinclude. Buffer length is
  2710. // 0. Need to get IPHeader and next
  2711. // header from linked buffer.
  2712. //
  2713. // Use the byte count of the first buffer
  2714. // to determine the case to handle.
  2715. //
  2716. if (NdisBufferLength(Buffer) > sizeof(IPHeader)) {
  2717. // Case 1.
  2718. pvBuf = (PVOID) (IPH + 1);
  2719. cbBuf = NdisBufferLength(Buffer) - sizeof(IPHeader);
  2720. } else {
  2721. // Need to skip to the next buffer.
  2722. NdisGetNextBuffer(Buffer, &pDataBuffer);
  2723. if (pDataBuffer) {
  2724. if (NdisBufferLength(Buffer) == 0) {
  2725. // Case 3.
  2726. cbBuf = NdisBufferLength(pDataBuffer) - sizeof(IPHeader);
  2727. pvBuf = (PVOID) (IPH + 1);
  2728. } else {
  2729. // Case 2.
  2730. ASSERT(NdisBufferLength(Buffer)
  2731. == sizeof(IPHeader));
  2732. cbBuf = NdisBufferLength(pDataBuffer);
  2733. pvBuf = TcpipBufferVirtualAddress(
  2734. pDataBuffer,
  2735. NormalPagePriority);
  2736. }
  2737. } else {
  2738. // Should always have two buffers in
  2739. // chain at this point!
  2740. ASSERT(FALSE);
  2741. }
  2742. }
  2743. if (pvBuf == NULL) {
  2744. IPSInfo.ipsi_outdiscards++;
  2745. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  2746. if (Link) {
  2747. DerefLink(Link);
  2748. }
  2749. return IP_NO_RESOURCES;
  2750. }
  2751. CTEInterlockedIncrementLong(&ForwardFilterRefCount);
  2752. Action = (*ForwardFilterPtr) (IPH,
  2753. pvBuf, cbBuf,
  2754. INVALID_IF_INDEX,
  2755. DestIF->if_index,
  2756. NULL_IP_ADDR,
  2757. LinkNextHop);
  2758. DerefFilterPtr();
  2759. if (Action == FORWARD) {
  2760. // Set the cancellation context
  2761. // Once link level call is made,
  2762. // Irp can go away any time
  2763. SET_CANCEL_CONTEXT(Irp, DestIF);
  2764. Status = (*(DestIF->if_xmit)) (
  2765. DestIF->if_lcontext,
  2766. &Packet, 1, FirstHop,
  2767. RCE, ArpCtxt);
  2768. } else {
  2769. Status = NDIS_STATUS_SUCCESS;
  2770. IPSInfo.ipsi_outdiscards++;
  2771. } // if (Action == FORWARD)
  2772. CTEInterlockedDecrementLong(&RCE->rce_usecnt);
  2773. if (Status != NDIS_STATUS_PENDING) {
  2774. SendStatus = (Status == NDIS_STATUS_SUCCESS)
  2775. ? IP_GENERAL_FAILURE : IP_SUCCESS;
  2776. FreeIPPacket(Packet, TRUE, SendStatus);
  2777. if (Link) {
  2778. DerefLink(Link);
  2779. }
  2780. return SendStatus;
  2781. }
  2782. return IP_PENDING;
  2783. }
  2784. }
  2785. }
  2786. }
  2787. if (RCE && IPSecStatus) {
  2788. RCE->rce_OffloadFlags = 0;
  2789. }
  2790. // CTEInterlockedDecrementLong(&RCE->rce_usecnt);
  2791. DType = RCE->rce_dtype;
  2792. } else {
  2793. uint IPHdrSize, BufLength;
  2794. IPHdrSize = sizeof(IPHeader);
  2795. //If user supplied header, account for it.
  2796. //This is to satisfy DoDcallout
  2797. //may not be necessary...
  2798. if (OptInfo->ioi_hdrincl) {
  2799. IPHdrSize = 0;
  2800. }
  2801. // We have an RCE, but there is no RTE for it. Call the
  2802. // routing code to fix this.
  2803. CTEFreeLock(&RCE->rce_lock, LockHandle);
  2804. BufLength = NdisBufferLength(Buffer);
  2805. if ((BufLength == 0) && DataSize) {
  2806. PNDIS_BUFFER NextBuffer = NULL;
  2807. // Get the virtual address of user buffer
  2808. // which is after null transport header
  2809. NdisGetNextBuffer(Buffer, &NextBuffer);
  2810. ASSERT(NextBuffer != NULL);
  2811. pvTmpBuffer = TcpipBufferVirtualAddress(NextBuffer, NormalPagePriority);
  2812. BufLength = NdisBufferLength(NextBuffer);
  2813. // Since this is raw socket, just pass the raw data
  2814. // to Dod Callout, instead of pointing beyond header
  2815. // size.
  2816. IPHdrSize = 0;
  2817. } else {
  2818. pvTmpBuffer = TcpipBufferVirtualAddress(Buffer, NormalPagePriority);
  2819. BufLength = NdisBufferLength(Buffer);
  2820. }
  2821. if (pvTmpBuffer == NULL) {
  2822. IPSInfo.ipsi_outdiscards++;
  2823. FreeIPPacket(Packet, TRUE,IP_NO_RESOURCES);
  2824. return IP_NO_RESOURCES;
  2825. }
  2826. if (!AttachRCEToRTE(RCE, Protocol,
  2827. (uchar *) pvTmpBuffer + IPHdrSize,
  2828. BufLength)) {
  2829. IPSInfo.ipsi_outnoroutes++;
  2830. FreeIPPacket(Packet, TRUE, IP_DEST_HOST_UNREACHABLE);
  2831. return IP_DEST_HOST_UNREACHABLE;
  2832. }
  2833. // See if the RCE is now valid.
  2834. CTEGetLock(&RCE->rce_lock, &LockHandle);
  2835. if (RCE->rce_flags == RCE_ALL_VALID) {
  2836. // The RCE is now valid, so use his info.
  2837. RTE = RCE->rce_rte;
  2838. FirstHop = ADDR_FROM_RTE(RTE, Dest);
  2839. DestIF = IF_FROM_RTE(RTE);
  2840. RoutedRCE = RCE;
  2841. CTEInterlockedIncrementLong(&RCE->rce_usecnt);
  2842. if (DestIF->if_flags & IF_FLAGS_P2MP) {
  2843. Link = RTE->rte_link;
  2844. if (!Link) {
  2845. ASSERT(Link);
  2846. CTEFreeLock(&RCE->rce_lock, LockHandle);
  2847. FreeIPPacket(Packet, TRUE, IP_GENERAL_FAILURE);
  2848. if (RoutedRCE) {
  2849. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  2850. }
  2851. return IP_GENERAL_FAILURE;
  2852. }
  2853. ArpCtxt = Link->link_arpctxt;
  2854. MTU = MIN(Link->link_mtu, DestIF->if_mtu);
  2855. pc->pc_iflink = Link;
  2856. CTEInterlockedIncrementLong(&Link->link_refcount);
  2857. } else {
  2858. MTU = MTU_FROM_RTE(RTE);
  2859. }
  2860. DType = RCE->rce_dtype;
  2861. if (RTE->rte_if) {
  2862. RCE->rce_TcpDelAckTicks = RTE->rte_if->if_TcpDelAckTicks;
  2863. RCE->rce_TcpAckFrequency = RTE->rte_if->if_TcpAckFrequency;
  2864. } else {
  2865. RCE->rce_TcpDelAckTicks = 0;
  2866. RCE->rce_TcpAckFrequency = 0;
  2867. }
  2868. if (!IPSecStatus) {
  2869. RCE->rce_OffloadFlags = RTE->rte_if->if_OffloadFlags;
  2870. } else {
  2871. RCE->rce_OffloadFlags = 0;
  2872. }
  2873. } else
  2874. FirstHop = NULL_IP_ADDR;
  2875. CTEFreeLock(&RCE->rce_lock, LockHandle);
  2876. }
  2877. } else {
  2878. // We had no RCE, so we'll have to look it up the hard way.
  2879. FirstHop = NULL_IP_ADDR;
  2880. }
  2881. DEBUGMSG(DBG_INFO && DBG_IP && DBG_TX,
  2882. (DTEXT("IPTransmit: Bailed to slow path.\n")));
  2883. // We bailed out of the fast path for some reason. Allocate a header
  2884. // buffer, and copy the data in the first buffer forward. Then figure
  2885. // out why we're off the fast path, and deal with it. If we don't have
  2886. // the next hop info, look it up now.
  2887. //If user has supplied the IP header, assume that he is taken care
  2888. //of options too.
  2889. NdisReinitializePacket(Packet);
  2890. if (!OptInfo->ioi_hdrincl) {
  2891. HeaderBuffer = GetIPHdrBuffer(&IPH);
  2892. if (HeaderBuffer == NULL) {
  2893. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  2894. if (Link) {
  2895. DerefLink(Link);
  2896. }
  2897. IPSInfo.ipsi_outdiscards++;
  2898. if (RoutedRCE) {
  2899. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  2900. }
  2901. DEBUGMSG(DBG_WARN && DBG_IP && DBG_TX,
  2902. (DTEXT("IPTransmit: failure to allocate IP hdr.\n")));
  2903. return IP_NO_RESOURCES;
  2904. } else {
  2905. uchar *Temp1, *Temp2;
  2906. // Got a buffer, copy the upper layer data forward.
  2907. Temp1 = TcpipBufferVirtualAddress(Buffer, NormalPagePriority);
  2908. if (Temp1 == NULL) {
  2909. FreeIPHdrBuffer(HeaderBuffer);
  2910. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  2911. if (Link) {
  2912. DerefLink(Link);
  2913. }
  2914. IPSInfo.ipsi_outdiscards++;
  2915. if (RoutedRCE) {
  2916. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  2917. }
  2918. return IP_NO_RESOURCES;
  2919. }
  2920. Temp2 = Temp1 + sizeof(IPHeader);
  2921. RtlCopyMemory(Temp1, Temp2, NdisBufferLength(Buffer));
  2922. }
  2923. DEBUGMSG(DBG_INFO && DBG_IP && DBG_TX,
  2924. (DTEXT("IPTransmit: Pkt %x IPBuf %x IPH %x\n"),
  2925. Packet, HeaderBuffer, IPH));
  2926. NdisChainBufferAtBack(Packet, HeaderBuffer);
  2927. IPH->iph_protocol = Protocol;
  2928. IPH->iph_xsum = 0;
  2929. IPH->iph_src = Source;
  2930. IPH->iph_ttl = OptInfo->ioi_ttl;
  2931. if (OptInfo->ioi_ttl == 0) {
  2932. NdisSetPacketFlags(Packet, NDIS_FLAGS_LOOPBACK_ONLY);
  2933. }
  2934. IPH->iph_tos = OptInfo->ioi_tos;
  2935. IPH->iph_offset = net_short((OptInfo->ioi_flags & IP_FLAG_DF) << 13);
  2936. IPH->iph_id = (ushort) InterlockedExchangeAdd(&IPIDCacheLine.Value, 1);
  2937. IPH->iph_id = net_short(IPH->iph_id);
  2938. pc = (PacketContext *) Packet->ProtocolReserved;
  2939. pc->pc_common.pc_flags |= PACKET_FLAG_IPHDR;
  2940. if (IP_ADDR_EQUAL(OptInfo->ioi_addr, NULL_IP_ADDR)) {
  2941. IPH->iph_dest = Dest;
  2942. } else {
  2943. if (IPSecHandlerPtr) {
  2944. UCHAR Length;
  2945. ULONG Index = 0;
  2946. PUCHAR pOptions = OptInfo->ioi_options;
  2947. //
  2948. // Search for the last hop gateway address in strict
  2949. // or loose source routing option.
  2950. //
  2951. while (Index < OptInfo->ioi_optlength) {
  2952. switch (*pOptions) {
  2953. case IP_OPT_EOL:
  2954. Index = OptInfo->ioi_optlength;
  2955. break;
  2956. case IP_OPT_NOP:
  2957. Index++;
  2958. pOptions++;
  2959. break;
  2960. case IP_OPT_LSRR:
  2961. case IP_OPT_SSRR:
  2962. Length = pOptions[IP_OPT_LENGTH];
  2963. pOptions += Length;
  2964. fSrcRoute = TRUE;
  2965. SrcRouteOrigDest = *((IPAddr UNALIGNED *)(pOptions - sizeof(IPAddr)));
  2966. Index = OptInfo->ioi_optlength;
  2967. break;
  2968. case IP_OPT_RR:
  2969. case IP_OPT_TS:
  2970. case IP_OPT_ROUTER_ALERT:
  2971. case IP_OPT_SECURITY:
  2972. default:
  2973. Length = pOptions[IP_OPT_LENGTH];
  2974. Index += Length;
  2975. pOptions += Length;
  2976. break;
  2977. }
  2978. }
  2979. }
  2980. //
  2981. // We have a source route, so we need to redo the
  2982. // destination and first hop information.
  2983. //
  2984. Dest = OptInfo->ioi_addr;
  2985. IPH->iph_dest = Dest;
  2986. if (RCE != NULL) {
  2987. // We have an RCE. Make sure it's valid.
  2988. CTEGetLock(&RCE->rce_lock, &LockHandle);
  2989. if (RCE->rce_flags == RCE_ALL_VALID) {
  2990. // The RTE is valid.
  2991. RTE = RCE->rce_rte;
  2992. FirstHop = ADDR_FROM_RTE(RTE, Dest);
  2993. DestIF = IF_FROM_RTE(RTE);
  2994. if (!RoutedRCE) {
  2995. CTEInterlockedIncrementLong(&RCE->rce_usecnt);
  2996. RoutedRCE = RCE;
  2997. }
  2998. if (DestIF->if_flags & IF_FLAGS_P2MP) {
  2999. Link = RTE->rte_link;
  3000. if (!Link) {
  3001. ASSERT(Link);
  3002. CTEFreeLock(&RCE->rce_lock, LockHandle);
  3003. FreeIPPacket(Packet, TRUE, IP_GENERAL_FAILURE);
  3004. if (RoutedRCE) {
  3005. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3006. }
  3007. return IP_GENERAL_FAILURE;
  3008. }
  3009. ArpCtxt = Link->link_arpctxt;
  3010. MTU = MIN(Link->link_mtu, DestIF->if_mtu);
  3011. pc->pc_iflink = Link;
  3012. CTEInterlockedIncrementLong(&Link->link_refcount);
  3013. } else {
  3014. MTU = MTU_FROM_RTE(RTE);
  3015. }
  3016. } else {
  3017. FirstHop = NULL_IP_ADDR;
  3018. }
  3019. CTEFreeLock(&RCE->rce_lock, LockHandle);
  3020. }
  3021. }
  3022. } else { //hdrincl option
  3023. PNDIS_BUFFER UserBuffer, NewBuffer, NextBuf;
  3024. uint len;
  3025. NDIS_STATUS NewStatus;
  3026. UserBuffer = NDIS_BUFFER_LINKAGE(Buffer);
  3027. ASSERT(UserBuffer != NULL);
  3028. HeaderBuffer = GetIPHdrBuffer(&IPH);
  3029. if (HeaderBuffer == NULL) {
  3030. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3031. if (Link) {
  3032. DerefLink(Link);
  3033. }
  3034. IPSInfo.ipsi_outdiscards++;
  3035. if (RoutedRCE) {
  3036. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3037. }
  3038. return IP_NO_RESOURCES;
  3039. } else {
  3040. uchar *UserData;
  3041. // Got a buffer, copy the upper layer data forward.
  3042. UserData = TcpipBufferVirtualAddress(UserBuffer, NormalPagePriority);
  3043. if (UserData == NULL || (DataSize < sizeof(IPHeader))) {
  3044. FreeIPHdrBuffer(HeaderBuffer);
  3045. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3046. if (Link) {
  3047. DerefLink(Link);
  3048. }
  3049. IPSInfo.ipsi_outdiscards++;
  3050. if (RoutedRCE) {
  3051. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3052. }
  3053. return IP_NO_RESOURCES;
  3054. }
  3055. RtlCopyMemory(IPH, UserData, sizeof(IPHeader));
  3056. NdisAdjustBufferLength(HeaderBuffer, sizeof(IPHeader));
  3057. }
  3058. pc = (PacketContext *) Packet->ProtocolReserved;
  3059. pc->pc_common.pc_flags |= PACKET_FLAG_IPHDR;
  3060. NdisChainBufferAtBack(Packet, HeaderBuffer);
  3061. // find the header length (in bytes) specified in IPHeader
  3062. len = (IPH->iph_verlen & 0xf) << 2;
  3063. if (len < sizeof(IPHeader)) {
  3064. // Fixup of headers is not needed as this is headerinclude
  3065. // packet and header include operation is not done yet
  3066. FreeIPPacket(Packet, FALSE, IP_GENERAL_FAILURE);
  3067. if (Link) {
  3068. DerefLink(Link);
  3069. }
  3070. IPSInfo.ipsi_outdiscards++;
  3071. if (RoutedRCE) {
  3072. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3073. }
  3074. return IP_GENERAL_FAILURE;
  3075. }
  3076. if (len > sizeof(IPHeader)) {
  3077. uchar *Temp1, *Temp2;
  3078. // we have options in HDR_INCL
  3079. HdrInclOptions = TRUE;
  3080. // find the length of options.
  3081. OptionSize = len - sizeof(IPHeader);
  3082. Options = CTEAllocMemN(OptionSize, 'wiCT');
  3083. if (Options == (uchar *) NULL) {
  3084. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3085. if (Link) {
  3086. DerefLink(Link);
  3087. }
  3088. IPSInfo.ipsi_outdiscards++;
  3089. if (RoutedRCE) {
  3090. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3091. }
  3092. return IP_NO_RESOURCES;
  3093. }
  3094. // Got a buffer, copy the options in Options Buffer
  3095. Temp1 = TcpipBufferVirtualAddress(UserBuffer, NormalPagePriority);
  3096. // Assume first user buffer contains complete IP header
  3097. if (Temp1 == NULL ||
  3098. NdisBufferLength(UserBuffer) < len) {
  3099. SendStatus = (Temp1 == NULL) ? IP_NO_RESOURCES
  3100. : IP_GENERAL_FAILURE;
  3101. FreeIPPacket(Packet, TRUE, SendStatus);
  3102. if (Link) {
  3103. DerefLink(Link);
  3104. }
  3105. CTEFreeMem(Options);
  3106. IPSInfo.ipsi_outdiscards++;
  3107. if (RoutedRCE) {
  3108. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3109. }
  3110. return SendStatus;
  3111. }
  3112. RtlCopyMemory(Options, Temp1 + sizeof(IPHeader), OptionSize);
  3113. }
  3114. DataSize -= NdisBufferLength(Buffer) + len;
  3115. //
  3116. // Map out the post-IP header portion
  3117. //
  3118. pvTmpBuffer = TcpipBufferVirtualAddress(UserBuffer, NormalPagePriority);
  3119. if (pvTmpBuffer == NULL) {
  3120. NewStatus = NDIS_STATUS_RESOURCES;
  3121. } else {
  3122. // If user header buffer is just the length of IP header
  3123. // check for NextBuf
  3124. NextBuf = NDIS_BUFFER_LINKAGE(UserBuffer);
  3125. if ((NdisBufferLength(UserBuffer) - len)) {
  3126. NdisAllocateBuffer(&NewStatus, &NewBuffer, BufferPool,
  3127. ((uchar *) pvTmpBuffer) + len,
  3128. NdisBufferLength(UserBuffer) - len);
  3129. } else {
  3130. if (NextBuf) {
  3131. pvTmpBuffer = TcpipBufferVirtualAddress(NextBuf, NormalPagePriority);
  3132. if (!pvTmpBuffer) {
  3133. NewStatus = NDIS_STATUS_RESOURCES;
  3134. } else {
  3135. NdisAllocateBuffer(&NewStatus, &NewBuffer, BufferPool,
  3136. ((uchar *) pvTmpBuffer),
  3137. NdisBufferLength(NextBuf));
  3138. }
  3139. } else {
  3140. NewStatus = NDIS_STATUS_FAILURE;
  3141. }
  3142. }
  3143. }
  3144. if (NewStatus != NDIS_STATUS_SUCCESS) {
  3145. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3146. if (Link) {
  3147. DerefLink(Link);
  3148. }
  3149. if (HdrInclOptions) {
  3150. CTEFreeMem(Options);
  3151. }
  3152. IPSInfo.ipsi_outdiscards++;
  3153. if (RoutedRCE) {
  3154. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3155. }
  3156. return IP_NO_RESOURCES;
  3157. }
  3158. // Remember the orignal usermdl
  3159. // Once this ip allocated mdl is chained,
  3160. // original chain needs to be restored
  3161. // in all the completion paths.
  3162. pc->pc_hdrincl = UserBuffer;
  3163. NDIS_BUFFER_LINKAGE(Buffer) = NewBuffer;
  3164. NDIS_BUFFER_LINKAGE(NewBuffer) = NextBuf;
  3165. NdisAdjustBufferLength(Buffer, 0);
  3166. if (!IPH->iph_id) {
  3167. IPH->iph_id = (ushort) InterlockedExchangeAdd(&IPIDCacheLine.Value, 1);
  3168. IPH->iph_id = net_short(IPH->iph_id);
  3169. }
  3170. IPH->iph_length = net_short(DataSize + len);
  3171. IPH->iph_tos = OptInfo->ioi_tos;
  3172. IPH->iph_xsum = 0;
  3173. if (OptInfo->ioi_ttl == 0) {
  3174. NdisSetPacketFlags(Packet, NDIS_FLAGS_LOOPBACK_ONLY);
  3175. }
  3176. ASSERT(!dbg_hdrincl);
  3177. }
  3178. ipsec_jump:
  3179. if (RCE) {
  3180. #if 0
  3181. //
  3182. //If we take slow path for TCP, offload is meaningless
  3183. //let this packet go with xsum error
  3184. //rexmitted packet will be okay, if it takes slow path again.
  3185. //
  3186. RCE->rce_OffloadFlags = 0;
  3187. #else
  3188. if (!fIpsec && OptInfo->ioi_TcpChksum &&
  3189. (RCE->rce_OffloadFlags & TCP_XMT_CHECKSUM_OFFLOAD)) {
  3190. PNDIS_PACKET_EXTENSION PktExt =
  3191. NDIS_PACKET_EXTENSION_FROM_PACKET(Packet);
  3192. PNDIS_TCP_IP_CHECKSUM_PACKET_INFO ChksumPktInfo =
  3193. (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)
  3194. &PktExt->NdisPacketInfo[TcpIpChecksumPacketInfo];
  3195. ChksumPktInfo->Value = 0;
  3196. ChksumPktInfo->Transmit.NdisPacketChecksumV4 = 1;
  3197. ChksumPktInfo->Transmit.NdisPacketTcpChecksum = 1;
  3198. }
  3199. #endif
  3200. }
  3201. if (IP_ADDR_EQUAL(FirstHop, NULL_IP_ADDR)) {
  3202. if (OptInfo->ioi_mcastif) {
  3203. //
  3204. // mcastif is set to unnumbered interface, we won't do any
  3205. // lookup in this case
  3206. //
  3207. CTELockHandle TableLock; // Lock handle for routing table.
  3208. Interface *pIf;
  3209. CTEGetLock(&RouteTableLock.Lock, &TableLock);
  3210. for (pIf = IFList; pIf != NULL; pIf = pIf->if_next) {
  3211. if ((pIf->if_refcount != 0) &&
  3212. (pIf->if_index == OptInfo->ioi_mcastif))
  3213. break;
  3214. }
  3215. if (pIf && !(pIf->if_iftype & DONT_ALLOW_MCAST)) {
  3216. LOCKED_REFERENCE_IF(pIf);
  3217. FirstHop = Dest;
  3218. MTU = pIf->if_mtu;
  3219. Link = NULL;
  3220. DestIF = pIf;
  3221. } else {
  3222. DestIF = NULL;
  3223. }
  3224. CTEFreeLock(&RouteTableLock.Lock, TableLock);
  3225. } else {
  3226. pvTmpBuffer = TcpipBufferVirtualAddress(Buffer, NormalPagePriority);
  3227. if (pvTmpBuffer == NULL) {
  3228. if (pc->pc_hdrincl) {
  3229. NdisChainBufferAtBack(Packet, Buffer);
  3230. }
  3231. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3232. if (HdrInclOptions)
  3233. CTEFreeMem(Options);
  3234. IPSInfo.ipsi_outdiscards++;
  3235. return IP_NO_RESOURCES;
  3236. }
  3237. // Decide whether to do a strong or weak host lookup
  3238. ConstrainIF = GetIfConstraint(Dest, Source, OptInfo, fIpsec);
  3239. DestIF = LookupNextHopWithBuffer(Dest, Source, &FirstHop, &MTU,
  3240. PInfo->pi_protocol,
  3241. (uchar *) NdisBufferVirtualAddress(Buffer),
  3242. NdisBufferLength(Buffer), NULL, &Link,
  3243. Source, ConstrainIF);
  3244. DEBUGMSG(DBG_INFO && DBG_IP && DBG_TX,
  3245. (DTEXT("IPTransmit: LookupNextHopWithBuffer returned %x\n"),
  3246. DestIF));
  3247. }
  3248. pc->pc_if = DestIF;
  3249. RoutedIF = DestIF;
  3250. if (DestIF == NULL) {
  3251. // Lookup failed. Return an error.
  3252. if (pc->pc_hdrincl) {
  3253. NdisChainBufferAtBack(Packet, Buffer);
  3254. }
  3255. FreeIPPacket(Packet, TRUE, IP_DEST_HOST_UNREACHABLE);
  3256. if (HdrInclOptions)
  3257. CTEFreeMem(Options);
  3258. IPSInfo.ipsi_outnoroutes++;
  3259. return IP_DEST_HOST_UNREACHABLE;
  3260. }
  3261. if (DestIF->if_flags & IF_FLAGS_P2MP) {
  3262. if (!Link) {
  3263. if (pc->pc_hdrincl) {
  3264. NdisChainBufferAtBack(Packet, Buffer);
  3265. }
  3266. FreeIPPacket(Packet, TRUE, IP_GENERAL_FAILURE);
  3267. if (HdrInclOptions)
  3268. CTEFreeMem(Options);
  3269. DerefIF(DestIF);
  3270. return IP_GENERAL_FAILURE;
  3271. }
  3272. // NextHopCtxt = Link->link_NextHop;
  3273. ArpCtxt = Link->link_arpctxt;
  3274. pc->pc_iflink = Link;
  3275. }
  3276. if (!OptInfo->ioi_hdrincl) {
  3277. if ((DestIF->if_flags & IF_FLAGS_NOIPADDR) &&
  3278. IP_ADDR_EQUAL(Source, NULL_IP_ADDR)) {
  3279. IPH->iph_src = g_ValidAddr;
  3280. if (IP_ADDR_EQUAL(g_ValidAddr, NULL_IP_ADDR)) {
  3281. FreeIPPacket(Packet, TRUE, IP_DEST_HOST_UNREACHABLE);
  3282. if (HdrInclOptions)
  3283. CTEFreeMem(Options);
  3284. if (Link) {
  3285. DerefLink(Link);
  3286. }
  3287. DerefIF(DestIF);
  3288. IPSInfo.ipsi_outnoroutes++;
  3289. return IP_DEST_HOST_UNREACHABLE;
  3290. }
  3291. } else {
  3292. IPH->iph_src = Source;
  3293. }
  3294. }
  3295. DType = GetAddrType(Dest);
  3296. ASSERT(DType != DEST_INVALID);
  3297. } else {
  3298. RoutedIF = NULL;
  3299. }
  3300. // Set DONT_LOOPBACK flags for unicast packets
  3301. // to save few cycles in ndis
  3302. if (DType == DEST_LOCAL) {
  3303. if (OptInfo->ioi_ttl) {
  3304. NdisSetPacketFlags(Packet, NDIS_FLAGS_DONT_LOOPBACK);
  3305. }
  3306. }
  3307. //
  3308. // See if we have any options. If we do, copy them now.
  3309. //
  3310. //
  3311. // If user is giving us IP hdr, just assume he has done Options too.
  3312. //
  3313. if ((!OptInfo->ioi_hdrincl &&
  3314. (OptInfo->ioi_options != NULL) &&
  3315. OptInfo->ioi_optlength) || HdrInclOptions) {
  3316. // if HdrInclOptions is TRUE we have already created Options Buffer
  3317. if (!HdrInclOptions) {
  3318. //
  3319. // If we have a SSRR, make sure that we're sending straight to
  3320. // the first hop.
  3321. //
  3322. if (OptInfo->ioi_flags & IP_FLAG_SSRR) {
  3323. if (!IP_ADDR_EQUAL(Dest, FirstHop)) {
  3324. FreeIPPacket(Packet, TRUE, IP_DEST_HOST_UNREACHABLE);
  3325. if (Link) {
  3326. DerefLink(Link);
  3327. }
  3328. if (RoutedIF != NULL) {
  3329. DerefIF(RoutedIF);
  3330. } else {
  3331. ASSERT(RoutedRCE);
  3332. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3333. }
  3334. IPSInfo.ipsi_outnoroutes++;
  3335. return IP_DEST_HOST_UNREACHABLE;
  3336. }
  3337. }
  3338. Options = CTEAllocMemN(OptionSize = OptInfo->ioi_optlength, 'xiCT');
  3339. if (Options == (uchar *) NULL) {
  3340. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3341. if (Link) {
  3342. DerefLink(Link);
  3343. }
  3344. if (RoutedIF != NULL) {
  3345. DerefIF(RoutedIF);
  3346. } else {
  3347. ASSERT(RoutedRCE);
  3348. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3349. }
  3350. IPSInfo.ipsi_outdiscards++;
  3351. return IP_NO_RESOURCES;
  3352. }
  3353. RtlCopyMemory(Options, OptInfo->ioi_options, OptionSize);
  3354. }
  3355. //
  3356. // Allocate the MDL for options too
  3357. //
  3358. if (IPSecHandlerPtr) {
  3359. NdisAllocateBuffer(&Status, &OptBuffer, BufferPool, Options,
  3360. OptionSize);
  3361. if (Status != NDIS_STATUS_SUCCESS) { // Couldn't get the
  3362. // needed option buffer.
  3363. CTEFreeMem(Options);
  3364. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3365. if (Link) {
  3366. DerefLink(Link);
  3367. }
  3368. if (RoutedIF != NULL) {
  3369. DerefIF(RoutedIF);
  3370. } else {
  3371. ASSERT(RoutedRCE);
  3372. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3373. }
  3374. IPSInfo.ipsi_outdiscards++;
  3375. return IP_NO_RESOURCES;
  3376. }
  3377. }
  3378. } else {
  3379. Options = (uchar *) NULL;
  3380. OptionSize = 0;
  3381. }
  3382. if (!OptInfo->ioi_hdrincl) {
  3383. if (!fIpsec) {
  3384. //
  3385. // The options have been taken care of. Now see if it's some
  3386. // sort of broadcast.
  3387. //
  3388. IPH->iph_verlen = IP_VERSION + ((OptionSize + sizeof(IPHeader)) >> 2);
  3389. IPH->iph_length = net_short(DataSize + OptionSize + sizeof(IPHeader));
  3390. }
  3391. }
  3392. // Call the firewall hooks
  3393. if (FirewallMode) {
  3394. IPRcvBuf *pRcvBuf, *tmpRcvBuf;
  3395. IPRcvBuf *pOutRcvBuf;
  3396. FIREWALL_CONTEXT_T FrCtx;
  3397. PacketContext *pc2;
  3398. PNDIS_BUFFER pBuf;
  3399. Queue *CurrQ;
  3400. FIREWALL_HOOK *CurrHook;
  3401. uint SrcIFIndex = LOCAL_IF_INDEX;
  3402. uint DestIFIndex = DestIF->if_index;
  3403. uchar DestinationType = DType;
  3404. IPHeader *Temp;
  3405. KIRQL OldIrql;
  3406. PNDIS_PACKET_EXTENSION PktExt =
  3407. NDIS_PACKET_EXTENSION_FROM_PACKET(Packet);
  3408. PNDIS_TCP_IP_CHECKSUM_PACKET_INFO ChksumPktInfo =
  3409. (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)
  3410. &PktExt->NdisPacketInfo[TcpIpChecksumPacketInfo];
  3411. //
  3412. // Temp will be used to contain complete IPHeader (including
  3413. // options) When we pass the RcvBuf chain to Firewall hook, its
  3414. // assumed that whole IPHeader is contained in the first buffer
  3415. //
  3416. Temp = CTEAllocMemN(sizeof(IPHeader) + OptionSize, 'yiCT');
  3417. if (Temp == NULL) {
  3418. if (pc->pc_hdrincl) {
  3419. NdisChainBufferAtBack(Packet, Buffer);
  3420. }
  3421. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3422. if (Link) {
  3423. DerefLink(Link);
  3424. }
  3425. if (RoutedIF != NULL) {
  3426. DerefIF(RoutedIF);
  3427. } else {
  3428. ASSERT(RoutedRCE);
  3429. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3430. }
  3431. if (Options) {
  3432. CTEFreeMem(Options);
  3433. }
  3434. IPSInfo.ipsi_outdiscards++;
  3435. return IP_NO_RESOURCES;
  3436. }
  3437. *Temp = *IPH;
  3438. if (Options) {
  3439. RtlCopyMemory((uchar *) (Temp + 1), Options, OptionSize);
  3440. }
  3441. // the context we pass to the firewall hook
  3442. FrCtx.Direction = IP_TRANSMIT;
  3443. FrCtx.NTE = NULL; //not required
  3444. FrCtx.LinkCtxt = NULL;
  3445. //
  3446. // Convert MDL chain to IPRcvBuf chain
  3447. // and pass it to the firewall hook
  3448. //
  3449. // attach the IP header
  3450. pRcvBuf = (IPRcvBuf *) (CTEAllocMemN(sizeof(IPRcvBuf), 'ziCT'));
  3451. if (!pRcvBuf) {
  3452. if (pc->pc_hdrincl) {
  3453. NdisChainBufferAtBack(Packet, Buffer);
  3454. }
  3455. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3456. if (Link) {
  3457. DerefLink(Link);
  3458. }
  3459. if (RoutedIF != NULL) {
  3460. DerefIF(RoutedIF);
  3461. } else {
  3462. ASSERT(RoutedRCE);
  3463. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3464. }
  3465. if (Options) {
  3466. CTEFreeMem(Options);
  3467. }
  3468. CTEFreeMem(Temp);
  3469. IPSInfo.ipsi_outdiscards++;
  3470. return IP_NO_RESOURCES;
  3471. }
  3472. RtlZeroMemory(pRcvBuf, sizeof(IPRcvBuf));
  3473. pRcvBuf->ipr_buffer = (uchar *) Temp;
  3474. pRcvBuf->ipr_size = sizeof(IPHeader) + OptionSize;
  3475. pRcvBuf->ipr_owner = IPR_OWNER_IP;
  3476. if (ChksumPktInfo->Value) {
  3477. pRcvBuf->ipr_flags |= IPR_FLAG_CHECKSUM_OFFLOAD;
  3478. }
  3479. pInRcvBuf = pRcvBuf;
  3480. // convert the MDL chain of buffers to RcvBuf chain
  3481. // firewall hook understands RcvBuf chain only
  3482. for (pBuf = Buffer; pBuf != NULL; pBuf = pBuf->Next) {
  3483. IPRcvBuf *tmpRcvBuf;
  3484. if (NdisBufferLength(pBuf) == 0)
  3485. continue;
  3486. tmpRcvBuf = (IPRcvBuf *) (CTEAllocMemN(sizeof(IPRcvBuf), '1iCT'));
  3487. if (!tmpRcvBuf) {
  3488. IPFreeBuff(pInRcvBuf);
  3489. if (pc->pc_hdrincl) {
  3490. NdisChainBufferAtBack(Packet, Buffer);
  3491. }
  3492. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3493. if (Link) {
  3494. DerefLink(Link);
  3495. }
  3496. if (RoutedIF != NULL) {
  3497. DerefIF(RoutedIF);
  3498. } else {
  3499. ASSERT(RoutedRCE);
  3500. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3501. }
  3502. if (Options) {
  3503. CTEFreeMem(Options);
  3504. }
  3505. CTEFreeMem(Temp);
  3506. IPSInfo.ipsi_outdiscards++;
  3507. return IP_NO_RESOURCES;
  3508. }
  3509. RtlZeroMemory(tmpRcvBuf, sizeof(IPRcvBuf));
  3510. tmpRcvBuf->ipr_buffer = TcpipBufferVirtualAddress(pBuf,
  3511. NormalPagePriority);
  3512. if (tmpRcvBuf->ipr_buffer == NULL) {
  3513. CTEFreeMem(tmpRcvBuf);
  3514. IPFreeBuff(pInRcvBuf);
  3515. if (pc->pc_hdrincl) {
  3516. NdisChainBufferAtBack(Packet, Buffer);
  3517. }
  3518. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3519. if (Link) {
  3520. DerefLink(Link);
  3521. }
  3522. if (RoutedIF != NULL) {
  3523. DerefIF(RoutedIF);
  3524. } else {
  3525. ASSERT(RoutedRCE);
  3526. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3527. }
  3528. if (Options) {
  3529. CTEFreeMem(Options);
  3530. }
  3531. CTEFreeMem(Temp);
  3532. IPSInfo.ipsi_outdiscards++;
  3533. return IP_NO_RESOURCES;
  3534. }
  3535. pRcvBuf->ipr_next = tmpRcvBuf;
  3536. tmpRcvBuf->ipr_size = NdisBufferLength(pBuf);
  3537. ASSERT(tmpRcvBuf->ipr_buffer != NULL);
  3538. ASSERT(tmpRcvBuf->ipr_size != 0);
  3539. tmpRcvBuf->ipr_owner = IPR_OWNER_IP;
  3540. if (ChksumPktInfo->Value) {
  3541. tmpRcvBuf->ipr_flags |= IPR_FLAG_CHECKSUM_OFFLOAD;
  3542. }
  3543. pRcvBuf = tmpRcvBuf;
  3544. }
  3545. pRcvBuf->ipr_next = NULL;
  3546. pOutRcvBuf = NULL;
  3547. pc = (PacketContext *) Packet->ProtocolReserved;
  3548. // scan the Queue from rear
  3549. // we scannned the Queue from front in rcv path
  3550. #if MILLEN
  3551. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  3552. #else // MILLEN
  3553. OldIrql = KeRaiseIrqlToDpcLevel();
  3554. #endif // MILLEN
  3555. FirewallRef = RefFirewallQ(&FirewallQ);
  3556. CurrQ = QPREV(FirewallQ);
  3557. while (CurrQ != QEND(FirewallQ)) {
  3558. CurrHook = QSTRUCT(FIREWALL_HOOK, CurrQ, hook_q);
  3559. // pOutRcvBuf has to be NULL before we call the firewallhook
  3560. // pInRcvBuf contains the input buffer chain
  3561. pOutRcvBuf = NULL;
  3562. Action = (*CurrHook->hook_Ptr) (&pInRcvBuf,
  3563. SrcIFIndex,
  3564. &DestIFIndex,
  3565. &DestinationType,
  3566. &FrCtx,
  3567. sizeof(FrCtx),
  3568. &pOutRcvBuf);
  3569. if (Action == DROP) {
  3570. DerefFirewallQ(FirewallRef);
  3571. KeLowerIrql(OldIrql);
  3572. IPSInfo.ipsi_outdiscards++;
  3573. if (pInRcvBuf != NULL) {
  3574. IPFreeBuff(pInRcvBuf);
  3575. }
  3576. if (pOutRcvBuf != NULL) {
  3577. IPFreeBuff(pOutRcvBuf);
  3578. }
  3579. if (pc->pc_hdrincl) {
  3580. NdisChainBufferAtBack(Packet, Buffer);
  3581. }
  3582. FreeIPPacket(Packet, TRUE, IP_DEST_HOST_UNREACHABLE);
  3583. if (Link) {
  3584. DerefLink(Link);
  3585. }
  3586. if (RoutedIF != NULL) {
  3587. DerefIF(RoutedIF);
  3588. } else {
  3589. ASSERT(RoutedRCE);
  3590. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3591. }
  3592. if (Options) {
  3593. CTEFreeMem(Options);
  3594. }
  3595. CTEFreeMem(Temp);
  3596. IPSInfo.ipsi_outdiscards++;
  3597. return IP_DEST_HOST_UNREACHABLE;
  3598. } else {
  3599. ASSERT(Action == FORWARD);
  3600. if (pOutRcvBuf != NULL) {
  3601. // free the old buffer if non NULL
  3602. if (pInRcvBuf != NULL) {
  3603. IPFreeBuff(pInRcvBuf);
  3604. }
  3605. pInRcvBuf = pOutRcvBuf;
  3606. BufferChanged = 1;
  3607. }
  3608. } // Action == FORWARD
  3609. CurrQ = QPREV(CurrQ);
  3610. }
  3611. DerefFirewallQ(FirewallRef);
  3612. KeLowerIrql(OldIrql);
  3613. ASSERT(Action == FORWARD);
  3614. if (BufferChanged) {
  3615. // At least one of the firewall hook touched the buffer
  3616. PNDIS_BUFFER CurrentBuffer;
  3617. PNDIS_BUFFER tmpBuffer;
  3618. int Status;
  3619. uint hlen;
  3620. //
  3621. // It is assumed that if first buffer contained just ipheader
  3622. // before the hook is called, this holds after firewall also
  3623. //
  3624. ASSERT(pInRcvBuf->ipr_buffer != NULL);
  3625. RtlCopyMemory((uchar *) IPH, pInRcvBuf->ipr_buffer, sizeof(IPHeader));
  3626. //
  3627. // we recompute it later on anyway: so if firewall has
  3628. // recomputed make it 0
  3629. //
  3630. IPH->iph_xsum = 0;
  3631. //
  3632. // find the header length (in bytes) specified in IPHeader
  3633. //
  3634. hlen = (IPH->iph_verlen & 0xf) << 2;
  3635. ASSERT(pInRcvBuf->ipr_size == hlen);
  3636. OptionSize = hlen - sizeof(IPHeader);
  3637. if (Options) {
  3638. // we will allocate a new one anyway
  3639. CTEFreeMem(Options);
  3640. if (IPSecHandlerPtr) {
  3641. // ipsec allocated the option buffer also
  3642. NdisFreeBuffer(OptBuffer);
  3643. OptBuffer = NULL;
  3644. }
  3645. }
  3646. if (OptionSize) {
  3647. Options = CTEAllocMemN(OptionSize, '2iCT');
  3648. if (Options == NULL) {
  3649. if (pc->pc_hdrincl) {
  3650. NdisChainBufferAtBack(Packet, Buffer);
  3651. }
  3652. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3653. CTEFreeMem(Temp);
  3654. IPFreeBuff(pInRcvBuf);
  3655. if (Link) {
  3656. DerefLink(Link);
  3657. }
  3658. if (RoutedIF != NULL) {
  3659. DerefIF(RoutedIF);
  3660. } else {
  3661. ASSERT(RoutedRCE);
  3662. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3663. }
  3664. IPSInfo.ipsi_outdiscards++;
  3665. return IP_NO_RESOURCES;
  3666. }
  3667. RtlCopyMemory(Options, pInRcvBuf->ipr_buffer + sizeof(IPHeader),
  3668. OptionSize);
  3669. if (IPSecHandlerPtr) {
  3670. NdisAllocateBuffer(&Status, &OptBuffer,
  3671. BufferPool, Options, OptionSize);
  3672. //
  3673. // If we couldn't get the needed options buffer
  3674. //
  3675. if (Status != NDIS_STATUS_SUCCESS) {
  3676. CTEFreeMem(Options);
  3677. if (pc->pc_hdrincl) {
  3678. NdisChainBufferAtBack(Packet, Buffer);
  3679. }
  3680. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3681. CTEFreeMem(Temp);
  3682. IPFreeBuff(pInRcvBuf);
  3683. if (Link) {
  3684. DerefLink(Link);
  3685. }
  3686. if (RoutedIF != NULL) {
  3687. DerefIF(RoutedIF);
  3688. } else {
  3689. ASSERT(RoutedRCE);
  3690. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3691. }
  3692. IPSInfo.ipsi_outdiscards++;
  3693. return IP_NO_RESOURCES;
  3694. }
  3695. }
  3696. } else {
  3697. Options = NULL;
  3698. }
  3699. // if packet touched compute the new length: DataSize
  3700. DataSize = 0;
  3701. tmpRcvBuf = pInRcvBuf->ipr_next; // First buffer contains
  3702. // header + options
  3703. while (tmpRcvBuf != NULL) {
  3704. ASSERT(tmpRcvBuf->ipr_buffer != NULL);
  3705. DataSize += tmpRcvBuf->ipr_size;
  3706. tmpRcvBuf = tmpRcvBuf->ipr_next;
  3707. }
  3708. // Convert the IPRcvBuf chain to MDL chain
  3709. // form the buffer chain again
  3710. tmpRcvBuf = pInRcvBuf->ipr_next; // first buffer contains
  3711. // just IP Header +
  3712. // options, if any
  3713. ASSERT(tmpRcvBuf->ipr_buffer != NULL);
  3714. ASSERT(tmpRcvBuf->ipr_size != 0);
  3715. NdisAllocateBuffer(&Status, &tmpBuffer, BufferPool,
  3716. tmpRcvBuf->ipr_buffer, tmpRcvBuf->ipr_size);
  3717. if (Status != NDIS_STATUS_SUCCESS) {
  3718. if (Options) {
  3719. // option buffer.
  3720. CTEFreeMem(Options);
  3721. if (IPSecHandlerPtr) {
  3722. NdisFreeBuffer(OptBuffer);
  3723. }
  3724. }
  3725. IPFreeBuff(pInRcvBuf);
  3726. if (pc->pc_hdrincl) {
  3727. NdisChainBufferAtBack(Packet, Buffer);
  3728. }
  3729. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3730. CTEFreeMem(Temp);
  3731. if (Link) {
  3732. DerefLink(Link);
  3733. }
  3734. if (RoutedIF != NULL) {
  3735. DerefIF(RoutedIF);
  3736. } else {
  3737. ASSERT(RoutedRCE);
  3738. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3739. }
  3740. IPSInfo.ipsi_outdiscards++;
  3741. return IP_NO_RESOURCES;
  3742. }
  3743. tmpBuffer->Next = (PNDIS_BUFFER) NULL;
  3744. //
  3745. // save these 2 in the packet context: will be used in
  3746. // freeippacket/ipsendcomplete
  3747. //
  3748. pc->pc_firewall = Buffer;
  3749. pc->pc_firewall2 = pInRcvBuf;
  3750. // Convert the RcvBuf chain back to MDL chain
  3751. Buffer = tmpBuffer;
  3752. CurrentBuffer = Buffer;
  3753. for (tmpRcvBuf = tmpRcvBuf->ipr_next;
  3754. tmpRcvBuf != NULL;
  3755. tmpRcvBuf = tmpRcvBuf->ipr_next) {
  3756. ASSERT(tmpRcvBuf->ipr_buffer != NULL);
  3757. ASSERT(tmpRcvBuf->ipr_size != 0);
  3758. if (tmpRcvBuf->ipr_size == 0)
  3759. continue;
  3760. NdisAllocateBuffer(&Status, &tmpBuffer, BufferPool,
  3761. tmpRcvBuf->ipr_buffer, tmpRcvBuf->ipr_size);
  3762. if (Status != NDIS_STATUS_SUCCESS) {
  3763. if (Options) {
  3764. // option buffer.
  3765. CTEFreeMem(Options);
  3766. if (IPSecHandlerPtr) {
  3767. NdisFreeBuffer(OptBuffer);
  3768. }
  3769. }
  3770. CTEFreeMem(Temp);
  3771. if (pc->pc_hdrincl) {
  3772. NdisChainBufferAtBack(Packet, Buffer);
  3773. }
  3774. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3775. FreeIPBufferChain(Buffer);
  3776. if (Link) {
  3777. DerefLink(Link);
  3778. }
  3779. if (RoutedIF != NULL) {
  3780. DerefIF(RoutedIF);
  3781. } else {
  3782. ASSERT(RoutedRCE);
  3783. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3784. }
  3785. IPSInfo.ipsi_outdiscards++;
  3786. return IP_NO_RESOURCES;
  3787. }
  3788. CurrentBuffer->Next = tmpBuffer;
  3789. CurrentBuffer = tmpBuffer;
  3790. CurrentBuffer->Next = (PNDIS_BUFFER) NULL;
  3791. }
  3792. ASSERT(CurrentBuffer->Next == NULL);
  3793. if (DestinationType == DEST_INVALID) {
  3794. // recompute DestIF by doing a lookup again
  3795. Dest = IPH->iph_dest;
  3796. // Decide whether to do a strong or weak host lookup
  3797. ConstrainIF = GetIfConstraint(Dest, Source, OptInfo, fIpsec);
  3798. if (!ConstrainIF) {
  3799. //
  3800. // if this option is set, we want to send on the
  3801. // address we are bound to so don't recompute the
  3802. // Source address from IP header
  3803. //
  3804. Source = IPH->iph_src;
  3805. }
  3806. DType = GetAddrType(Dest);
  3807. if (Link) {
  3808. DerefLink(Link);
  3809. // Make sure that pc_iflink is also initialized
  3810. pc->pc_iflink = NULL;
  3811. Link = NULL;
  3812. }
  3813. if (RoutedIF != NULL) {
  3814. DerefIF(DestIF);
  3815. } else {
  3816. ASSERT(RoutedRCE);
  3817. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3818. RoutedRCE = NULL;
  3819. }
  3820. pvTmpBuffer = TcpipBufferVirtualAddress(Buffer,
  3821. NormalPagePriority);
  3822. if (pvTmpBuffer == NULL) {
  3823. if (Options) {
  3824. CTEFreeMem(Options);
  3825. }
  3826. if (pc->pc_hdrincl) {
  3827. NdisChainBufferAtBack(Packet, Buffer);
  3828. }
  3829. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3830. if (BufferChanged) {
  3831. FreeIPBufferChain(Buffer);
  3832. }
  3833. IPSInfo.ipsi_outdiscards++;
  3834. return IP_NO_RESOURCES;
  3835. }
  3836. // Decide whether to do a strong or weak host lookup
  3837. ConstrainIF = GetIfConstraint(Dest, Source, OptInfo, fIpsec);
  3838. DestIF = LookupNextHopWithBuffer(Dest, Source, &FirstHop, &MTU,
  3839. PInfo->pi_protocol,
  3840. (uchar *) NdisBufferVirtualAddress(Buffer),
  3841. NdisBufferLength(Buffer), NULL, &Link,
  3842. Source, ConstrainIF);
  3843. pc->pc_if = DestIF;
  3844. RoutedIF = DestIF;
  3845. if (DestIF == NULL) {
  3846. // Lookup failed. Return an error.
  3847. if (Options)
  3848. CTEFreeMem(Options);
  3849. if (pc->pc_hdrincl) {
  3850. NdisChainBufferAtBack(Packet, Buffer);
  3851. }
  3852. FreeIPPacket(Packet, TRUE, IP_DEST_HOST_UNREACHABLE);
  3853. if (BufferChanged) {
  3854. FreeIPBufferChain(Buffer);
  3855. }
  3856. IPSInfo.ipsi_outnoroutes++;
  3857. return IP_DEST_HOST_UNREACHABLE;
  3858. }
  3859. if (DestIF->if_flags & IF_FLAGS_P2MP) {
  3860. if (!Link) {
  3861. ASSERT(Link);
  3862. if (pc->pc_hdrincl) {
  3863. NdisChainBufferAtBack(Packet, Buffer);
  3864. }
  3865. FreeIPPacket(Packet, TRUE, IP_GENERAL_FAILURE);
  3866. if (HdrInclOptions) {
  3867. CTEFreeMem(Options);
  3868. }
  3869. DerefIF(DestIF);
  3870. return IP_GENERAL_FAILURE;
  3871. }
  3872. // NextHopCtxt = Link->link_NextHop;
  3873. ArpCtxt = Link->link_arpctxt;
  3874. pc->pc_iflink = Link;
  3875. }
  3876. }
  3877. // Finally, clear the checksum-request option in the packet,
  3878. // if it was set. The firewall-hook is responsible for ensuring
  3879. // that the checksum has now been computed correctly.
  3880. ChksumPktInfo->Value = 0;
  3881. } // BufferChanged
  3882. else { // Buffer not changed
  3883. if (pInRcvBuf != NULL) {
  3884. IPFreeBuff(pInRcvBuf);
  3885. }
  3886. }
  3887. CTEFreeMem(Temp);
  3888. }
  3889. if (ForwardFilterEnabled) {
  3890. IPHeader *Temp;
  3891. PNDIS_BUFFER pDataBuffer;
  3892. PVOID pvBuf = NULL;
  3893. ULONG cbBuf = 0;
  3894. //
  3895. // See if we need to filter this packet. If we
  3896. // do, call the filter routine to see if it's
  3897. // OK to send it.
  3898. //
  3899. if (Options == NULL) {
  3900. Temp = IPH;
  3901. } else {
  3902. Temp = CTEAllocMemN(sizeof(IPHeader) + OptionSize, '3iCT');
  3903. if (Temp == NULL) {
  3904. if (pc->pc_hdrincl) {
  3905. NdisChainBufferAtBack(Packet, Buffer);
  3906. }
  3907. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3908. if (BufferChanged) {
  3909. FreeIPBufferChain(Buffer);
  3910. }
  3911. if (Link) {
  3912. DerefLink(Link);
  3913. }
  3914. if (RoutedIF != NULL) {
  3915. DerefIF(RoutedIF);
  3916. } else {
  3917. ASSERT(RoutedRCE);
  3918. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3919. }
  3920. CTEFreeMem(Options);
  3921. if (IPSecHandlerPtr) {
  3922. NdisFreeBuffer(OptBuffer);
  3923. }
  3924. IPSInfo.ipsi_outdiscards++;
  3925. return IP_NO_RESOURCES;
  3926. }
  3927. *Temp = *IPH;
  3928. RtlCopyMemory((uchar *) (Temp + 1), Options, OptionSize);
  3929. }
  3930. if (DestIF->if_flags & IF_FLAGS_P2MP) {
  3931. LinkNextHop = Link->link_NextHop;
  3932. } else {
  3933. LinkNextHop = NULL_IP_ADDR;
  3934. }
  3935. //
  3936. // There are some cases where the first buffer in the chain
  3937. // of data does not contain any data. This includes ICMP,
  3938. // and iphdrinclude. If the first buffer is zero length,
  3939. // then we skip and give the second buffer. Really the
  3940. // filter api should take an MDL chain.
  3941. //
  3942. if (NdisBufferLength(Buffer) == 0) {
  3943. NdisGetNextBuffer(Buffer, &pDataBuffer);
  3944. if (pDataBuffer) {
  3945. cbBuf = NdisBufferLength(pDataBuffer);
  3946. pvBuf = TcpipBufferVirtualAddress(pDataBuffer,
  3947. NormalPagePriority);
  3948. }
  3949. } else {
  3950. pvBuf = TcpipBufferVirtualAddress(Buffer, NormalPagePriority);
  3951. cbBuf = NdisBufferLength(Buffer);
  3952. }
  3953. if (pvBuf == NULL) {
  3954. if (Options)
  3955. CTEFreeMem(Options);
  3956. // Need to chain buffers correctly to packet before calling
  3957. // FreeIPPacket.
  3958. if (pc->pc_hdrincl) {
  3959. NdisChainBufferAtBack(Packet, Buffer);
  3960. }
  3961. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  3962. if (BufferChanged) {
  3963. FreeIPBufferChain(Buffer);
  3964. }
  3965. if (Link) {
  3966. DerefLink(Link);
  3967. }
  3968. if (RoutedIF != NULL) {
  3969. DerefIF(RoutedIF);
  3970. } else {
  3971. ASSERT(RoutedRCE);
  3972. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  3973. }
  3974. IPSInfo.ipsi_outdiscards++;
  3975. return IP_NO_RESOURCES;
  3976. }
  3977. CTEInterlockedIncrementLong(&ForwardFilterRefCount);
  3978. Action = (*ForwardFilterPtr) (Temp,
  3979. pvBuf,
  3980. cbBuf,
  3981. INVALID_IF_INDEX,
  3982. DestIF->if_index,
  3983. NULL_IP_ADDR, LinkNextHop);
  3984. DerefFilterPtr();
  3985. if (Options != NULL) {
  3986. CTEFreeMem(Temp);
  3987. }
  3988. if (Action != FORWARD) {
  3989. //
  3990. // If this is a bcast pkt, dont fail the send here since we might
  3991. // send this pkt over some other NTE; instead, let SendIPBCast
  3992. // deal with the Filtering for broadcast pkts.
  3993. //
  3994. // NOTE: We shd actually not call into ForwardFilterPtr here at
  3995. // all since we deal with it in BCast, but we do so in order to
  3996. // avoid a check above and hence
  3997. // take a double call hit in the bcast case.
  3998. //
  3999. if (DType != DEST_BCAST) {
  4000. if (Options)
  4001. CTEFreeMem(Options);
  4002. // Need to chain buffers correctly to packet before calling
  4003. // FreeIPPacket.
  4004. if (pc->pc_hdrincl) {
  4005. NdisChainBufferAtBack(Packet, Buffer);
  4006. }
  4007. FreeIPPacket(Packet, TRUE, IP_DEST_HOST_UNREACHABLE);
  4008. if (BufferChanged) {
  4009. FreeIPBufferChain(Buffer);
  4010. }
  4011. if (Link) {
  4012. DerefLink(Link);
  4013. }
  4014. if (RoutedIF != NULL) {
  4015. DerefIF(RoutedIF);
  4016. } else {
  4017. ASSERT(RoutedRCE);
  4018. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  4019. }
  4020. IPSInfo.ipsi_outdiscards++;
  4021. return IP_DEST_HOST_UNREACHABLE;
  4022. }
  4023. #if FWD_DBG
  4024. else {
  4025. DbgPrint("IPTransmit: ignoring return %lx\n", Action);
  4026. }
  4027. #endif
  4028. }
  4029. }
  4030. if (IPSecHandlerPtr) {
  4031. //
  4032. // See if IPSEC is enabled, see if it needs to do anything with this
  4033. // packet - we need to construct the full IP header in the first MDL
  4034. // before we call out to IPSEC.
  4035. //
  4036. IPSEC_ACTION Action;
  4037. ulong csum;
  4038. ushort savecsum;
  4039. PacketContext *pc = (PacketContext *) Packet->ProtocolReserved;
  4040. //
  4041. // dont re-xsum if this came from IPSEC.
  4042. //
  4043. if (fIpsec) {
  4044. HeaderBuffer = Buffer;
  4045. } else {
  4046. IPH->iph_xsum = 0;
  4047. csum = xsum(IPH, sizeof(IPHeader));
  4048. //
  4049. // Link the header buffer to the options buffer before we
  4050. // indicate to IPSEC
  4051. //
  4052. if (OptBuffer) {
  4053. NDIS_BUFFER_LINKAGE(HeaderBuffer) = OptBuffer;
  4054. NDIS_BUFFER_LINKAGE(OptBuffer) = Buffer;
  4055. //
  4056. // update the xsum in the IP header
  4057. //
  4058. pc->pc_common.pc_flags |= PACKET_FLAG_OPTIONS;
  4059. csum += xsum(Options, OptionSize);
  4060. csum = (csum >> 16) + (csum & 0xffff);
  4061. csum += (csum >> 16);
  4062. } else {
  4063. NDIS_BUFFER_LINKAGE(HeaderBuffer) = Buffer;
  4064. }
  4065. IPH->iph_xsum = ~(ushort) csum;
  4066. }
  4067. if ((DataSize + OptionSize) < MTU) {
  4068. ipsecByteCount = MTU - (DataSize + OptionSize);
  4069. }
  4070. ipsecMTU = MTU;
  4071. //
  4072. // Pass the original dest address if source routing.
  4073. //
  4074. if (fSrcRoute) {
  4075. SrcRouteFirstHop = IPH->iph_dest;
  4076. IPH->iph_dest = SrcRouteOrigDest;
  4077. ipsecFlags |= IPSEC_FLAG_SSRR;
  4078. }
  4079. if (DestIF == &LoopInterface) {
  4080. ipsecFlags |= IPSEC_FLAG_LOOPBACK;
  4081. }
  4082. Action = (*IPSecHandlerPtr) ((PUCHAR) IPH,
  4083. (PVOID) HeaderBuffer,
  4084. DestIF,
  4085. Packet,
  4086. &ipsecByteCount,
  4087. &ipsecMTU,
  4088. (PVOID) & newBuf,
  4089. &ipsecFlags,
  4090. DType);
  4091. //
  4092. // Put back the dest address for source routing.
  4093. //
  4094. if (fSrcRoute) {
  4095. IPH->iph_dest = SrcRouteFirstHop;
  4096. }
  4097. if (Action != eFORWARD) {
  4098. IP_STATUS ipStatus;
  4099. //
  4100. // If this is a bcast pkt, dont fail the send here since we
  4101. // might send this pkt over some other NTE; instead, let
  4102. // SendIPBCast deal with the Filtering
  4103. // for broadcast pkts.
  4104. // Since Options are linked already, FreeIPPacket will do
  4105. // the right thing.
  4106. //
  4107. FreeIPPacket(Packet, TRUE, IP_DEST_HOST_UNREACHABLE);
  4108. if (ipsecMTU) {
  4109. ipStatus = IP_PACKET_TOO_BIG;
  4110. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPTransmit: MTU %lx, ipsecMTU %lx\n", MTU, ipsecMTU));
  4111. if (fIpsec) {
  4112. SendICMPIPSecErr(DestIF->if_nte->nte_addr,
  4113. (IPHeader *) saveIPH,
  4114. ICMP_DEST_UNREACH,
  4115. FRAG_NEEDED,
  4116. net_long(ipsecMTU + sizeof(IPHeader)));
  4117. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPTransmit: Sent ICMP frag_needed to %lx, "
  4118. "from src: %lx\n",
  4119. ((IPHeader *) saveIPH)->iph_src,
  4120. DestIF->if_nte->nte_addr));
  4121. } else if (RCE) {
  4122. RCE->rce_newmtu = ipsecMTU;
  4123. }
  4124. } else {
  4125. if (Action == eABSORB && Protocol == PROTOCOL_ICMP) {
  4126. ipStatus = IP_NEGOTIATING_IPSEC;
  4127. } else {
  4128. ipStatus = IP_DEST_HOST_UNREACHABLE;
  4129. }
  4130. }
  4131. if (Link) {
  4132. DerefLink(Link);
  4133. }
  4134. if (RoutedIF != NULL) {
  4135. DerefIF(RoutedIF);
  4136. } else {
  4137. ASSERT(RoutedRCE);
  4138. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  4139. }
  4140. IPSInfo.ipsi_outdiscards++;
  4141. return ipStatus;
  4142. } else {
  4143. //
  4144. // Reset newmtu if we don't need IPSec. Otherwise if this RCE
  4145. // was applied IPSec previously but not now and link MTU gets
  4146. // changed, we won't be able to adjust MTU anymore in TCPSend.
  4147. //
  4148. if (!pc->pc_common.pc_IpsecCtx && RCE) {
  4149. RCE->rce_newmtu = 0;
  4150. }
  4151. //
  4152. // Use the new buffer chain - IPSEC will restore the old one
  4153. // on send complete
  4154. //
  4155. if (newBuf) {
  4156. NdisReinitializePacket(Packet);
  4157. NdisChainBufferAtBack(Packet, newBuf);
  4158. }
  4159. DataSize += ipsecByteCount;
  4160. }
  4161. }
  4162. //
  4163. // If this is a broadcast address, call our broadcast send handler
  4164. // to deal with this. The broadcast address handler will free the
  4165. // option buffer for us, if needed. Otherwise if it's a fragment, call
  4166. // the fragmentation handler.
  4167. //
  4168. if (DType == DEST_BCAST) {
  4169. DEBUGMSG(DBG_INFO && DBG_IP && DBG_TX,
  4170. (DTEXT("IPTransmit: DEST_BCAST, source %x\n"), Source));
  4171. //Note the fact that this is bcast pkt,in the irp,
  4172. //used for cancelling the requests
  4173. //Irp can go away any time
  4174. SET_CANCEL_CONTEXT(Irp, BCAST_IF_CTXT);
  4175. if (IP_ADDR_EQUAL(Source, NULL_IP_ADDR)) {
  4176. SendStatus = SendDHCPPacket(Dest, Packet, Buffer, IPH, ArpCtxt);
  4177. if ((Link) && (SendStatus != IP_PENDING)) {
  4178. DerefLink(Link);
  4179. }
  4180. if (SendStatus != IP_PENDING && RoutedIF != NULL) {
  4181. DerefIF(RoutedIF);
  4182. }
  4183. if (RoutedRCE) {
  4184. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  4185. }
  4186. return SendStatus;
  4187. } else {
  4188. SendStatus = SendIPBCast(NULL, Dest, Packet, IPH, Buffer, DataSize,
  4189. Options, OptionSize,
  4190. OptInfo->ioi_limitbcasts, NULL);
  4191. if ((Link) && (SendStatus != IP_PENDING)) {
  4192. DerefLink(Link);
  4193. }
  4194. if (SendStatus != IP_PENDING && RoutedIF != NULL) {
  4195. DerefIF(RoutedIF);
  4196. }
  4197. if (RoutedRCE) {
  4198. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  4199. }
  4200. // In the case of header include, SendIPBcast will handle
  4201. // the cleanup.
  4202. return SendStatus;
  4203. }
  4204. }
  4205. // Not a broadcast. If it needs to be fragmented, call our
  4206. // fragmenter to do it. The fragmentation routine needs a
  4207. // BufferReference structure, so we'll need one of those first.
  4208. if ((DataSize + OptionSize) > MTU) {
  4209. DEBUGMSG(DBG_INFO && DBG_IP && DBG_TX,
  4210. (DTEXT("IPTransmit: fragmentation needed.\n")));
  4211. BR = CTEAllocMemN(sizeof(BufferReference), '4iCT');
  4212. if (BR == (BufferReference *) NULL) {
  4213. // Couldn't get a BufferReference
  4214. //
  4215. // If options are already linked in, dont free them.
  4216. // FreeIPPacket will.
  4217. //
  4218. if (Options) {
  4219. if (!(pc->pc_common.pc_flags & PACKET_FLAG_OPTIONS)) {
  4220. CTEFreeMem(Options);
  4221. } else if (newBuf) {
  4222. //
  4223. // Option has been copied by IPSEC (in the tunneling
  4224. // case); free the original option and clear the
  4225. // FLAG_OPTIONS so that FreeIPPacket will not try to
  4226. // free options again.
  4227. //
  4228. ASSERT(IPSecHandlerPtr);
  4229. NdisFreeBuffer(OptBuffer);
  4230. CTEFreeMem(Options);
  4231. pc->pc_common.pc_flags &= ~PACKET_FLAG_OPTIONS;
  4232. }
  4233. }
  4234. if (pc->pc_hdrincl) {
  4235. NdisChainBufferAtBack(Packet, Buffer);
  4236. }
  4237. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  4238. if (BufferChanged) {
  4239. FreeIPBufferChain(Buffer);
  4240. }
  4241. if (Link) {
  4242. DerefLink(Link);
  4243. }
  4244. if (RoutedIF != NULL) {
  4245. DerefIF(RoutedIF);
  4246. }
  4247. if (RoutedRCE) {
  4248. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  4249. }
  4250. IPSInfo.ipsi_outdiscards++;
  4251. return IP_NO_RESOURCES;
  4252. }
  4253. BR->br_buffer = Buffer;
  4254. BR->br_refcount = 0;
  4255. CTEInitLock(&BR->br_lock);
  4256. pc->pc_br = BR;
  4257. BR->br_userbuffer = pc->pc_hdrincl;
  4258. //
  4259. // setup so IPSEC headers appear just as first part of the data.
  4260. //
  4261. if (IPSecHandlerPtr) {
  4262. //
  4263. // If this is a reinjected packet from IPSEC, then, allocate
  4264. // another IP header here.
  4265. //
  4266. // This is to ensure that in fragmented packets, the send
  4267. // completes happen properly vis-a-vis IPSEC.
  4268. //
  4269. // When packet comes in it looks like this: [IP]->[ULP]
  4270. // We allocate another IP header [IP'] and nuke [IP] length
  4271. // to 0 so that it is ignored and [IP'] is used instead.
  4272. //
  4273. if (fIpsec) {
  4274. PNDIS_BUFFER UserBuffer;
  4275. int len;
  4276. NDIS_STATUS NewStatus;
  4277. int hdrLen;
  4278. UserBuffer = Buffer;
  4279. HeaderBuffer = GetIPHdrBuffer(&IPH);
  4280. if (HeaderBuffer == NULL) {
  4281. pc->pc_common.pc_flags &= ~PACKET_FLAG_IPHDR;
  4282. pc->pc_ipsec_flags |= (IPSEC_FLAG_FRAG_DONE |
  4283. IPSEC_FLAG_FLUSH);
  4284. if (pc->pc_hdrincl) {
  4285. NdisChainBufferAtBack(Packet, Buffer);
  4286. }
  4287. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  4288. CTEFreeMem(BR);
  4289. if (Link) {
  4290. DerefLink(Link);
  4291. }
  4292. if (RoutedIF != NULL) {
  4293. DerefIF(RoutedIF);
  4294. }
  4295. if (RoutedRCE) {
  4296. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  4297. }
  4298. IPSInfo.ipsi_outdiscards++;
  4299. return IP_NO_RESOURCES;
  4300. } else {
  4301. uchar *UserData;
  4302. // Got a buffer, copy the upper layer data forward.
  4303. UserData = TcpipBufferVirtualAddress(UserBuffer,
  4304. NormalPagePriority);
  4305. if (UserData == NULL) {
  4306. FreeIPHdrBuffer(HeaderBuffer);
  4307. pc->pc_common.pc_flags &= ~PACKET_FLAG_IPHDR;
  4308. pc->pc_ipsec_flags |= (IPSEC_FLAG_FRAG_DONE |
  4309. IPSEC_FLAG_FLUSH);
  4310. if (pc->pc_hdrincl) {
  4311. NdisChainBufferAtBack(Packet, Buffer);
  4312. }
  4313. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  4314. CTEFreeMem(BR);
  4315. if (Link) {
  4316. DerefLink(Link);
  4317. }
  4318. if (RoutedIF != NULL) {
  4319. DerefIF(RoutedIF);
  4320. }
  4321. if (RoutedRCE) {
  4322. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  4323. }
  4324. IPSInfo.ipsi_outdiscards++;
  4325. return IP_NO_RESOURCES;
  4326. }
  4327. RtlCopyMemory(IPH, UserData, sizeof(IPHeader));
  4328. NdisAdjustBufferLength(HeaderBuffer, sizeof(IPHeader));
  4329. }
  4330. pc = (PacketContext *) Packet->ProtocolReserved;
  4331. pc->pc_common.pc_flags |= PACKET_FLAG_IPHDR;
  4332. NdisAdjustBufferLength(Buffer, 0);
  4333. //
  4334. // Handle options by using the same method as above:
  4335. // i.e. link our own options buffer; copy out the input
  4336. // options and nuke the input buffer.
  4337. //
  4338. hdrLen = (IPH->iph_verlen & (uchar) ~ IP_VER_FLAG) << 2;
  4339. if (hdrLen > sizeof(IPHeader)) {
  4340. PNDIS_BUFFER InOptionBuf;
  4341. ULONG InOptionSize;
  4342. PUCHAR InOptions;
  4343. InOptionBuf = NDIS_BUFFER_LINKAGE(UserBuffer);
  4344. ASSERT(InOptionBuf);
  4345. TcpipQueryBuffer(InOptionBuf, &InOptions,
  4346. &InOptionSize, NormalPagePriority);
  4347. Options = CTEAllocMemN(InOptionSize, '5iCT');
  4348. if (Options == NULL || InOptions == NULL) {
  4349. pc->pc_common.pc_flags &= ~PACKET_FLAG_IPHDR;
  4350. if (Options) {
  4351. CTEFreeMem(Options);
  4352. }
  4353. pc->pc_ipsec_flags |= (IPSEC_FLAG_FRAG_DONE |
  4354. IPSEC_FLAG_FLUSH);
  4355. if (pc->pc_hdrincl) {
  4356. NdisChainBufferAtBack(Packet, Buffer);
  4357. }
  4358. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  4359. CTEFreeMem(BR);
  4360. if (Link) {
  4361. DerefLink(Link);
  4362. }
  4363. if (RoutedIF != NULL) {
  4364. DerefIF(RoutedIF);
  4365. }
  4366. if (RoutedRCE) {
  4367. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  4368. }
  4369. IPSInfo.ipsi_outdiscards++;
  4370. return IP_NO_RESOURCES;
  4371. }
  4372. //
  4373. // Got a buffer, copy the options.
  4374. //
  4375. OptionSize = InOptionSize;
  4376. RtlCopyMemory(Options, InOptions, OptionSize);
  4377. NdisAdjustBufferLength(InOptionBuf, 0);
  4378. }
  4379. } else {
  4380. Buffer = NDIS_BUFFER_LINKAGE(HeaderBuffer);
  4381. //
  4382. // This is to ensure that options are freed appropriately.
  4383. // In the fragment code, the first fragment inherits the
  4384. // options of the entire packet; but these packets have
  4385. // no IPSEC context, hence cannot be freed appropriately.
  4386. // So, we allocate temporary options here and use these to
  4387. // represent the real options.
  4388. // These are freed when the first fragment is freed and
  4389. // the real options are freed here.
  4390. //
  4391. if (Options) {
  4392. PUCHAR tmpOptions;
  4393. if (newBuf) {
  4394. //
  4395. // if a new buffer chain was returned above by
  4396. // IPSEC, then it is most prob. a tunnel =>
  4397. // options were copied, hence get rid of ours.
  4398. //
  4399. NdisFreeBuffer(OptBuffer);
  4400. CTEFreeMem(Options);
  4401. Options = NULL;
  4402. OptionSize = 0;
  4403. } else {
  4404. Buffer = NDIS_BUFFER_LINKAGE(OptBuffer);
  4405. tmpOptions = CTEAllocMemN(OptionSize, '6iCT');
  4406. if (!tmpOptions) {
  4407. if (pc->pc_hdrincl) {
  4408. NdisChainBufferAtBack(Packet, Buffer);
  4409. }
  4410. FreeIPPacket(Packet, TRUE, IP_NO_RESOURCES);
  4411. CTEFreeMem(BR);
  4412. if (Link) {
  4413. DerefLink(Link);
  4414. }
  4415. if (RoutedIF != NULL) {
  4416. DerefIF(RoutedIF);
  4417. }
  4418. if (RoutedRCE) {
  4419. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  4420. }
  4421. IPSInfo.ipsi_outdiscards++;
  4422. return IP_NO_RESOURCES;
  4423. }
  4424. NdisFreeBuffer(OptBuffer);
  4425. RtlCopyMemory(tmpOptions, Options, OptionSize);
  4426. CTEFreeMem(Options);
  4427. Options = tmpOptions;
  4428. }
  4429. pc->pc_common.pc_flags &= ~PACKET_FLAG_OPTIONS;
  4430. }
  4431. }
  4432. NDIS_BUFFER_LINKAGE(HeaderBuffer) = NULL;
  4433. NdisReinitializePacket(Packet);
  4434. NdisChainBufferAtBack(Packet, HeaderBuffer);
  4435. IPH->iph_xsum = 0;
  4436. }
  4437. // Mark Irp with the destif
  4438. // Once link level call is made,
  4439. // Irp can go away any time
  4440. SET_CANCEL_CONTEXT(Irp, DestIF);
  4441. SendStatus = IPFragment(DestIF, MTU, FirstHop, Packet, IPH,
  4442. Buffer, DataSize, Options, OptionSize,
  4443. NULL, FALSE, ArpCtxt);
  4444. //
  4445. // If IPFragment returns IP_PACKET_TOO_BIG (meaning DF bit is set)
  4446. // and we are in the IPSEC reinject path, send an ICMP error
  4447. // message including the MTU back so the source host can perform
  4448. // Path MTU discovery.
  4449. //
  4450. if ((SendStatus == IP_PACKET_TOO_BIG) && fIpsec) {
  4451. ASSERT(IPSecHandlerPtr);
  4452. SendICMPIPSecErr(DestIF->if_nte->nte_addr,
  4453. (IPHeader *) saveIPH,
  4454. ICMP_DEST_UNREACH,
  4455. FRAG_NEEDED,
  4456. net_long(MTU + sizeof(IPHeader)));
  4457. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPTransmit: Sent ICMP frag_needed to %lx, "
  4458. "from src: %lx\n",
  4459. ((IPHeader *) saveIPH)->iph_src,
  4460. DestIF->if_nte->nte_addr));
  4461. }
  4462. if ((Link) && (SendStatus != IP_PENDING)) {
  4463. DerefLink(Link);
  4464. }
  4465. if (SendStatus != IP_PENDING && RoutedIF != NULL) {
  4466. DerefIF(RoutedIF);
  4467. }
  4468. if (RoutedRCE) {
  4469. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  4470. }
  4471. // If this is a headerinclude packet and status != pending, IPFragment takes
  4472. // care of clean up.
  4473. return SendStatus;
  4474. }
  4475. DEBUGMSG(DBG_INFO && DBG_IP && DBG_TX,
  4476. (DTEXT("IPTransmit: Calling SendIPPacket...\n")));
  4477. //
  4478. // If we've reached here, we aren't sending a broadcast and don't
  4479. // need to fragment anything. Presumably we got here because we have
  4480. // options. In any case, we're ready now.
  4481. //
  4482. // Mark Irp with outgoing interface
  4483. // Once link level call is made,
  4484. // Irp can go away any time
  4485. SET_CANCEL_CONTEXT(Irp, DestIF);
  4486. // Do not free the packet in SendIPPacket, as we may need
  4487. // to chain the buffer in case of IP_NO_RESOURCES
  4488. SendStatus = SendIPPacket(DestIF, FirstHop, Packet, Buffer, IPH,
  4489. Options, OptionSize, (BOOLEAN) (IPSecHandlerPtr != NULL),
  4490. ArpCtxt, TRUE);
  4491. if ((Link) && (SendStatus != IP_PENDING)) {
  4492. DerefLink(Link);
  4493. }
  4494. if (SendStatus != IP_PENDING && RoutedIF != NULL) {
  4495. DerefIF(RoutedIF);
  4496. }
  4497. if (RoutedRCE) {
  4498. CTEInterlockedDecrementLong(&RoutedRCE->rce_usecnt);
  4499. }
  4500. if (SendStatus != IP_PENDING) {
  4501. if (SendStatus == IP_NO_RESOURCES) {
  4502. NdisChainBufferAtBack(Packet, Buffer);
  4503. }
  4504. FreeIPPacket(Packet, TRUE, SendStatus);
  4505. }
  4506. return SendStatus;
  4507. }