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.

2999 lines
85 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. tcpip\ip\mcastfwd.c
  5. Abstract:
  6. The actual multicast forwarding code
  7. Author:
  8. Amritansh Raghav
  9. Revision History:
  10. AmritanR Created
  11. Notes:
  12. --*/
  13. #include "precomp.h"
  14. #if IPMCAST
  15. #define __FILE_SIG__ FWD_SIG
  16. #include "ipmcast.h"
  17. #include "ipmcstxt.h"
  18. #include "mcastmfe.h"
  19. #include "tcpipbuf.h"
  20. #include "info.h"
  21. uchar
  22. ParseRcvdOptions(
  23. IPOptInfo *,
  24. OptIndex *
  25. );
  26. IPHeader *
  27. GetFWPacket(
  28. PNDIS_PACKET *Packet
  29. );
  30. void
  31. FreeFWPacket(
  32. PNDIS_PACKET Packet
  33. );
  34. UINT
  35. GrowFWBuffer(
  36. VOID
  37. );
  38. IP_STATUS
  39. IPFragment(
  40. Interface *DestIF,
  41. uint MTU,
  42. IPAddr FirstHop,
  43. PNDIS_PACKET Packet,
  44. IPHeader *Header,
  45. PNDIS_BUFFER Buffer,
  46. uint DataSize,
  47. uchar *Options,
  48. uint OptionSize,
  49. int *SentCount,
  50. BOOLEAN bDontLoopback,
  51. void *ArpCtxt
  52. );
  53. IPHeader *
  54. GetIPHeader(
  55. PNDIS_PACKET *PacketPtr
  56. );
  57. IP_STATUS
  58. SendIPPacket(
  59. Interface *IF,
  60. IPAddr FirstHop,
  61. PNDIS_PACKET Packet,
  62. PNDIS_BUFFER Buffer,
  63. IPHeader *Header,
  64. uchar *Options,
  65. uint OptionSize,
  66. BOOLEAN IPSeced,
  67. void *ArpCtxt,
  68. BOOLEAN DontFreePacket
  69. );
  70. void
  71. FWSendComplete(
  72. void *SendContext,
  73. PNDIS_BUFFER Buffer,
  74. IP_STATUS SendStatus
  75. );
  76. uchar
  77. UpdateOptions(
  78. uchar *Options,
  79. OptIndex *Index,
  80. IPAddr Address
  81. );
  82. int
  83. ReferenceBuffer(
  84. BufferReference *BR, int Count
  85. );
  86. EXTERNAL_LOCK(FWBufFreeLock);
  87. extern PNDIS_BUFFER FWBufFree;
  88. extern NDIS_HANDLE BufferPool;
  89. //
  90. // A quick way of getting to the flags.
  91. //
  92. #define PCFLAGS pc_common.pc_flags
  93. #define FCFLAGS fc_pc.PCFLAGS
  94. NDIS_STATUS
  95. AllocateCopyBuffers(
  96. IN PNDIS_PACKET pnpPacket,
  97. IN ULONG ulDataLength,
  98. OUT PNDIS_BUFFER *ppnbBuffer,
  99. OUT PULONG pulNumBufs
  100. );
  101. NTSTATUS
  102. IPMForward(
  103. PNDIS_PACKET pnpPacket,
  104. PSOURCE pSource,
  105. BOOLEAN bSendFromQueue
  106. );
  107. VOID
  108. IPMForwardAfterTD(
  109. NetTableEntry *pPrimarySrcNte,
  110. PNDIS_PACKET pnpPacket,
  111. UINT uiBytesCopied
  112. );
  113. BOOLEAN
  114. IPMForwardAfterRcv(
  115. NetTableEntry *pPrimarySrcNte,
  116. IPHeader UNALIGNED *pHeader,
  117. ULONG ulHeaderLength,
  118. PVOID pvData,
  119. ULONG ulBufferLength,
  120. NDIS_HANDLE LContext1,
  121. UINT LContext2,
  122. BYTE byDestType,
  123. LinkEntry *pLink
  124. );
  125. BOOLEAN
  126. IPMForwardAfterRcvPkt(
  127. NetTableEntry *pPrimarySrcNte,
  128. IPHeader UNALIGNED *pHeader,
  129. ULONG ulHeaderLength,
  130. PVOID pvData,
  131. ULONG ulBufferLength,
  132. NDIS_HANDLE LContext1,
  133. UINT LContext2,
  134. BYTE byDestType,
  135. UINT uiMacHeaderSize,
  136. PNDIS_BUFFER pNdisBuffer,
  137. uint *pClientCnt,
  138. LinkEntry *pLink
  139. );
  140. NDIS_STATUS
  141. __inline
  142. ProcessOptions(
  143. FWContext *pFWC,
  144. ULONG ulHeaderLength,
  145. IPHeader UNALIGNED *pHeader
  146. );
  147. //
  148. // VOID
  149. // LinkHeaderAndData(
  150. // PNDIS_PACKET _pPacket,
  151. // FWContext *_pFWC,
  152. // PBYTE _pOptions,
  153. // PNDIS_BUFFER _pOptBuff
  154. // )
  155. //
  156. // This routine links up the header, options (if any) and the data
  157. // portions of an IP Packet.
  158. // It takes an NDIS_PACKET, which has the IP data portion in NDIS_BUFFERs
  159. // linked to it, as its input. The FWContext for the packet must
  160. // have the header, header buffer and options set up.
  161. // It adds the options up front and then adds the header before that
  162. //
  163. #define UnlinkDataFromPacket(_pPacket, _pFWC) \
  164. { \
  165. PNDIS_BUFFER _pDataBuff, _pHeaderBuff; \
  166. PVOID _pvVirtualAddress; \
  167. RtAssert(_pFWC == (FWContext *)_pPacket->ProtocolReserved); \
  168. _pDataBuff = _pPacket->Private.Head; \
  169. _pHeaderBuff = _pFWC->fc_hndisbuff; \
  170. _pPacket->Private.Head = _pHeaderBuff; \
  171. _pPacket->Private.Tail = _pHeaderBuff; \
  172. NDIS_BUFFER_LINKAGE(_pHeaderBuff) = NULL; \
  173. _pPacket->Private.TotalLength = sizeof(IPHeader); \
  174. _pPacket->Private.Count = 1; \
  175. _pvVirtualAddress = NdisBufferVirtualAddress(_pHeaderBuff); \
  176. _pPacket->Private.PhysicalCount = \
  177. ADDRESS_AND_SIZE_TO_SPAN_PAGES(_pvVirtualAddress, \
  178. sizeof(IPHeader)); \
  179. }
  180. //
  181. // Code to dump the header of a packet. For debug purposes
  182. //
  183. #define DumpIpHeader(s,e,p) \
  184. Trace(s,e, \
  185. ("Src %d.%d.%d.%d Dest %d.%d.%d.%d\n", \
  186. PRINT_IPADDR((p)->iph_src), \
  187. PRINT_IPADDR((p)->iph_dest))); \
  188. Trace(s,e, \
  189. ("HdrLen %d Total Len %d\n", \
  190. ((((p)->iph_verlen)&0x0f)<<2), \
  191. net_short((p)->iph_length))); \
  192. Trace(s,e, \
  193. ("TTL %d XSum %x\n",(p)->iph_ttl, (p)->iph_xsum))
  194. //
  195. // Since this is used both in IPMForwardAfterRcv and IPMForwardAfterRcvPkt,
  196. // we put the code here so bugs can be fixed in one place
  197. //
  198. #if MREF_DEBUG
  199. #define InitForwardContext() \
  200. { \
  201. pFWC = (FWContext *)pnpNewPacket->ProtocolReserved; \
  202. RtAssert(pFWC->fc_buffhead is NULL); \
  203. RtAssert(pFWC->fc_hbuff is pNewHeader); \
  204. RtAssert(pFWC->fc_optlength is 0); \
  205. RtAssert(pFWC->fc_options is NULL); \
  206. RtAssert(!(pFWC->FCFLAGS & PACKET_FLAG_OPTIONS)); \
  207. RtAssert(pFWC->FCFLAGS & PACKET_FLAG_FW); \
  208. RtAssert(!(pFWC->FCFLAGS & PACKET_FLAG_MFWD)); \
  209. pFWC->FCFLAGS |= PACKET_FLAG_MFWD; \
  210. pFWC->fc_options = NULL; \
  211. pFWC->fc_optlength = 0; \
  212. pFWC->fc_if = NULL; \
  213. pFWC->fc_mtu = 0; \
  214. pFWC->fc_srcnte = pPrimarySrcNte; \
  215. pFWC->fc_nexthop = 0; \
  216. pFWC->fc_sos = DisableSendOnSource; \
  217. pFWC->fc_dtype = DEST_REM_MCAST; \
  218. pFWC->fc_pc.pc_br = NULL; \
  219. if(pLink) { CTEInterlockedIncrementLong(&(pLink->link_refcount)); } \
  220. pFWC->fc_iflink = pLink; \
  221. }
  222. #else
  223. #define InitForwardContext() \
  224. { \
  225. pFWC = (FWContext *)pnpNewPacket->ProtocolReserved; \
  226. RtAssert(pFWC->fc_buffhead is NULL); \
  227. RtAssert(pFWC->fc_hbuff is pNewHeader); \
  228. RtAssert(pFWC->fc_optlength is 0); \
  229. RtAssert(pFWC->fc_options is NULL); \
  230. RtAssert(!(pFWC->FCFLAGS & PACKET_FLAG_OPTIONS)); \
  231. RtAssert(pFWC->FCFLAGS & PACKET_FLAG_FW); \
  232. pFWC->fc_options = NULL; \
  233. pFWC->fc_optlength = 0; \
  234. pFWC->fc_if = NULL; \
  235. pFWC->fc_mtu = 0; \
  236. pFWC->fc_srcnte = pPrimarySrcNte; \
  237. pFWC->fc_nexthop = 0; \
  238. pFWC->fc_sos = DisableSendOnSource; \
  239. pFWC->fc_dtype = DEST_REM_MCAST; \
  240. pFWC->fc_pc.pc_br = NULL; \
  241. if(pLink) { CTEInterlockedIncrementLong(&(pLink->link_refcount)); } \
  242. pFWC->fc_iflink = pLink; \
  243. }
  244. #endif
  245. #pragma warning(push)
  246. #pragma warning(disable:4127) // conditional expression is constant
  247. _inline
  248. VOID
  249. ProcessWrongIfUpcall(Interface * pIf, PSOURCE pSrc, LinkEntry * pLink,
  250. IPHeader UNALIGNED * pHdr, ULONG ulHdrLen,
  251. PUCHAR pvOpt, ULONG ulOptLen, PVOID pvData,
  252. ULONG ulDataLen)
  253. {
  254. if(pIf->if_mcastflags & IPMCAST_IF_WRONG_IF)
  255. {
  256. PEXCEPT_IF pTempIf;
  257. BOOLEAN bWrong = TRUE;
  258. LONGLONG llCurrentTime, llTime;
  259. KeQueryTickCount((PLARGE_INTEGER)&llCurrentTime);
  260. llTime = llCurrentTime - pIf->if_lastupcall;
  261. if((llCurrentTime > pIf->if_lastupcall) && (llTime < SECS_TO_TICKS(UPCALL_PERIOD))) {
  262. bWrong = FALSE;
  263. } else {
  264. for(pTempIf = (pSrc)->pFirstExceptIf;
  265. pTempIf != NULL;
  266. pTempIf = pTempIf->pNextExceptIf)
  267. {
  268. if(pTempIf->dwIfIndex == (pIf)->if_index)
  269. {
  270. bWrong = FALSE;
  271. break;
  272. }
  273. }
  274. }
  275. if(bWrong)
  276. {
  277. SendWrongIfUpcall((pIf), (pLink), (pHdr), (ulHdrLen),
  278. (pvOpt), (ulOptLen), (pvData), (ulDataLen));
  279. }
  280. }
  281. }
  282. #pragma warning(pop)
  283. //
  284. // Again common code, but this is too big to put as a #define.
  285. // Make it inline for better speed
  286. //
  287. //
  288. // MUST BE PAGED IN
  289. //
  290. #pragma alloc_text(PAGEIPMc, ProcessOptions)
  291. NDIS_STATUS
  292. __inline
  293. ProcessOptions(
  294. FWContext *pFWC,
  295. ULONG ulHeaderLength,
  296. IPHeader UNALIGNED *pHeader
  297. )
  298. {
  299. IPOptInfo oiOptInfo;
  300. BYTE byErrIndex;
  301. pFWC->fc_index.oi_srtype = NO_SR;
  302. pFWC->fc_index.oi_srindex = MAX_OPT_SIZE;
  303. pFWC->fc_index.oi_rrindex = MAX_OPT_SIZE;
  304. pFWC->fc_index.oi_tsindex = MAX_OPT_SIZE;
  305. oiOptInfo.ioi_options = (uchar *)(pHeader + 1);
  306. oiOptInfo.ioi_optlength = (BYTE)(ulHeaderLength - sizeof(IPHeader));
  307. byErrIndex = ParseRcvdOptions(&oiOptInfo,
  308. &pFWC->fc_index);
  309. if(byErrIndex < MAX_OPT_SIZE)
  310. {
  311. return NDIS_STATUS_FAILURE;
  312. }
  313. pFWC->fc_options = CTEAllocMem(oiOptInfo.ioi_optlength);
  314. if(pFWC->fc_options is NULL)
  315. {
  316. return NDIS_STATUS_RESOURCES;
  317. }
  318. // copy the options across
  319. RtlCopyMemory( pFWC->fc_options,
  320. oiOptInfo.ioi_options,
  321. oiOptInfo.ioi_optlength );
  322. pFWC->fc_optlength = oiOptInfo.ioi_optlength;
  323. pFWC->FCFLAGS |= PACKET_FLAG_OPTIONS;
  324. return NDIS_STATUS_SUCCESS;
  325. }
  326. //////////////////////////////////////////////////////////////////////////////
  327. // //
  328. // Routines //
  329. // //
  330. //////////////////////////////////////////////////////////////////////////////
  331. //
  332. // MUST BE PAGED IN
  333. //
  334. #pragma alloc_text(PAGEIPMc, IPMForwardAfterTD)
  335. VOID
  336. IPMForwardAfterTD(
  337. NetTableEntry *pPrimarySrcNte,
  338. PNDIS_PACKET pnpPacket,
  339. UINT uiBytesCopied
  340. )
  341. /*++
  342. Routine Description:
  343. This is the function called by IPTDComplete when a Transfer Data completes
  344. and it figures out that the packet was a multicast that needed to be
  345. forwarded
  346. Unlike the unicast code, TD is called very early on in the forward routine
  347. (before the main forwarding workhorse is called).
  348. We need to patch up the NDIS_PACKET so that the header, options and data are
  349. in the right order. Then we call the main forwarding function
  350. Locks:
  351. Arguments:
  352. pPrimarySrcNte
  353. pnpPacket
  354. uiBytesCopied
  355. Return Value:
  356. None
  357. --*/
  358. {
  359. FWContext *pFWC;
  360. UNREFERENCED_PARAMETER(uiBytesCopied);
  361. UNREFERENCED_PARAMETER(pPrimarySrcNte);
  362. //
  363. // DONT CALL ENTERDRIVER() HERE BECAUSE WE DID NOT CALL EXITDRIVER
  364. // IF TD WAS PENDING
  365. //
  366. TraceEnter(FWD, "IPMForwardAfterTD");
  367. pFWC = (FWContext *)pnpPacket->ProtocolReserved;
  368. RtAssert(uiBytesCopied is pFWC->fc_datalength);
  369. //
  370. // After TD we get the data portion in the packet and the options, are in
  371. // the Just call the main multicast function with the right arguments
  372. //
  373. IPMForward(pnpPacket,
  374. NULL,
  375. FALSE);
  376. TraceLeave(FWD, "IPMForwardAfterTD");
  377. ExitDriver();
  378. return;
  379. }
  380. //
  381. // MUST BE PAGED IN
  382. //
  383. #pragma alloc_text(PAGEIPMc, IPMForwardAfterRcv)
  384. BOOLEAN
  385. IPMForwardAfterRcv(
  386. NetTableEntry *pPrimarySrcNte,
  387. IPHeader UNALIGNED *pHeader,
  388. ULONG ulHeaderLength,
  389. PVOID pvData,
  390. ULONG ulBufferLength,
  391. NDIS_HANDLE LContext1,
  392. UINT LContext2,
  393. BYTE byDestType,
  394. LinkEntry *pLink
  395. )
  396. /*++
  397. Routine Description:
  398. This is the forwarding function called from IPRcv.
  399. We look up the (S,G) entry.
  400. If the entry is present, we do the RPF check. If it fails or if the
  401. entry was NEGATIVE, we toss the packet out.
  402. (The case of no entry is covered in IPMForward)
  403. We get a new packet and header and fill that up. We set up the
  404. forwarding context, and then check if we need to do a Transfer Data. If
  405. so we call the lower layer's TD routine. If that returns pending, we
  406. are done. If the TD is synchronous or was not needed at all, we set
  407. the NDIS_PACKET so that the header, options and data are all properly
  408. chained. Then we call the main forwarding routine
  409. Locks:
  410. Arguments:
  411. SrcNTE - Pointer to NTE on which packet was received.
  412. Packet - Packet being forwarded, used for TD.
  413. Data - Pointer to data buffer being forwarded.
  414. DataLength - Length in bytes of Data.
  415. BufferLength - Length in bytes available in buffer pointer to by Data.
  416. Offset - Offset into original data from which to transfer.
  417. LContext1, LContext2 - Context values for the link layer.
  418. Return Value:
  419. TRUE if the IP filter-driver needs to be notified, FALSE otherwise.
  420. --*/
  421. {
  422. Interface *pInIf;
  423. PSOURCE pSource;
  424. IPHeader *pNewHeader;
  425. FWContext *pFWC;
  426. ULONG ulDataLength, ulCopyBufLen;
  427. ULONG ulDataLeft, ulNumBufs;
  428. PVOID pvCopyPtr;
  429. NDIS_STATUS nsStatus;
  430. PNDIS_PACKET pnpNewPacket;
  431. PNDIS_BUFFER pnbNewBuffer, pnbCopyBuffer;
  432. #if DBG
  433. ULONG ulBufCopied;
  434. #endif
  435. UNREFERENCED_PARAMETER(byDestType);
  436. EnterDriverWithStatus(FALSE);
  437. TraceEnter(RCV, "IPMForwardAfterRcv");
  438. pInIf = pPrimarySrcNte->nte_if;
  439. RtAssert(pInIf isnot &DummyInterface);
  440. DumpIpHeader(RCV, INFO, pHeader);
  441. Trace(RCV, INFO,
  442. ("IPMForwardAfterRcv: Incoming interface at 0x%x is %d\n",
  443. pInIf, pInIf->if_index));
  444. //
  445. // Lookup the (S,G) entry and see if this needs to be discarded, if so
  446. // throw it away
  447. //
  448. pSource = FindSGEntry(pHeader->iph_src,
  449. pHeader->iph_dest);
  450. if(pSource isnot NULL)
  451. {
  452. Trace(RCV, TRACE,
  453. ("IPMForwardAfterRcv: Found Source at 0x%x. In i/f is 0x%x. State is %x\n",
  454. pSource, pSource->pInIpIf, pSource->byState));
  455. //
  456. // If the source doesnt exist we will do the right thing
  457. // in IPMForwardPkt()
  458. //
  459. switch(pSource->byState)
  460. {
  461. case MFE_UNINIT:
  462. {
  463. pSource->ulInPkts++;
  464. pSource->ulInOctets += net_short(pHeader->iph_length);
  465. pSource->ulUninitMfe++;
  466. #pragma warning(push)
  467. #pragma warning(disable:4127) // conditional expression is constant
  468. RtAssert(FALSE);
  469. #pragma warning(pop)
  470. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  471. DereferenceSource(pSource);
  472. TraceLeave(RCV, "IPMForwardAfterRcv");
  473. ExitDriver();
  474. return TRUE;
  475. }
  476. case MFE_NEGATIVE:
  477. {
  478. Trace(RCV, TRACE,
  479. ("IPMForwardAfterRcv: Negative MFE \n"));
  480. pSource->ulInPkts++;
  481. pSource->ulInOctets += net_short(pHeader->iph_length);
  482. pSource->ulNegativeMfe++;
  483. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  484. DereferenceSource(pSource);
  485. TraceLeave(RCV, "IPMForwardAfterRcv");
  486. ExitDriver();
  487. return TRUE;
  488. }
  489. case MFE_QUEUE:
  490. {
  491. //
  492. // if we are going to drop the packet, may as well do it
  493. // now, before we allocate and resources
  494. //
  495. if(pSource->ulNumPending >= MAX_PENDING)
  496. {
  497. pSource->ulInPkts++;
  498. pSource->ulQueueOverflow++;
  499. pSource->ulInOctets += net_short(pHeader->iph_length);
  500. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  501. DereferenceSource(pSource);
  502. Trace(RCV, INFO,
  503. ("IPMForwardAfterRcv: MFE Queue is full\n"));
  504. TraceLeave(RCV, "IPMForwardAfterRcv");
  505. ExitDriver();
  506. return FALSE;
  507. }
  508. break;
  509. }
  510. case MFE_INIT:
  511. {
  512. if(pInIf isnot pSource->pInIpIf)
  513. {
  514. UpdateActivityTime(pSource);
  515. //
  516. // See if we need to generate a wrong i/f upcall
  517. //
  518. ProcessWrongIfUpcall(pInIf,
  519. pSource,
  520. pLink,
  521. pHeader,
  522. ulHeaderLength,
  523. NULL,
  524. 0,
  525. pvData,
  526. ulBufferLength);
  527. //
  528. // If the packet shouldnt be accepted - stop now
  529. //
  530. if(!(pInIf->if_mcastflags & IPMCAST_IF_ACCEPT_ALL))
  531. {
  532. pSource->ulInPkts++;
  533. pSource->ulInOctets += net_short(pHeader->iph_length);
  534. pSource->ulPktsDifferentIf++;
  535. Trace(RCV, ERROR,
  536. ("IPMForwardAfterRcv: Pkt from %d.%d.%d.%d to %d.%d.%d.%d came in on 0x%x instead of 0x%x\n",
  537. PRINT_IPADDR(pHeader->iph_src),
  538. PRINT_IPADDR(pHeader->iph_dest),
  539. pInIf ? pInIf->if_index : 0,
  540. pSource->pInIpIf ? pSource->pInIpIf->if_index : 0));
  541. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  542. DereferenceSource(pSource);
  543. Trace(RCV, TRACE,
  544. ("IPMForwardAfterRcv: RPF failed \n"));
  545. TraceLeave(RCV, "IPMForwardAfterRcv");
  546. ExitDriver();
  547. return TRUE;
  548. }
  549. }
  550. break;
  551. }
  552. default:
  553. {
  554. #pragma warning(push)
  555. #pragma warning(disable:4127) // conditional expression is constant
  556. RtAssert(FALSE);
  557. #pragma warning(pop)
  558. break;
  559. }
  560. }
  561. }
  562. //
  563. // We have come in through Receive Indication, means we dont
  564. // have ownership of the packet. So we copy out to our
  565. // own packet
  566. //
  567. //
  568. // Get a header for the packet. We use the incoming interface as
  569. // the IF
  570. //
  571. if((pNewHeader = GetFWPacket(&pnpNewPacket)) is NULL)
  572. {
  573. if(pSource)
  574. {
  575. pSource->ulInDiscards++;
  576. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  577. DereferenceSource(pSource);
  578. }
  579. Trace(RCV, ERROR,
  580. ("IPMForwardAfterRcv: Unable to get new packet/header \n"));
  581. //
  582. // Could not get a packet. We have not allocated anything as yet
  583. // so just bail out
  584. //
  585. IPSInfo.ipsi_indiscards++;
  586. TraceLeave(RCV, "IPMForwardAfterRcv");
  587. ExitDriver();
  588. return FALSE;
  589. }
  590. //
  591. // Should see which is more effecient - RtlCopyMemory or structure
  592. // assignment
  593. //
  594. RtlCopyMemory(pNewHeader,
  595. pHeader,
  596. sizeof(IPHeader));
  597. //
  598. // Macro defined above
  599. //
  600. #if MCAST_COMP_DBG
  601. Trace(FWD, INFO, ("IPMForwardAfterRcv: New Packet 0x%x New Header 0x%x\n",pnpNewPacket, pNewHeader));
  602. ((PacketContext *)pnpNewPacket->ProtocolReserved)->PCFLAGS |= PACKET_FLAG_IPMCAST;
  603. #endif
  604. InitForwardContext();
  605. if(ulHeaderLength isnot sizeof(IPHeader))
  606. {
  607. //
  608. // We have options, Do the Right Thing (TM)
  609. //
  610. nsStatus = ProcessOptions(pFWC,
  611. ulHeaderLength,
  612. pHeader);
  613. if(nsStatus isnot NDIS_STATUS_SUCCESS)
  614. {
  615. //
  616. // No ICMP packet if we fail
  617. //
  618. if(pSource)
  619. {
  620. pSource->ulInHdrErrors++;
  621. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  622. DereferenceSource(pSource);
  623. }
  624. IPSInfo.ipsi_inhdrerrors++;
  625. #if MCAST_BUG_TRACKING
  626. pFWC->fc_mtu = __LINE__;
  627. #endif
  628. FreeFWPacket(pnpNewPacket);
  629. ExitDriver();
  630. return TRUE;
  631. }
  632. }
  633. //
  634. // Total size of the IP Datagram sans header and options
  635. //
  636. ulDataLength = net_short(pHeader->iph_length) - ulHeaderLength;
  637. pFWC->fc_datalength = ulDataLength;
  638. //
  639. // Get the buffers for the packet. This routine
  640. // chains the buffers to the front of the packet
  641. //
  642. if (!ulDataLength)
  643. {
  644. pnbNewBuffer = NULL;
  645. ulNumBufs = 0;
  646. nsStatus = STATUS_SUCCESS;
  647. }
  648. else
  649. {
  650. nsStatus = AllocateCopyBuffers(pnpNewPacket,
  651. ulDataLength,
  652. &pnbNewBuffer,
  653. &ulNumBufs);
  654. }
  655. if(nsStatus isnot STATUS_SUCCESS)
  656. {
  657. if(pSource)
  658. {
  659. pSource->ulInDiscards++;
  660. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  661. DereferenceSource(pSource);
  662. }
  663. Trace(RCV, ERROR,
  664. ("IPMForwardAfterRcv: Unable to allocate buffers for copying\n"));
  665. //
  666. // At this point we have allocate the packet and possibly, space
  667. // for options. FreeFWPacket takes care of all that provided
  668. // the fc_options points to the options. It however does not
  669. // clear the option flag
  670. //
  671. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  672. #if MCAST_BUG_TRACKING
  673. pFWC->fc_mtu = __LINE__;
  674. #endif
  675. FreeFWPacket(pnpNewPacket);
  676. IPSInfo.ipsi_indiscards++;
  677. TraceLeave(RCV, "IPMForwardAfterRcv");
  678. ExitDriver();
  679. return FALSE;
  680. }
  681. //
  682. // See if the packet requires a transfer data
  683. //
  684. if(ulDataLength <= ulBufferLength)
  685. {
  686. Trace(RCV, TRACE,
  687. ("IPMForwardAfterRcv: All data is present, copying\n"));
  688. //
  689. // Everything here copy and call the main forwarding function
  690. //
  691. pnbCopyBuffer = pnbNewBuffer;
  692. ulDataLeft = ulDataLength;
  693. #if DBG
  694. ulBufCopied = 0;
  695. #endif
  696. while(ulDataLeft)
  697. {
  698. //
  699. // TODO: This is inefficient. Figure out a better way.
  700. //
  701. TcpipQueryBuffer(pnbCopyBuffer,
  702. &pvCopyPtr,
  703. (PUINT) &ulCopyBufLen,
  704. NormalPagePriority);
  705. if(pvCopyPtr is NULL)
  706. {
  707. nsStatus = STATUS_NO_MEMORY;
  708. break;
  709. }
  710. RtlCopyMemory(pvCopyPtr,
  711. pvData,
  712. ulCopyBufLen);
  713. pvData = (PVOID)((PBYTE)pvData + ulCopyBufLen);
  714. ulDataLeft -= ulCopyBufLen;
  715. pnbCopyBuffer = NDIS_BUFFER_LINKAGE(pnbCopyBuffer);
  716. #if DBG
  717. ulBufCopied++;
  718. #endif
  719. }
  720. //
  721. // Cleanup on data copy failure.
  722. //
  723. if (nsStatus isnot STATUS_SUCCESS)
  724. {
  725. if(pSource)
  726. {
  727. pSource->ulInDiscards++;
  728. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  729. DereferenceSource(pSource);
  730. }
  731. Trace(RCV, ERROR,
  732. ("IPMForwardAfterRcv: Unable to copy data\n"));
  733. //
  734. // At this point we have allocate the packet and possibly, sp
  735. // for options. FreeFWPacket takes care of all that provided
  736. // the fc_options points to the options. It however does not
  737. // clear the option flag
  738. //
  739. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  740. #if MCAST_BUG_TRACKING
  741. pFWC->fc_mtu = __LINE__;
  742. #endif
  743. FreeFWPacket(pnpNewPacket);
  744. IPSInfo.ipsi_indiscards++;
  745. }
  746. else
  747. {
  748. #if DBG
  749. RtAssert(ulBufCopied is ulNumBufs);
  750. #endif
  751. nsStatus = IPMForward(pnpNewPacket,
  752. pSource,
  753. FALSE);
  754. //
  755. // Do not need to release the lock or deref source because
  756. // IPMForward would have done it
  757. //
  758. }
  759. TraceLeave(RCV, "IPMForwardAfterRcv");
  760. ExitDriver();
  761. return FALSE;
  762. }
  763. //
  764. // Either all the data is not around, or lower layer
  765. // wants to force us to do a TD
  766. //
  767. Trace(RCV, TRACE,
  768. ("IPMForwardAfterRcv: Datagram size is %d, buffer is %d. Copy flag is %s. TD needed\n",
  769. ulDataLength,
  770. ulBufferLength,
  771. (pPrimarySrcNte->nte_flags & NTE_COPY)? "SET":"CLEARED"));
  772. //
  773. // Call the transfer data function
  774. //
  775. nsStatus = (pInIf->if_transfer)(pInIf->if_lcontext,
  776. LContext1,
  777. LContext2,
  778. ulHeaderLength,
  779. ulDataLength,
  780. pnpNewPacket,
  781. &(pFWC->fc_datalength));
  782. if(nsStatus isnot NDIS_STATUS_PENDING)
  783. {
  784. if(nsStatus isnot NDIS_STATUS_SUCCESS)
  785. {
  786. if(pSource)
  787. {
  788. pSource->ulInDiscards++;
  789. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  790. DereferenceSource(pSource);
  791. }
  792. Trace(RCV, ERROR,
  793. ("IPMForwardAfterRcv: TD failed status %X\n",
  794. nsStatus));
  795. //
  796. // Failed for some reason, bail out here
  797. // Since we have allocated resources, call the send
  798. // completion routine
  799. //
  800. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  801. #if MCAST_BUG_TRACKING
  802. pFWC->fc_mtu = __LINE__;
  803. #endif
  804. FreeFWPacket(pnpNewPacket);
  805. IPSInfo.ipsi_indiscards++;
  806. TraceLeave(RCV, "IPMForwardAfterRcv");
  807. ExitDriver();
  808. return FALSE;
  809. }
  810. //
  811. // TD finished synchronously
  812. //
  813. Trace(RCV, TRACE,
  814. ("IPMForwardAfterRcv: TD returned synchronously\n"));
  815. nsStatus = IPMForward(pnpNewPacket,
  816. pSource,
  817. FALSE);
  818. //
  819. // Again, dont release or deref
  820. //
  821. TraceLeave(RCV, "IPMForwardAfterRcv");
  822. ExitDriver();
  823. return FALSE;
  824. }
  825. //
  826. // Transfer is pending
  827. //
  828. //
  829. // The source info is lost across transfers if the Xfer is not
  830. // synchronouse
  831. //
  832. if(pSource)
  833. {
  834. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  835. DereferenceSource(pSource);
  836. }
  837. Trace(RCV, TRACE,
  838. ("IPMForwardAfterRcv: TD is pending\n"));
  839. TraceLeave(RCV, "IPMForwardAfterRcv");
  840. //
  841. // DO NOT CALL EXITDRIVER() HERE SINCE THE XFER DATA IS PENDING
  842. //
  843. return FALSE;
  844. }
  845. //
  846. // MUST BE PAGED IN
  847. //
  848. #pragma alloc_text(PAGEIPMc, IPMForwardAfterRcvPkt)
  849. BOOLEAN
  850. IPMForwardAfterRcvPkt(
  851. NetTableEntry *pPrimarySrcNte,
  852. IPHeader UNALIGNED *pHeader,
  853. ULONG ulHeaderLength,
  854. PVOID pvData,
  855. ULONG ulBufferLength,
  856. NDIS_HANDLE LContext1,
  857. UINT LContext2,
  858. BYTE byDestType,
  859. UINT uiMacHeaderSize,
  860. PNDIS_BUFFER pNdisBuffer,
  861. uint *pClientCnt,
  862. LinkEntry *pLink
  863. )
  864. /*++
  865. Routine Description:
  866. This function is called from when we get a ReceivePacket indication
  867. We look up the (S,G) entry. If the entry is not present, we copy and queue
  868. the packet, and complete an IRP up to the Router Manager.
  869. If the entry is present, we do the RPF check. If it fails we toss the
  870. packet out.
  871. If the (S,G) entry is a negative cache, we discard the packet
  872. If the entry is queueing at present, we copy and queue the packet
  873. Then we create a new packet since the Miniport reserved fields are being
  874. used by the receive miniport. We set up the forwarding context and munge
  875. the old header.
  876. If there is only one outgoing interface (no need to copy), no
  877. fragmentation is needed, no demand dial needs to be done, there are no
  878. options and there is no padding put on by the lower layers, we take the
  879. fast path and send the same packet out
  880. On the slow path, we copy out the packet and header and call the main
  881. forwarding function
  882. Locks:
  883. Arguments:
  884. pPrimarySrcNte
  885. pHeader
  886. ulHeaderLength
  887. pvData
  888. ulBufferLength
  889. LContext1
  890. LContext2
  891. byDestType
  892. uiMacHeaderSize
  893. pNdisBuffer
  894. pClientCnt
  895. pLink
  896. Return Value:
  897. TRUE if the IP filter-driver needs to be notified, FALSE otherwise.
  898. --*/
  899. {
  900. Interface *pInIf;
  901. PSOURCE pSource;
  902. IPHeader *pNewHeader;
  903. FWContext *pFWC;
  904. ULONG ulBytesCopied;
  905. ULONG ulDataLength, ulSrcOffset;
  906. ULONG ulNumBufs, ulBuffCount;
  907. NDIS_STATUS nsStatus;
  908. POUT_IF pOutIf = NULL;
  909. BOOLEAN bHoldPacket;
  910. PNDIS_PACKET pnpNewPacket;
  911. PNDIS_BUFFER pnbNewBuffer;
  912. FORWARD_ACTION faAction;
  913. IPPacketFilterPtr FilterPtr;
  914. ULONG xsum;
  915. #if DBG
  916. ULONG ulPacketLength;
  917. #endif
  918. UNREFERENCED_PARAMETER(LContext2);
  919. UNREFERENCED_PARAMETER(byDestType);
  920. ulBuffCount = 0;
  921. EnterDriverWithStatus(FALSE);
  922. TraceEnter(RCV, "IPMForwardAfterRcvPkt");
  923. //
  924. // Set client count to 0 so that the lower layer doesnt
  925. // think we are holding on to the packet, if we bail out
  926. //
  927. *pClientCnt = 0;
  928. bHoldPacket = TRUE;
  929. pInIf = pPrimarySrcNte->nte_if;
  930. RtAssert(pInIf isnot &DummyInterface);
  931. DumpIpHeader(RCV, INFO, pHeader);
  932. Trace(RCV, INFO,
  933. ("IPMForwardAfterRcvPkt: Incoming interface at 0x%x is %d\n",
  934. pInIf, pInIf->if_index));
  935. //
  936. // As usual, first thing is to lookup the (S,G) entry for this packet
  937. //
  938. pSource = FindSGEntry(pHeader->iph_src,
  939. pHeader->iph_dest);
  940. if(pSource isnot NULL)
  941. {
  942. Trace(RCV, TRACE,
  943. ("IPMForwardAfterRcvPkt: Found Source at 0x%x. In i/f is 0x%x. State is %x\n",
  944. pSource, pSource->pInIpIf, pSource->byState));
  945. //
  946. // If the source doesnt exist we will do the right thing
  947. // in IPMForwardPkt()
  948. //
  949. //
  950. // We only increment statistics if we are not going to
  951. // call IPMForward().
  952. //
  953. switch(pSource->byState)
  954. {
  955. case MFE_UNINIT:
  956. {
  957. pSource->ulInPkts++;
  958. pSource->ulInOctets += net_short(pHeader->iph_length);
  959. pSource->ulUninitMfe++;
  960. #pragma warning(push)
  961. #pragma warning(disable:4127) // conditional expression is constant
  962. RtAssert(FALSE);
  963. #pragma warning(pop)
  964. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  965. DereferenceSource(pSource);
  966. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  967. ExitDriver();
  968. return TRUE;
  969. }
  970. case MFE_NEGATIVE:
  971. {
  972. Trace(RCV, TRACE,
  973. ("IPMForwardAfterRcvPkt: Negative MFE \n"));
  974. pSource->ulInPkts++;
  975. pSource->ulInOctets += net_short(pHeader->iph_length);
  976. pSource->ulNegativeMfe++;
  977. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  978. DereferenceSource(pSource);
  979. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  980. ExitDriver();
  981. return TRUE;
  982. }
  983. case MFE_QUEUE:
  984. {
  985. if(pSource->ulNumPending >= MAX_PENDING)
  986. {
  987. pSource->ulInPkts++;
  988. pSource->ulQueueOverflow++;
  989. pSource->ulInOctets += net_short(pHeader->iph_length);
  990. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  991. DereferenceSource(pSource);
  992. Trace(RCV, INFO,
  993. ("IPMForwardAfterRcvPkt: MFE Queue is full\n"));
  994. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  995. ExitDriver();
  996. return FALSE;
  997. }
  998. pOutIf = NULL;
  999. bHoldPacket = FALSE;
  1000. break;
  1001. }
  1002. case MFE_INIT:
  1003. {
  1004. if(pInIf isnot pSource->pInIpIf)
  1005. {
  1006. UpdateActivityTime(pSource);
  1007. //
  1008. // See if we need to generate a wrong i/f upcall
  1009. //
  1010. ProcessWrongIfUpcall(pInIf,
  1011. pSource,
  1012. pLink,
  1013. pHeader,
  1014. ulHeaderLength,
  1015. NULL,
  1016. 0,
  1017. pvData,
  1018. ulBufferLength);
  1019. //
  1020. // If the packet shouldnt be accepted - stop now
  1021. //
  1022. if(!(pInIf->if_mcastflags & IPMCAST_IF_ACCEPT_ALL))
  1023. {
  1024. pSource->ulInPkts++;
  1025. pSource->ulInOctets += net_short(pHeader->iph_length);
  1026. pSource->ulPktsDifferentIf++;
  1027. Trace(RCV, ERROR,
  1028. ("IPMForwardAfterRcvPkt: Pkt from %d.%d.%d.%d to %d.%d.%d.%d came in on 0x%x instead of 0x%x\n",
  1029. PRINT_IPADDR(pHeader->iph_src),
  1030. PRINT_IPADDR(pHeader->iph_dest),
  1031. pInIf ? pInIf->if_index : 0,
  1032. pSource->pInIpIf ? pSource->pInIpIf->if_index : 0));
  1033. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1034. DereferenceSource(pSource);
  1035. Trace(RCV, TRACE,
  1036. ("IPMForwardAfterRcvPkt: RPF failed \n"));
  1037. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  1038. ExitDriver();
  1039. return TRUE;
  1040. }
  1041. }
  1042. pOutIf = pSource->pFirstOutIf;
  1043. RtAssert(pOutIf);
  1044. bHoldPacket = (BOOLEAN) (pOutIf->pIpIf isnot &DummyInterface);
  1045. bHoldPacket = (BOOLEAN) (pSource->ulNumOutIf is 1);
  1046. break;
  1047. }
  1048. default:
  1049. {
  1050. #pragma warning(push)
  1051. #pragma warning(disable:4127) // conditional expression is constant
  1052. RtAssert(FALSE);
  1053. #pragma warning(pop)
  1054. break;
  1055. }
  1056. }
  1057. }
  1058. else
  1059. {
  1060. bHoldPacket = FALSE;
  1061. }
  1062. //
  1063. // Since this function was called due to ReceivePacket, we dont have
  1064. // ownership of the Protocol reserved section, so allocate a new packet
  1065. // Unfortunately, getting a new packet, causes a new header to be allocate
  1066. // but what the heck, we will go with that scheme instead of inventing
  1067. // our own buffer management
  1068. //
  1069. //
  1070. // For the interface we use the INCOMING interface.
  1071. // And we specify DestType to be DEST_REMOTE. This way the queue looked at
  1072. // is the interface queue, as opposed to the global bcast queue.
  1073. //
  1074. if((pNewHeader = GetFWPacket(&pnpNewPacket)) is NULL)
  1075. {
  1076. if(pSource)
  1077. {
  1078. pSource->ulInDiscards++;
  1079. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1080. DereferenceSource(pSource);
  1081. }
  1082. //
  1083. // Could not get a packet. We have not allocated anything as yet
  1084. // so just bail out
  1085. //
  1086. IPSInfo.ipsi_indiscards++;
  1087. Trace(RCV, ERROR,
  1088. ("IPMForwardAfterRcvPkt: Unable to get new packet/header\n"));
  1089. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  1090. ExitDriver();
  1091. return FALSE;
  1092. }
  1093. //
  1094. // So we have a new packet. Fix up the packet
  1095. // Save the packet forwarding context info.
  1096. //
  1097. #if MCAST_COMP_DBG
  1098. Trace(FWD, INFO, ("IPMForwardAfterRcvPkt: New Packet 0x%x New Header 0x%x\n",pnpNewPacket, pNewHeader));
  1099. ((PacketContext *)pnpNewPacket->ProtocolReserved)->PCFLAGS |= PACKET_FLAG_IPMCAST;
  1100. #endif
  1101. InitForwardContext();
  1102. if(ulHeaderLength isnot sizeof(IPHeader))
  1103. {
  1104. nsStatus = ProcessOptions(pFWC,
  1105. ulHeaderLength,
  1106. pHeader);
  1107. if(nsStatus isnot NDIS_STATUS_SUCCESS)
  1108. {
  1109. if(pSource)
  1110. {
  1111. pSource->ulInHdrErrors++;
  1112. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1113. DereferenceSource(pSource);
  1114. }
  1115. IPSInfo.ipsi_inhdrerrors++;
  1116. #if MCAST_BUG_TRACKING
  1117. pFWC->fc_mtu = __LINE__;
  1118. #endif
  1119. FreeFWPacket(pnpNewPacket);
  1120. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  1121. ExitDriver();
  1122. return TRUE;
  1123. }
  1124. bHoldPacket = FALSE;
  1125. }
  1126. ulDataLength = net_short(pHeader->iph_length) - ulHeaderLength;
  1127. pFWC->fc_datalength = ulDataLength;
  1128. //
  1129. // Now we can try for the fast forward path. For that
  1130. // (i) we should have a complete MFE
  1131. // (ii) the number of outgoing interface should be 1
  1132. // (iii) fragmentation should not be needed
  1133. // (iv) the lower layer driver should not be running out of buffers,
  1134. // (v) no demand dial should be necessary
  1135. // (vi) no options should be present
  1136. // (vii) IMPORTANT - there is no padding at the end of the buffer
  1137. //
  1138. if((bHoldPacket) and
  1139. (net_short(pHeader->iph_length) <= (USHORT)(pOutIf->pIpIf->if_mtu)) and
  1140. (NDIS_GET_PACKET_STATUS((PNDIS_PACKET)LContext1) isnot NDIS_STATUS_RESOURCES))
  1141. {
  1142. RtAssert(pOutIf->pNextOutIf is NULL);
  1143. RtAssert(pSource);
  1144. RtAssert(pOutIf->pIpIf isnot &DummyInterface);
  1145. RtAssert(!pFWC->fc_options);
  1146. #if DBG
  1147. if(pFWC->fc_options)
  1148. {
  1149. RtAssert(pFWC->fc_optlength);
  1150. RtAssert(pFWC->FCFLAGS & PACKET_FLAG_OPTIONS);
  1151. }
  1152. else
  1153. {
  1154. RtAssert(pFWC->fc_optlength is 0);
  1155. RtAssert(!(pFWC->FCFLAGS & PACKET_FLAG_OPTIONS));
  1156. }
  1157. #endif
  1158. Trace(FWD, INFO,
  1159. ("IPMForwardAfterRcvPkt: Fast Forwarding packet\n"));
  1160. pFWC->fc_bufown = LContext1;
  1161. pFWC->fc_MacHdrSize = uiMacHeaderSize;
  1162. pFWC->fc_nexthop = pOutIf->dwNextHopAddr;
  1163. //
  1164. // Munge ttl and xsum fields
  1165. //
  1166. pHeader->iph_ttl--;
  1167. if(pHeader->iph_ttl < pOutIf->pIpIf->if_mcastttl)
  1168. {
  1169. //
  1170. // TTL is lower than scope
  1171. //
  1172. InterlockedIncrement((PLONG) &(pOutIf->ulTtlTooLow));
  1173. Trace(FWD, WARN,
  1174. ("IPMForwardAfterRcvPkt: Packet ttl is %d, I/f ttl is %d. Dropping\n",
  1175. pHeader->iph_ttl,
  1176. pOutIf->pIpIf->if_mcastttl));
  1177. //
  1178. // Here we always have a source
  1179. //
  1180. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1181. DereferenceSource(pSource);
  1182. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  1183. ExitDriver();
  1184. return TRUE;
  1185. }
  1186. xsum = pHeader->iph_xsum + 1;
  1187. xsum = (ushort)(xsum + (xsum >> 16));
  1188. pHeader->iph_xsum = (USHORT)xsum;
  1189. //
  1190. // See if we need to filter
  1191. //
  1192. if(RefPtrValid(&FilterRefPtr))
  1193. {
  1194. //
  1195. // We have a pointer to the header and we have
  1196. // a pointer to the data - alles ok
  1197. //
  1198. FilterPtr = AcquireRefPtr(&FilterRefPtr);
  1199. faAction = (*FilterPtr) (pHeader, pvData, ulBufferLength,
  1200. pInIf->if_index, pOutIf->pIpIf->if_index,
  1201. NULL_IP_ADDR, NULL_IP_ADDR);
  1202. ReleaseRefPtr(&FilterRefPtr);
  1203. if(faAction isnot FORWARD)
  1204. {
  1205. InterlockedIncrement((PLONG) &(pOutIf->ulOutDiscards));
  1206. //
  1207. // We are assured of a source
  1208. //
  1209. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1210. DereferenceSource(pSource);
  1211. //DerefIF(IF);
  1212. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  1213. ExitDriver();
  1214. return FALSE;
  1215. }
  1216. }
  1217. //
  1218. // Adjust incoming mdl pointer and counts
  1219. //
  1220. NdisAdjustBuffer(
  1221. pNdisBuffer,
  1222. (PCHAR) NdisBufferVirtualAddress(pNdisBuffer) + uiMacHeaderSize,
  1223. NdisBufferLength(pNdisBuffer) - uiMacHeaderSize
  1224. );
  1225. //
  1226. // Now link this mdl to the packet
  1227. //
  1228. pnpNewPacket->Private.Head = pNdisBuffer;
  1229. pnpNewPacket->Private.Tail = pNdisBuffer;
  1230. RtAssert(pNdisBuffer->Next is NULL);
  1231. pnpNewPacket->Private.TotalLength = ulDataLength + ulHeaderLength;
  1232. pnpNewPacket->Private.Count = 1;
  1233. UpdateActivityTime(pSource);
  1234. //
  1235. // Let go of the lock
  1236. //
  1237. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1238. //
  1239. // Mark the packet as not being loop-backed
  1240. //
  1241. NdisSetPacketFlags(pnpNewPacket,
  1242. NDIS_FLAGS_DONT_LOOPBACK);
  1243. nsStatus = (*(pOutIf->pIpIf->if_xmit))(pOutIf->pIpIf->if_lcontext,
  1244. &pnpNewPacket,
  1245. 1,
  1246. pOutIf->dwNextHopAddr,
  1247. NULL,
  1248. NULL);
  1249. if(nsStatus isnot NDIS_STATUS_PENDING)
  1250. {
  1251. Trace(FWD, INFO,
  1252. ("IPMForwardAfterRcvPkt: Fast Forward completed with status %x\n",
  1253. nsStatus));
  1254. NdisAdjustBuffer(
  1255. pNdisBuffer,
  1256. (PCHAR) NdisBufferVirtualAddress(pNdisBuffer) - uiMacHeaderSize,
  1257. NdisBufferLength(pNdisBuffer) + uiMacHeaderSize
  1258. );
  1259. pnpNewPacket->Private.Head = NULL;
  1260. pnpNewPacket->Private.Tail = NULL;
  1261. pFWC->fc_bufown = NULL;
  1262. //
  1263. // Since client count is 0
  1264. // we dont need to call FWSendComplete
  1265. //
  1266. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  1267. #if MCAST_BUG_TRACKING
  1268. pFWC->fc_mtu = __LINE__;
  1269. #endif
  1270. FreeFWPacket(pnpNewPacket);
  1271. }
  1272. else
  1273. {
  1274. //
  1275. // Okay, the xmit is pending indicate this to ndis.
  1276. //
  1277. *pClientCnt = 1;
  1278. }
  1279. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  1280. ExitDriver();
  1281. return FALSE;
  1282. }
  1283. //
  1284. // Copy the header out at this point because if we get into
  1285. // the fast path, the copy would be a waste
  1286. //
  1287. RtlCopyMemory(pNewHeader,
  1288. pHeader,
  1289. sizeof(IPHeader));
  1290. //
  1291. // Good old slow path. We already have the header, allocate and copy
  1292. // out the data and pass it to the main function
  1293. //
  1294. if (!ulDataLength)
  1295. {
  1296. ulNumBufs = 0;
  1297. pnbNewBuffer = NULL;
  1298. nsStatus = STATUS_SUCCESS;
  1299. }
  1300. else
  1301. {
  1302. nsStatus = AllocateCopyBuffers(pnpNewPacket,
  1303. ulDataLength,
  1304. &pnbNewBuffer,
  1305. &ulNumBufs);
  1306. }
  1307. if(nsStatus isnot STATUS_SUCCESS)
  1308. {
  1309. if(pSource)
  1310. {
  1311. pSource->ulInDiscards++;
  1312. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1313. DereferenceSource(pSource);
  1314. }
  1315. Trace(RCV, ERROR,
  1316. ("IPMForwardAfterRcvPkt: Unable to allocate buffers for copying\n"));
  1317. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  1318. IPSInfo.ipsi_indiscards++;
  1319. #if MCAST_BUG_TRACKING
  1320. pFWC->fc_mtu = __LINE__;
  1321. #endif
  1322. FreeFWPacket(pnpNewPacket);
  1323. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  1324. ExitDriver();
  1325. return FALSE;
  1326. }
  1327. //
  1328. // Now we have a MDL chain which we need to copy to a chain of NDIS buffers
  1329. // which is nothing but another MDL chain.
  1330. // We want to copy out only the data. So we need to start after the
  1331. // header but copy to the beginning of the destination buffer
  1332. //
  1333. ulSrcOffset = ulHeaderLength + (ULONG)uiMacHeaderSize;
  1334. nsStatus = TdiCopyMdlChainToMdlChain(pNdisBuffer,
  1335. ulSrcOffset,
  1336. pnbNewBuffer,
  1337. 0,
  1338. &ulBytesCopied);
  1339. if (nsStatus isnot STATUS_SUCCESS)
  1340. {
  1341. ULONG ulNdisPktSize;
  1342. NdisQueryPacket(pnpNewPacket,
  1343. NULL,
  1344. NULL,
  1345. NULL,
  1346. (PUINT) &ulNdisPktSize);
  1347. //
  1348. // Some problem here
  1349. //
  1350. if(pSource)
  1351. {
  1352. pSource->ulInDiscards++;
  1353. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1354. DereferenceSource(pSource);
  1355. }
  1356. Trace(RCV,ERROR,
  1357. ("IPMForwardAfterRcvPkt: Copying chain with offset %d to %d sized MDL-chain returned %x with %d bytes copied\n",
  1358. ulSrcOffset,
  1359. ulNdisPktSize,
  1360. nsStatus,
  1361. ulBytesCopied));
  1362. //
  1363. // Free options and option buffer if any
  1364. //
  1365. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  1366. IPSInfo.ipsi_indiscards++;
  1367. #if MCAST_BUG_TRACKING
  1368. pFWC->fc_mtu = __LINE__;
  1369. #endif
  1370. FreeFWPacket(pnpNewPacket);
  1371. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  1372. ExitDriver();
  1373. return FALSE;
  1374. }
  1375. #if DBG
  1376. NdisQueryPacket(pnpNewPacket,
  1377. NULL,
  1378. (PUINT) &ulBuffCount,
  1379. NULL,
  1380. (PUINT) &ulPacketLength);
  1381. RtAssert(ulBuffCount is ulNumBufs);
  1382. RtAssert(ulPacketLength is ulBytesCopied);
  1383. #endif
  1384. nsStatus = IPMForward(pnpNewPacket,
  1385. pSource,
  1386. FALSE);
  1387. //
  1388. // Dont release or deref
  1389. //
  1390. TraceLeave(RCV, "IPMForwardAfterRcvPkt");
  1391. ExitDriver();
  1392. return FALSE;
  1393. }
  1394. //
  1395. // MUST BE PAGED IN
  1396. //
  1397. #pragma alloc_text(PAGEIPMc, IPMForward)
  1398. NTSTATUS
  1399. IPMForward(
  1400. IN PNDIS_PACKET pnpPacket,
  1401. IN PSOURCE pSource OPTIONAL,
  1402. IN BOOLEAN bSendFromQueue
  1403. )
  1404. /*++
  1405. Routine Description:
  1406. This is the main multicast forwarding routine. It is called from
  1407. the three top level forwarding routines (IPMForwardAfterRcv,
  1408. IPMForwardAfterRcvPkt and IPMForwardAfterTD)
  1409. It is always called with a complete packet (either one buffer or chained
  1410. buffers) and we always have final ownership of the packet.
  1411. The NDIS_PACKET for the datagram must be a FWPacket and must be
  1412. chained when this function is called. The various parts of the data are:
  1413. Comp Size Allocated in Stored at
  1414. ---------------------------------------------------------------
  1415. Header sizeof(IPHeader) GrowFWPacket fc_hbuff
  1416. Hdr Buffer NDIS_BUFFER GrowFWPacket fc_hndisbuff
  1417. Options fc_optlength ForwardAfterRcv fc_option
  1418. ForwardAfterRcvPkt
  1419. Opt Buffer NDIS_BUFFER SendIPPacket (later) 2nd buffer if
  1420. ..FLAG_OPTIONS is set
  1421. Data fc_datalength ForwardAfterRcv fc_buffhead
  1422. ForwardAfterRcvPkt
  1423. The data is also chained to the NDIS_PACKET as the first buffer
  1424. The NDIS_PACKET must have the FWContext all setup before this routine
  1425. is called. All necessary information is retrieved using the FWC
  1426. All this chaining needs to be undone in the routine, since SendIPPacket()
  1427. requires an unchained buffer.
  1428. We first try and find an (S,G) entry if one is not already passed to us.
  1429. If we dont have an entry, then we copy and queue the packet while
  1430. sending a notification to Router Manager. As as side effect an entry with
  1431. a state of QUEUEING gets created so that other packets coming in just get
  1432. queued here.
  1433. If we do find an entry, then according to the state of the entry, we
  1434. either drop the packet, queue it or continue processing it.
  1435. We do an RPF check and if that fails, the packet is dropped.
  1436. Since we may potentially duplicate the packet (or even fragment it), we
  1437. allocate a BufferReference. The BuffRef keeps track of the ORIGINAL
  1438. BUFFERS. These are the ones that point to the data and were allocated
  1439. out of our FWBuffer pool.
  1440. We copy out the headers and options into a flat buffer to use with
  1441. Filtering callout.
  1442. Then for each IF on the outgoing list:
  1443. We get a pointer to the primary NTE. This is needed to process options
  1444. since we need the address of the outgoing interface
  1445. For all but the last interface, we allocate a new header and new
  1446. packet. (For the last interface we use the packet and header that was
  1447. passed to us in this routine. So for the last interface, the packet,
  1448. header, options and buffer descriptors come from the FWPacket/Buffer
  1449. pool, where as for all other interfaces, the header and packet are
  1450. plain IP buffers and the memory for options is allocated in this
  1451. routine.)
  1452. If there are options, we allocate memory for the options and update
  1453. them.
  1454. Then we see if the packet needs to be fragmented. To do this we use
  1455. the MTU of the outgoing interface. This is different from UNICAST
  1456. where we used the mtu in the route - because that is where the
  1457. updated mtu from PathMTU discovery is kept. Since we dont do path
  1458. MTU discovery for multicast, we just use the MTU of the outgoing i/f
  1459. So if the IP Data length + OptionSize + Header Size > if_mtu, we
  1460. call IPFragment(), otherwise we send the packet out using
  1461. SendIPPacket().
  1462. For each pending send from SendIPPacket(), we increase the refcount
  1463. on the BuffRef. IPFragment() may increase the refcount by more than
  1464. 1 for each call because it breaks the packet into two or more packets.
  1465. NOTE: We pass the original data buffers to SendIPPacket() and to
  1466. IPFragment(). This way we only copy out the header and the options. This
  1467. is better than HenrySa's SendIPBCast() which copies out the whole data.
  1468. Locks:
  1469. This code is assumed to run at DPCLevel. If a PSOURCE is passed to the
  1470. function, it is assumed to be Referenced and Locked.
  1471. Arguments:
  1472. pnpPacket
  1473. pSource
  1474. bSendFromQueue
  1475. Return Value:
  1476. STATUS_SUCCESS
  1477. --*/
  1478. {
  1479. NetTableEntry *pPrimarySrcNte, *pOutNte;
  1480. IPHeader *pHeader, *pNewHeader;
  1481. FWContext *pFWC;
  1482. PNDIS_PACKET pnpNewPacket;
  1483. PNDIS_BUFFER pnbDataBuffer;
  1484. PBYTE pbyNewOptions;
  1485. POUT_IF pOutIf;
  1486. BufferReference *pBuffRef;
  1487. NTSTATUS nsStatus;
  1488. ULONG ulDataLength, ulSent;
  1489. PacketContext *pPC;
  1490. FORWARD_ACTION faAction;
  1491. IPPacketFilterPtr FilterPtr;
  1492. PVOID pvData;
  1493. UINT uiFirstBufLen;
  1494. Interface *pInIf;
  1495. DWORD dwNewIndex;
  1496. INT iBufRefCount;
  1497. LinkEntry *pLink;
  1498. #if DBG
  1499. PNDIS_BUFFER pnpFirstBuffer;
  1500. ULONG ulTotalPacketLength, ulTotalHdrLength;
  1501. #endif
  1502. TraceEnter(FWD, "IPMForward");
  1503. #if DBG
  1504. //
  1505. // Lets make sure that this is a forwardable multicast
  1506. //
  1507. #endif
  1508. pFWC = (FWContext *)pnpPacket->ProtocolReserved;
  1509. pPrimarySrcNte = pFWC->fc_srcnte;
  1510. pInIf = pPrimarySrcNte->nte_if;
  1511. pHeader = pFWC->fc_hbuff;
  1512. ulDataLength = pFWC->fc_datalength;
  1513. pnbDataBuffer = pFWC->fc_buffhead;
  1514. pLink = pFWC->fc_iflink;
  1515. //
  1516. // Check to make sure the buffer and packets are
  1517. // as we expect
  1518. //
  1519. RtAssert(pPrimarySrcNte);
  1520. RtAssert(pHeader);
  1521. //
  1522. // Setup pvData to point to the first part of the data
  1523. // so that the filter driver can get to it in a flat
  1524. // buffer
  1525. //
  1526. if (!pnbDataBuffer)
  1527. {
  1528. pvData = NULL;
  1529. uiFirstBufLen = 0;
  1530. }
  1531. else
  1532. {
  1533. TcpipQueryBuffer(pnbDataBuffer,
  1534. &pvData,
  1535. &uiFirstBufLen,
  1536. NormalPagePriority);
  1537. if(pvData is NULL)
  1538. {
  1539. Trace(FWD, ERROR,
  1540. ("IPMForward: failed to query data buffer.\n"));
  1541. IPSInfo.ipsi_indiscards++;
  1542. if(pSource)
  1543. {
  1544. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1545. DereferenceSource(pSource);
  1546. }
  1547. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  1548. #if MCAST_BUG_TRACKING
  1549. pFWC->fc_mtu = __LINE__;
  1550. #endif
  1551. FreeFWPacket(pnpPacket);
  1552. TraceLeave(FWD, "IPMForward");
  1553. return STATUS_NO_MEMORY;
  1554. }
  1555. }
  1556. #if DBG
  1557. if(pFWC->fc_options)
  1558. {
  1559. RtAssert(pFWC->fc_optlength);
  1560. RtAssert(pFWC->FCFLAGS & PACKET_FLAG_OPTIONS);
  1561. }
  1562. else
  1563. {
  1564. RtAssert(pFWC->fc_optlength is 0);
  1565. RtAssert(!(pFWC->FCFLAGS & PACKET_FLAG_OPTIONS));
  1566. }
  1567. //
  1568. // "To make assurance doubly sure." Extra points to the person
  1569. // who gets the quote
  1570. //
  1571. NdisQueryPacket(pnpPacket,
  1572. NULL,
  1573. NULL,
  1574. &pnpFirstBuffer,
  1575. (PUINT) &ulTotalPacketLength);
  1576. RtAssert(pnpFirstBuffer is pFWC->fc_buffhead);
  1577. RtAssert(ulTotalPacketLength is ulDataLength);
  1578. ulTotalHdrLength = sizeof(IPHeader) + pFWC->fc_optlength;
  1579. ulTotalPacketLength = net_short(pHeader->iph_length) - ulTotalHdrLength;
  1580. RtAssert(ulTotalPacketLength is ulDataLength);
  1581. #endif
  1582. if(!ARGUMENT_PRESENT(pSource))
  1583. {
  1584. //
  1585. // This happens when we come through the TD path or
  1586. // when dont have a (S,G) entry in our MFIB
  1587. //
  1588. pSource = FindSGEntry(pHeader->iph_src,
  1589. pHeader->iph_dest);
  1590. }
  1591. if(pSource is NULL)
  1592. {
  1593. Trace(FWD, INFO,
  1594. ("IPMForward: No (S,G,) entry found\n"));
  1595. //
  1596. // Invoke the IP filter driver.
  1597. //
  1598. if (RefPtrValid(&FilterRefPtr))
  1599. {
  1600. ASSERT(!bSendFromQueue);
  1601. FilterPtr = AcquireRefPtr(&FilterRefPtr);
  1602. faAction = (*FilterPtr) (pHeader, pvData, uiFirstBufLen,
  1603. pPrimarySrcNte->nte_if->if_index,
  1604. INVALID_IF_INDEX,
  1605. NULL_IP_ADDR, NULL_IP_ADDR);
  1606. ReleaseRefPtr(&FilterRefPtr);
  1607. if(faAction != FORWARD)
  1608. {
  1609. Trace(FWD, INFO,
  1610. ("IPMForward: Filter returned %d\n",
  1611. faAction));
  1612. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  1613. FreeFWPacket(pnpPacket);
  1614. TraceLeave(FWD, "IPMForward");
  1615. return STATUS_SUCCESS;
  1616. }
  1617. }
  1618. //
  1619. // No S found, create one, copy and queue the packet
  1620. // and complete and IRP to the router manager
  1621. //
  1622. nsStatus = CreateSourceAndQueuePacket(pHeader->iph_dest,
  1623. pHeader->iph_src,
  1624. pInIf->if_index,
  1625. pLink,
  1626. pnpPacket);
  1627. //
  1628. // We are not done with the packet, because it
  1629. // is queued. So we dont free it or call complete on it
  1630. //
  1631. TraceLeave(FWD, "IPMForward");
  1632. return STATUS_SUCCESS;
  1633. }
  1634. Trace(FWD, TRACE,
  1635. ("IPMForward: Source at 0x%x. In i/f is 0x%x. State is %x\n",
  1636. pSource, pSource->pInIpIf, pSource->byState));
  1637. pSource->ulInPkts++;
  1638. pSource->ulInOctets += net_short(pHeader->iph_length);
  1639. switch(pSource->byState)
  1640. {
  1641. case MFE_UNINIT:
  1642. {
  1643. #pragma warning(push)
  1644. #pragma warning(disable:4127) // conditional expression is constant
  1645. RtAssert(FALSE);
  1646. #pragma warning(pop)
  1647. pSource->ulUninitMfe++;
  1648. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1649. DereferenceSource(pSource);
  1650. if (!bSendFromQueue) {
  1651. NotifyFilterOfDiscard(pPrimarySrcNte, pHeader, pvData,
  1652. uiFirstBufLen);
  1653. }
  1654. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  1655. #if MCAST_BUG_TRACKING
  1656. pFWC->fc_mtu = __LINE__;
  1657. #endif
  1658. FreeFWPacket(pnpPacket);
  1659. TraceLeave(RCV, "IPMForward");
  1660. return STATUS_SUCCESS;
  1661. }
  1662. case MFE_NEGATIVE:
  1663. {
  1664. //
  1665. // Throw the packet away
  1666. // IMPORTANT - DO NOT UPDATE THE ACTIVITY TIMESTAMP
  1667. // otherwise the upper layer protocols will never see the
  1668. // packets from this
  1669. //
  1670. pSource->ulNegativeMfe++;
  1671. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1672. DereferenceSource(pSource);
  1673. if (!bSendFromQueue) {
  1674. NotifyFilterOfDiscard(pPrimarySrcNte, pHeader, pvData,
  1675. uiFirstBufLen);
  1676. }
  1677. Trace(FWD, INFO,
  1678. ("IPMForward: MFE is negative, so discarding packet\n"));
  1679. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  1680. #if MCAST_BUG_TRACKING
  1681. pFWC->fc_mtu = __LINE__;
  1682. #endif
  1683. FreeFWPacket(pnpPacket);
  1684. TraceLeave(FWD, "IPMForward");
  1685. return STATUS_SUCCESS;
  1686. }
  1687. case MFE_QUEUE:
  1688. {
  1689. //
  1690. // Invoke the IP filter driver.
  1691. //
  1692. if (RefPtrValid(&FilterRefPtr))
  1693. {
  1694. ASSERT(!bSendFromQueue);
  1695. FilterPtr = AcquireRefPtr(&FilterRefPtr);
  1696. faAction = (*FilterPtr) (pHeader, pvData, uiFirstBufLen,
  1697. pPrimarySrcNte->nte_if->if_index,
  1698. INVALID_IF_INDEX,
  1699. NULL_IP_ADDR, NULL_IP_ADDR);
  1700. ReleaseRefPtr(&FilterRefPtr);
  1701. if(faAction != FORWARD)
  1702. {
  1703. Trace(FWD, INFO,
  1704. ("IPMForward: Filter returned %d\n",
  1705. faAction));
  1706. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  1707. FreeFWPacket(pnpPacket);
  1708. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1709. DereferenceSource(pSource);
  1710. TraceLeave(FWD, "IPMForward");
  1711. return STATUS_SUCCESS;
  1712. }
  1713. }
  1714. //
  1715. // Havent got a the MFE from user mode as yet, just
  1716. // queue the packet
  1717. //
  1718. Trace(RCV, INFO,
  1719. ("IPMForward: MFE is queuing\n"));
  1720. UpdateActivityTime(pSource);
  1721. //
  1722. // Dont update pSource stats, this will be done the second
  1723. // time around
  1724. //
  1725. pSource->ulInPkts--;
  1726. pSource->ulInOctets -= net_short(pHeader->iph_length);
  1727. nsStatus = QueuePacketToSource(pSource,
  1728. pnpPacket);
  1729. if(nsStatus isnot STATUS_PENDING)
  1730. {
  1731. pSource->ulInPkts++;
  1732. pSource->ulInOctets += net_short(pHeader->iph_length);
  1733. pSource->ulInDiscards++;
  1734. IPSInfo.ipsi_indiscards++;
  1735. Trace(FWD, ERROR,
  1736. ("IPMForward: QueuePacketToSource returned %x\n",
  1737. nsStatus));
  1738. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  1739. #if MCAST_BUG_TRACKING
  1740. pFWC->fc_mtu = __LINE__;
  1741. #endif
  1742. FreeFWPacket(pnpPacket);
  1743. }
  1744. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1745. DereferenceSource(pSource);
  1746. TraceLeave(RCV, "IPMForward");
  1747. return nsStatus;
  1748. }
  1749. #if DBG
  1750. case MFE_INIT:
  1751. {
  1752. break;
  1753. }
  1754. default:
  1755. {
  1756. #pragma warning(push)
  1757. #pragma warning(disable:4127) // conditional expression is constant
  1758. RtAssert(FALSE);
  1759. #pragma warning(pop)
  1760. break;
  1761. }
  1762. #endif
  1763. }
  1764. if(pSource->pInIpIf isnot pPrimarySrcNte->nte_if)
  1765. {
  1766. UpdateActivityTime(pSource);
  1767. //
  1768. // See if we need to generate a wrong i/f upcall
  1769. //
  1770. ProcessWrongIfUpcall(pPrimarySrcNte->nte_if,
  1771. pSource,
  1772. pLink,
  1773. pHeader,
  1774. sizeof(IPHeader),
  1775. pFWC->fc_options,
  1776. pFWC->fc_optlength,
  1777. pvData,
  1778. uiFirstBufLen);
  1779. //
  1780. // If the packet shouldnt be accepted - stop now
  1781. //
  1782. if(!(pInIf->if_mcastflags & IPMCAST_IF_ACCEPT_ALL))
  1783. {
  1784. pSource->ulPktsDifferentIf++;
  1785. Trace(RCV, ERROR,
  1786. ("IPMForward: Pkt from %d.%d.%d.%d to %d.%d.%d.%d came in on 0x%x instead of 0x%x\n",
  1787. PRINT_IPADDR(pHeader->iph_src),
  1788. PRINT_IPADDR(pHeader->iph_dest),
  1789. pInIf ? pInIf->if_index : 0,
  1790. pSource->pInIpIf ? pSource->pInIpIf->if_index : 0));
  1791. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1792. DereferenceSource(pSource);
  1793. //
  1794. // RPF check failed. Throw the packet away
  1795. //
  1796. Trace(FWD, INFO,
  1797. ("IPMForward: RPF Failed. In i/f %x (%d). RPF i/f %x (%d)\n",
  1798. pPrimarySrcNte->nte_if, pPrimarySrcNte->nte_if->if_index,
  1799. pSource->pInIpIf, pSource->pInIpIf->if_index));
  1800. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  1801. #if MCAST_BUG_TRACKING
  1802. pFWC->fc_mtu = __LINE__;
  1803. #endif
  1804. FreeFWPacket(pnpPacket);
  1805. TraceLeave(FWD, "IPMForward");
  1806. return STATUS_SUCCESS;
  1807. }
  1808. }
  1809. //
  1810. // We need to unlink the packet so that the code below works properly.
  1811. // This is kind of painful, but SendIPPacket wants a packet which has
  1812. // only the header buffer chained to it
  1813. // We do th unlinking at this point because if we do it before this and
  1814. // queue the packet, then we will hit a ton of asserts we come here
  1815. // when the queue is being drained (since then we will be unlinking twice)
  1816. //
  1817. UnlinkDataFromPacket(pnpPacket, pFWC);
  1818. //
  1819. // Zero out the XSUM
  1820. //
  1821. pHeader->iph_xsum = 0x0000;
  1822. //
  1823. // Decrement the TTL
  1824. //
  1825. pHeader->iph_ttl--;
  1826. Trace(FWD, INFO,
  1827. ("IPMForward: New TTL is %d\n",
  1828. pHeader->iph_ttl));
  1829. //
  1830. // The number of pending sends. Used later
  1831. //
  1832. ulSent = 0;
  1833. //
  1834. // Get a buffer reference. We need this if we are sending to
  1835. // more than one interface, or if we need to fragment.
  1836. // However, we always use a reference. This only increases
  1837. // memory and has no effect on the correctness
  1838. //
  1839. pBuffRef = CTEAllocMem(sizeof(BufferReference));
  1840. if(pBuffRef is NULL)
  1841. {
  1842. pSource->ulInDiscards++;
  1843. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1844. DereferenceSource(pSource);
  1845. pFWC->FCFLAGS &= ~PACKET_FLAG_OPTIONS;
  1846. #if MCAST_BUG_TRACKING
  1847. pFWC->fc_mtu = __LINE__;
  1848. #endif
  1849. FreeFWPacket(pnpPacket);
  1850. IPSInfo.ipsi_indiscards++;
  1851. Trace(FWD, ERROR,
  1852. ("IPMForward: Could not allocate memory for BuffRef\n"));
  1853. TraceLeave(FWD, "IPMForward");
  1854. return STATUS_NO_MEMORY;
  1855. }
  1856. UpdateActivityTime(pSource);
  1857. //
  1858. // Everything after this is InterlockedInc'ed
  1859. // We release the spinlock but still have the pSource refcounted.
  1860. //
  1861. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1862. //
  1863. // Initialize the BufferReference.It is init to 0. Even though
  1864. // some send completes may occur before we get a chance to bump
  1865. // the ref-count, that is not a problem because the send complete
  1866. // will cause it to go to a negative number which will not have any bad
  1867. // effect
  1868. //
  1869. pBuffRef->br_buffer = pFWC->fc_buffhead;
  1870. pBuffRef->br_refcount = 0;
  1871. CTEInitLock(&(pBuffRef->br_lock));
  1872. pPC = (PacketContext *)pnpPacket->ProtocolReserved;
  1873. pPC->pc_br = pBuffRef;
  1874. //
  1875. // Start looping through the OIFs
  1876. // We allocate a packet and a header for each interface except the last
  1877. // one. (For the last one we use the one given to us - since we own it).
  1878. // Instead of using a new buffer chain for each packet, we point to the
  1879. // old chain.
  1880. // The last packet is a FWPacket. All the others are simply IP Packets
  1881. //
  1882. for(pOutIf = pSource->pFirstOutIf;
  1883. pOutIf isnot NULL;
  1884. pOutIf = pOutIf->pNextOutIf)
  1885. {
  1886. //
  1887. // Skip it if the OIF matches the IIF
  1888. // The address check is for RAS clients.
  1889. //
  1890. if((pOutIf->pIpIf is pInIf) and
  1891. (pHeader->iph_src is pOutIf->dwNextHopAddr))
  1892. {
  1893. continue;
  1894. }
  1895. Trace(FWD, INFO,
  1896. ("IPMForward: Sending over i/f @ 0x%x\n",
  1897. pOutIf));
  1898. if(pOutIf->pIpIf is &DummyInterface)
  1899. {
  1900. Trace(FWD, INFO,
  1901. ("IPMForward: Need to dial out\n"));
  1902. //
  1903. // Need to dial out
  1904. //
  1905. if (RefPtrValid(&DODRefPtr))
  1906. {
  1907. IPMapRouteToInterfacePtr DODCallout;
  1908. //
  1909. // Dial out pointer has been plumbed
  1910. //
  1911. DODCallout = AcquireRefPtr(&DODRefPtr);
  1912. dwNewIndex = (*DODCallout)(pOutIf->dwDialContext,
  1913. pHeader->iph_dest,
  1914. pHeader->iph_src,
  1915. pHeader->iph_protocol,
  1916. pvData,
  1917. uiFirstBufLen,
  1918. pHeader->iph_src);
  1919. ReleaseRefPtr(&DODRefPtr);
  1920. if(dwNewIndex isnot INVALID_IF_INDEX)
  1921. {
  1922. //
  1923. // This puts a reference on the interface
  1924. //
  1925. pOutIf->pIpIf = GetInterfaceGivenIndex(dwNewIndex);
  1926. RtAssert(pOutIf->pIpIf isnot &DummyInterface);
  1927. RtAssert(pOutIf->pIpIf isnot &LoopInterface);
  1928. }
  1929. else
  1930. {
  1931. continue;
  1932. }
  1933. }
  1934. else
  1935. {
  1936. //
  1937. // No call out!
  1938. //
  1939. #pragma warning(push)
  1940. #pragma warning(disable:4127) // conditional expression is constant
  1941. RtAssert(FALSE);
  1942. #pragma warning(pop)
  1943. continue;
  1944. }
  1945. }
  1946. if(pHeader->iph_ttl < pOutIf->pIpIf->if_mcastttl)
  1947. {
  1948. //
  1949. // TTL would be too low, what do we send back?
  1950. //
  1951. InterlockedIncrement((PLONG) &(pOutIf->ulTtlTooLow));
  1952. Trace(FWD, WARN,
  1953. ("IPMForward: Packet ttl is %d, I/f ttl is %d. Dropping\n",
  1954. pHeader->iph_ttl, pOutIf->pIpIf->if_mcastttl));
  1955. continue;
  1956. }
  1957. //
  1958. // See if we need to filter this
  1959. //
  1960. if (RefPtrValid(&FilterRefPtr))
  1961. {
  1962. uint InIFIndex = bSendFromQueue ? INVALID_IF_INDEX
  1963. : pPrimarySrcNte->nte_if->if_index;
  1964. //
  1965. // NOTE: We use the same header and data all the time.
  1966. //
  1967. FilterPtr = AcquireRefPtr(&FilterRefPtr);
  1968. faAction = (*FilterPtr) (pHeader, pvData, uiFirstBufLen,
  1969. InIFIndex, pOutIf->pIpIf->if_index,
  1970. NULL_IP_ADDR, NULL_IP_ADDR);
  1971. ReleaseRefPtr(&FilterRefPtr);
  1972. if(faAction != FORWARD)
  1973. {
  1974. InterlockedIncrement((PLONG) &(pOutIf->ulOutDiscards));
  1975. Trace(FWD, INFO,
  1976. ("IPMForward: Filter returned %d\n",
  1977. faAction));
  1978. InterlockedIncrement((PLONG) &(pOutIf->ulOutDiscards));
  1979. //DerefIF(IF);
  1980. continue;
  1981. }
  1982. }
  1983. //
  1984. // TODO Get the primary NTE for this IF.
  1985. // right now we are picking up the first NTE
  1986. //
  1987. pOutNte = pOutIf->pIpIf->if_nte;
  1988. if(pOutNte is NULL)
  1989. {
  1990. Trace(FWD, WARN,
  1991. ("IPMForward: No NTE found for interface %x (%d)\n",
  1992. pOutIf->pIpIf, pOutIf->pIpIf->if_nte));
  1993. continue;
  1994. }
  1995. if(pOutIf->pNextOutIf)
  1996. {
  1997. Trace(FWD, INFO,
  1998. ("IPMForward: Not the last i/f - need to allocate packets\n"));
  1999. //
  2000. // Get a plain old header and packet.
  2001. //
  2002. pNewHeader = GetIPHeader(&pnpNewPacket);
  2003. if(pNewHeader is NULL)
  2004. {
  2005. Trace(FWD, ERROR,
  2006. ("IPMForward: Could not get packet/header\n"));
  2007. //
  2008. // Could not get a header and packet
  2009. //
  2010. InterlockedIncrement((PLONG) &(pOutIf->ulOutDiscards));
  2011. continue;
  2012. }
  2013. #if MCAST_COMP_DBG
  2014. Trace(FWD, INFO,
  2015. ("IPMForward: New Packet 0x%x New Header 0x%x\n",pnpNewPacket, pNewHeader));
  2016. #endif
  2017. //
  2018. // Set the packet context for all packets that are created
  2019. // here to be Non FW packets
  2020. // Note: Earlier we would also set the packet to be IPBUF, but
  2021. // now since we dont allocate buffers and instead just use the
  2022. // original buffers, we MUST not set the IPBUF flag
  2023. //
  2024. pPC = (PacketContext *)pnpNewPacket->ProtocolReserved;
  2025. //
  2026. // Copy out the context. STRUCTURE COPY
  2027. //
  2028. *pPC = pFWC->fc_pc;
  2029. pPC->PCFLAGS &= ~PACKET_FLAG_FW;
  2030. //
  2031. // Copy out the header. STRUCTURE COPY
  2032. //
  2033. *pNewHeader = *pHeader;
  2034. if(pFWC->fc_options)
  2035. {
  2036. Trace(FWD, INFO,
  2037. ("IPMForward: FWC has options at %x. Length %d\n",
  2038. pFWC->fc_options, pFWC->fc_optlength));
  2039. RtAssert(pFWC->fc_optlength);
  2040. RtAssert(pPC->PCFLAGS & PACKET_FLAG_OPTIONS);
  2041. //
  2042. // We have options, make a copy.
  2043. //
  2044. pbyNewOptions = CTEAllocMem(pFWC->fc_optlength);
  2045. if(pbyNewOptions is NULL)
  2046. {
  2047. Trace(FWD, ERROR,
  2048. ("IPMForward: Unable to allocate memory for options\n"));
  2049. //
  2050. // This gets set during the context copy
  2051. //
  2052. pPC->PCFLAGS &= ~PACKET_FLAG_OPTIONS;
  2053. FreeIPPacket(pnpNewPacket, TRUE, IP_NO_RESOURCES);
  2054. InterlockedIncrement((PLONG) &(pOutIf->ulOutDiscards));
  2055. continue;
  2056. }
  2057. RtlCopyMemory(pbyNewOptions,
  2058. pFWC->fc_options,
  2059. pFWC->fc_optlength);
  2060. }
  2061. else
  2062. {
  2063. pbyNewOptions = NULL;
  2064. RtAssert(!(pPC->PCFLAGS & PACKET_FLAG_OPTIONS));
  2065. }
  2066. // NOT NEEDED - see below
  2067. // CTEGetLockAtDPC(&RouteTableLock);
  2068. //
  2069. // pOutIf->pIpIf->if_refcount++;
  2070. // InterlockedIncrement(&(pOutIf->pIpIf->if_mfwdpktcount));
  2071. //
  2072. // CTEFreeLockFromDPC(&RouteTableLock);
  2073. //
  2074. // pPC->pc_if = pOutIf->pIpIf;
  2075. //
  2076. }
  2077. else
  2078. {
  2079. Trace(FWD, INFO,
  2080. ("IPMForward: Last i/f. Using packet 0x%x. Flags 0x%X. Opt 0x%x OptLen %d\n",
  2081. pnpPacket,
  2082. pFWC->FCFLAGS,
  2083. pFWC->fc_options,
  2084. pFWC->fc_optlength));
  2085. //
  2086. // Use the original packet, header and options
  2087. //
  2088. pnpNewPacket = pnpPacket;
  2089. pNewHeader = pHeader;
  2090. pbyNewOptions = pFWC->fc_options;
  2091. // NOT NEEDED - see below
  2092. // CTEGetLockAtDPC(&RouteTableLock);
  2093. //
  2094. // pOutIf->pIpIf->if_refcount++;
  2095. // InterlockedIncrement(&(pOutIf->pIpIf->if_mfwdpktcount));
  2096. //
  2097. // CTEFreeLockFromDPC(&RouteTableLock);
  2098. //
  2099. // pFWC->fc_if = pOutIf->pIpIf;
  2100. //
  2101. }
  2102. #if 0
  2103. UpdateOptions(pbyNewOptions,
  2104. pOptIndex,
  2105. pOutNte->nte_addr);
  2106. #endif
  2107. //
  2108. // Just need to ref across the send, not the send-sendcomplete
  2109. //
  2110. CTEGetLockAtDPC(&RouteTableLock.Lock);
  2111. LOCKED_REFERENCE_IF(pOutIf->pIpIf);
  2112. #ifdef MREF_DEBUG
  2113. InterlockedIncrement(&(pOutIf->pIpIf->if_mfwdpktcount));
  2114. #endif
  2115. CTEFreeLockFromDPC(&RouteTableLock.Lock);
  2116. if((ulDataLength + pFWC->fc_optlength) > pOutIf->pIpIf->if_mtu)
  2117. {
  2118. Trace(FWD, INFO,
  2119. ("IPMForward: Data %d Opt %d Hdr %d. MTU %d. Requires frag\n",
  2120. ulDataLength,
  2121. pFWC->fc_optlength,
  2122. sizeof(IPHeader),
  2123. pOutIf->pIpIf->if_mtu));
  2124. //
  2125. // This is too big
  2126. // If the numSent variable is null, IPFragment will
  2127. // automatically increment the buffer ref by the sent count
  2128. // We however pass ulSent (THIS MUST BE INITIALIZED TO 0).
  2129. // At the end, we increment it by the
  2130. //
  2131. InterlockedIncrement((PLONG) &(pOutIf->ulFragNeeded));
  2132. nsStatus = IPFragment(pOutIf->pIpIf,
  2133. pOutIf->pIpIf->if_mtu - sizeof(IPHeader),
  2134. pOutIf->dwNextHopAddr,
  2135. pnpNewPacket,
  2136. pNewHeader,
  2137. pnbDataBuffer,
  2138. ulDataLength,
  2139. pbyNewOptions,
  2140. pFWC->fc_optlength,
  2141. (PINT) &ulSent,
  2142. TRUE,
  2143. NULL);
  2144. if((nsStatus isnot STATUS_SUCCESS) and
  2145. (nsStatus isnot IP_PENDING))
  2146. {
  2147. InterlockedIncrement((PLONG) &(pOutIf->ulOutDiscards));
  2148. }
  2149. else
  2150. {
  2151. InterlockedExchangeAdd((PLONG) &(pOutIf->ulOutPackets),
  2152. ulSent);
  2153. InterlockedExchangeAdd((PLONG) &(pSource->ulTotalOutPackets),
  2154. ulSent);
  2155. }
  2156. }
  2157. else
  2158. {
  2159. Trace(FWD, INFO,
  2160. ("IPMForward: No fragmentation needed, sending packet with flags 0x%X\n",
  2161. ((PacketContext *)pnpNewPacket->ProtocolReserved)->PCFLAGS));
  2162. //
  2163. // Mark as no loopback
  2164. //
  2165. NdisSetPacketFlags(pnpNewPacket,
  2166. NDIS_FLAGS_DONT_LOOPBACK);
  2167. nsStatus = SendIPPacket(pOutIf->pIpIf,
  2168. pOutIf->dwNextHopAddr,
  2169. pnpNewPacket,
  2170. pnbDataBuffer,
  2171. pNewHeader,
  2172. pbyNewOptions,
  2173. pFWC->fc_optlength,
  2174. FALSE,
  2175. NULL,
  2176. FALSE);
  2177. if((nsStatus isnot STATUS_SUCCESS) and
  2178. (nsStatus isnot IP_PENDING))
  2179. {
  2180. Trace(FWD, ERROR,
  2181. ("IPMForward: Error 0x%x from SendIPPacket\n",
  2182. nsStatus));
  2183. InterlockedIncrement((PLONG) &(pOutIf->ulOutDiscards));
  2184. }
  2185. else
  2186. {
  2187. InterlockedIncrement((PLONG) &(pOutIf->ulOutPackets));
  2188. InterlockedIncrement((PLONG) &(pSource->ulTotalOutPackets));
  2189. if(nsStatus is IP_PENDING)
  2190. {
  2191. //
  2192. // The resources allocated in this routine are
  2193. // freed because SendIPPacket calls FreeIPPacket
  2194. // We just need to track if we are done with the
  2195. // original buffer
  2196. //
  2197. ulSent++;
  2198. }
  2199. }
  2200. }
  2201. #ifdef MREF_DEBUG
  2202. InterlockedDecrement(&(pOutIf->pIpIf->if_mfwdpktcount));
  2203. #endif
  2204. DerefIF(pOutIf->pIpIf);
  2205. }
  2206. DereferenceSource(pSource);
  2207. //
  2208. // so how many do we have pending?
  2209. //
  2210. if(ulSent isnot 0)
  2211. {
  2212. Trace(FWD, INFO,
  2213. ("IPMForward: Pending sends %d\n",
  2214. ulSent));
  2215. //
  2216. // So there were some pending sends (or some
  2217. // fragments)
  2218. //
  2219. iBufRefCount = ReferenceBuffer(pBuffRef, ulSent);
  2220. Trace(FWD, INFO,
  2221. ("IPMForward: ReferenceBuffer returned %d\n",iBufRefCount));
  2222. if(iBufRefCount is 0)
  2223. {
  2224. //
  2225. // The sends completed before we got here. But since the
  2226. // refcount would have been negative, the buffer would
  2227. // not have been freed
  2228. //
  2229. CTEFreeMem(pBuffRef);
  2230. //
  2231. // Call FWSendComplete on the packet to free up
  2232. // resources
  2233. //
  2234. #if MCAST_BUG_TRACKING
  2235. pFWC->fc_mtu = __LINE__;
  2236. #endif
  2237. FWSendComplete(pnpPacket,
  2238. pFWC->fc_buffhead, IP_SUCCESS);
  2239. }
  2240. }
  2241. else
  2242. {
  2243. Trace(FWD, INFO,
  2244. ("IPMForward: There are no pending sends\n"));
  2245. //
  2246. // NULL out the pc_br so the completion routine does not
  2247. // try to deref it. Also generally clean stuff up
  2248. //
  2249. ((PacketContext *)pnpPacket->ProtocolReserved)->pc_br = NULL;
  2250. CTEFreeMem(pBuffRef);
  2251. //
  2252. // No pending sends. There was however a buffref in the
  2253. // FWC, so the packets would not have been freed
  2254. //
  2255. #if MCAST_BUG_TRACKING
  2256. pFWC->fc_mtu = __LINE__;
  2257. #endif
  2258. FWSendComplete(pnpPacket,
  2259. pFWC->fc_buffhead, IP_SUCCESS);
  2260. }
  2261. TraceLeave(FWD, "IPMForward");
  2262. return STATUS_SUCCESS;
  2263. }
  2264. #endif // IPMCAST