Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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