Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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