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.

3841 lines
117 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. igmp.c - IP multicast routines.
  5. Abstract:
  6. This file contains all the routines related to the Internet Group Management
  7. Protocol (IGMP).
  8. Author:
  9. [Environment:]
  10. kernel mode only
  11. [Notes:]
  12. optional-notes
  13. Revision History:
  14. Feb. 2000 - upgraded to IGMPv3 (DThaler)
  15. --*/
  16. #include "precomp.h"
  17. #include "mdlpool.h"
  18. #include "igmp.h"
  19. #include "icmp.h"
  20. #include "ipxmit.h"
  21. #include "iproute.h"
  22. #if GPC
  23. #include "qos.h"
  24. #include "traffic.h"
  25. #include "gpcifc.h"
  26. #include "ntddtc.h"
  27. extern GPC_HANDLE hGpcClient[];
  28. extern ULONG GpcCfCounts[];
  29. extern GPC_EXPORTED_CALLS GpcEntries;
  30. extern ULONG GPCcfInfo;
  31. extern ULONG ServiceTypeOffset;
  32. #endif
  33. extern uint DisableUserTOS;
  34. extern uint DefaultTOS;
  35. #define IGMP_QUERY 0x11 // Membership query
  36. #define IGMP_REPORT_V1 0x12 // Version 1 membership report
  37. #define IGMP_REPORT_V2 0x16 // Version 2 membership report
  38. #define IGMP_LEAVE 0x17 // Leave Group
  39. #define IGMP_REPORT_V3 0x22 // Version 3 membership report
  40. // IGMPv3 Group Record Types
  41. #define MODE_IS_INCLUDE 1
  42. #define MODE_IS_EXCLUDE 2
  43. #define CHANGE_TO_INCLUDE_MODE 3
  44. #define CHANGE_TO_EXCLUDE_MODE 4
  45. #define ALLOW_NEW_SOURCES 5
  46. #define BLOCK_OLD_SOURCES 6
  47. #define ALL_HOST_MCAST 0x010000E0
  48. #define IGMPV3_RTRS_MCAST 0x160000E0
  49. #define UNSOLICITED_REPORT_INTERVAL 2 // used when sending a report after a
  50. // mcast group has been added. The
  51. // report is sent at a interval of
  52. // 0 msecs to 1 sec. IGMPv3 spec
  53. // changed this from previous value
  54. // of 10 seconds (value 20)
  55. #define DEFAULT_ROBUSTNESS 2
  56. static uchar g_IgmpRobustness = DEFAULT_ROBUSTNESS;
  57. //
  58. // The following values are used to initialize counters that keep time in
  59. // 1/2 a sec.
  60. //
  61. #define DEFAULT_QUERY_RESP_INTERVAL 100 // 10 seconds, note different units from other defines
  62. #define DEFAULT_QUERY_INTERVAL 250 // 125 secs, per spec
  63. // Macro to test whether a source passes the network-layer filter
  64. #define IS_SOURCE_ALLOWED(Grp, Src) \
  65. (((Src)->isa_xrefcnt != (Grp)->iga_grefcnt) || ((Src)->isa_irefcnt != 0))
  66. // Macro to test whether a group should pass the link-layer filter
  67. #define IS_GROUP_ALLOWED(Grp) \
  68. (((Grp)->iga_grefcnt != 0) || ((Grp)->iga_srclist != NULL))
  69. #define IS_SOURCE_DELETABLE(Src) \
  70. (((Src)->isa_irefcnt == 0) && ((Src)->isa_xrefcnt == 0) \
  71. && ((Src)->isa_xmitleft==0) && ((Src)->isa_csmarked == 0))
  72. #define IS_GROUP_DELETABLE(Grp) \
  73. (!IS_GROUP_ALLOWED(Grp) && ((Grp)->iga_xmitleft == 0) \
  74. && ((Grp)->iga_resptimer == 0))
  75. int RandomValue;
  76. int Seed;
  77. // Structure of an IGMPv1/v2 header.
  78. typedef struct IGMPHeader {
  79. uchar igh_vertype; // Type of igmp message
  80. uchar igh_rsvd; // max. resp. time for igmpv2 query;
  81. // max. resp. code for igmpv3 query;
  82. // will be 0 for other messages
  83. ushort igh_xsum;
  84. IPAddr igh_addr;
  85. } IGMPHeader;
  86. typedef struct IGMPv3GroupRecord {
  87. uchar igr_type;
  88. uchar igr_datalen;
  89. ushort igr_numsrc;
  90. IPAddr igr_addr;
  91. IPAddr igr_srclist[0];
  92. } IGMPv3GroupRecord;
  93. #define RECORD_SIZE(numsrc, datalen) (sizeof(IGMPv3GroupRecord) + (numsrc) * sizeof(IPAddr) + (datalen * sizeof(ulong)))
  94. typedef struct IGMPv3RecordQueueEntry {
  95. struct IGMPv3RecordQueueEntry *i3qe_next;
  96. IGMPv3GroupRecord *i3qe_buff;
  97. uint i3qe_size;
  98. } IGMPv3RecordQueueEntry;
  99. typedef struct IGMPReportQueueEntry {
  100. struct IGMPReportQueueEntry *iqe_next;
  101. IGMPHeader *iqe_buff;
  102. uint iqe_size;
  103. IPAddr iqe_dest;
  104. } IGMPReportQueueEntry;
  105. typedef struct IGMPv3ReportHeader {
  106. uchar igh_vertype; // Type of igmp message
  107. uchar igh_rsvd;
  108. ushort igh_xsum;
  109. ushort igh_rsvd2;
  110. ushort igh_numrecords;
  111. } IGMPv3ReportHeader;
  112. typedef struct IGMPv3QueryHeader {
  113. uchar igh_vertype; // Type of igmp message
  114. union {
  115. uchar igh_maxresp; // will be 0 for igmpv1 messages
  116. struct {
  117. uchar igh_mrcmant : 4; // MaxRespCode mantissa
  118. uchar igh_mrcexp : 3; // MaxRespCode exponent
  119. uchar igh_mrctype : 1; // MaxRespCode type
  120. };
  121. };
  122. ushort igh_xsum;
  123. IPAddr igh_addr;
  124. uchar igh_qrv : 3;
  125. uchar igh_s : 1;
  126. uchar igh_rsvd2 : 4;
  127. uchar igh_qqic;
  128. ushort igh_numsrc;
  129. IPAddr igh_srclist[0];
  130. } IGMPv3QueryHeader;
  131. #define IGMPV3_QUERY_SIZE(NumSrc) \
  132. (sizeof(IGMPv3QueryHeader) + (NumSrc) * sizeof(IPAddr))
  133. #define TOTAL_HEADER_LENGTH \
  134. (sizeof(IPHeader) + ROUTER_ALERT_SIZE + sizeof(IGMPv3ReportHeader))
  135. #define RECORD_MTU(NTE) \
  136. (4 * (((NTE)->nte_if->if_mtu - TOTAL_HEADER_LENGTH) / 4))
  137. typedef struct IGMPBlockStruct {
  138. struct IGMPBlockStruct *ibs_next;
  139. CTEBlockStruc ibs_block;
  140. } IGMPBlockStruct;
  141. void *IGMPProtInfo;
  142. IGMPBlockStruct *IGMPBlockList;
  143. uchar IGMPBlockFlag;
  144. extern BOOLEAN CopyToNdisSafe(PNDIS_BUFFER DestBuf, PNDIS_BUFFER * ppNextBuf,
  145. uchar * SrcBuf, uint Size, uint * StartOffset);
  146. extern NDIS_HANDLE BufferPool;
  147. DEFINE_LOCK_STRUCTURE(IGMPLock)
  148. extern ProtInfo *RawPI; // Raw IP protinfo
  149. //
  150. // the global address for unnumbered interfaces
  151. //
  152. extern IPAddr g_ValidAddr;
  153. extern IP_STATUS IPCopyOptions(uchar *, uint, IPOptInfo *);
  154. extern void IPInitOptions(IPOptInfo *);
  155. extern void *IPRegisterProtocol(uchar Protocol, void *RcvHandler,
  156. void *XmitHandler, void *StatusHandler,
  157. void *RcvCmpltHandler, void *PnPHandler,
  158. void *ElistHandler);
  159. extern ushort XsumBufChain(IPRcvBuf * BufChain);
  160. uint IGMPInit(void);
  161. //
  162. // All of the init code can be discarded
  163. //
  164. #ifdef ALLOC_PRAGMA
  165. #pragma alloc_text(INIT, IGMPInit)
  166. #endif // ALLOC_PRAGMA
  167. //** GetIGMPBuffer - Get an IGMP buffer, and allocate an NDIS_BUFFER that maps it.
  168. //
  169. // A routine to allocate an IGMP buffer and map an NDIS_BUFFER to it.
  170. //
  171. // Entry: Size - Size in bytes header buffer should be mapped as.
  172. // Buffer - Pointer to pointer to NDIS_BUFFER to return.
  173. //
  174. // Returns: Pointer to ICMP buffer if allocated, or NULL.
  175. //
  176. __inline
  177. IGMPHeader *
  178. GetIGMPBuffer(uint Size, PNDIS_BUFFER *Buffer)
  179. {
  180. IGMPHeader *Header;
  181. ASSERT(Size);
  182. ASSERT(Buffer);
  183. *Buffer = MdpAllocate(IcmpHeaderPool, &Header);
  184. if (*Buffer) {
  185. NdisAdjustBufferLength(*Buffer, Size);
  186. // Reserve room for the IP Header.
  187. //
  188. Header = (IGMPHeader *)((uchar *)Header + sizeof(IPHeader));
  189. }
  190. return Header;
  191. }
  192. //** FreeIGMPBuffer - Free an ICMP buffer.
  193. //
  194. // This routine puts an ICMP buffer back on our free list.
  195. //
  196. // Entry: Buffer - Pointer to NDIS_BUFFER to be freed.
  197. // Type - ICMP header type
  198. //
  199. // Returns: Nothing.
  200. //
  201. __inline
  202. void
  203. FreeIGMPBuffer(PNDIS_BUFFER Buffer)
  204. {
  205. MdpFree(Buffer);
  206. }
  207. //** IGMPSendComplete - Complete an IGMP send.
  208. //
  209. // This rtn is called when an IGMP send completes. We free the header buffer,
  210. // the data buffer if there is one, and the NDIS_BUFFER chain.
  211. //
  212. // Entry: DataPtr - Pointer to data buffer, if any.
  213. // BufferChain - Pointer to NDIS_BUFFER chain.
  214. //
  215. // Returns: Nothing
  216. //
  217. void
  218. IGMPSendComplete(void *DataPtr, PNDIS_BUFFER BufferChain, IP_STATUS SendStatus)
  219. {
  220. PNDIS_BUFFER DataBuffer;
  221. NdisGetNextBuffer(BufferChain, &DataBuffer);
  222. FreeIGMPBuffer(BufferChain);
  223. if (DataBuffer != (PNDIS_BUFFER) NULL) { // We had data with this IGMP send.
  224. CTEFreeMem(DataPtr);
  225. NdisFreeBuffer(DataBuffer);
  226. }
  227. }
  228. //* IGMPRandomTicks - Generate a random value of timer ticks.
  229. //
  230. // A random number routine to generate a random number of timer ticks,
  231. // between 1 and time (in units of half secs) passed. The random number
  232. // algorithm is adapted from the book 'System Simulation' by Geoffrey Gordon.
  233. //
  234. // Input: Nothing.
  235. //
  236. // Returns: A random value between 1 and TimeDelayInHalfSec.
  237. //
  238. uint
  239. IGMPRandomTicks(
  240. IN uint TimeDelayInHalfSec)
  241. {
  242. RandomValue = RandomValue * 1220703125;
  243. if (RandomValue < 0) {
  244. RandomValue += 2147483647; // inefficient, but avoids warnings.
  245. RandomValue++;
  246. }
  247. // Not sure if RandomValue can get to 0, but if it does the algorithm
  248. // degenerates, so fix this if it happens.
  249. if (RandomValue == 0)
  250. RandomValue = ((Seed + (int)CTESystemUpTime()) % 100000000) | 1;
  251. return (uint) (((uint) RandomValue % TimeDelayInHalfSec) + 1);
  252. }
  253. //////////////////////////////////////////////////////////////////////////////
  254. // Routines accessing group entries
  255. //////////////////////////////////////////////////////////////////////////////
  256. //* FindIGMPAddr - Find an mcast entry on an NTE.
  257. //
  258. // Called to search an NTE for an IGMP entry for a given multicast address.
  259. // We walk down the chain on the NTE looking for it. If we find it,
  260. // we return a pointer to it and the one immediately preceding it. If we
  261. // don't find it we return NULL. We assume the caller has taken the lock
  262. // on the NTE before calling us.
  263. //
  264. // Input: NTE - NTE on which to search.
  265. // Addr - Class D address to find.
  266. // PrevPtr - Where to return pointer to preceding entry.
  267. //
  268. // Returns: Pointer to matching IGMPAddr structure if found, or NULL if not
  269. // found.
  270. //
  271. IGMPAddr *
  272. FindIGMPAddr(
  273. IN NetTableEntry *NTE,
  274. IN IPAddr Addr,
  275. OUT IGMPAddr **PrevPtr OPTIONAL)
  276. {
  277. int bucket;
  278. IGMPAddr *Current, *Temp;
  279. IGMPAddr **AddrPtr;
  280. AddrPtr = NTE->nte_igmplist;
  281. if (AddrPtr != NULL) {
  282. bucket = IGMP_HASH(Addr);
  283. Temp = STRUCT_OF(IGMPAddr, &AddrPtr[bucket], iga_next);
  284. Current = AddrPtr[bucket];
  285. while (Current != NULL) {
  286. if (IP_ADDR_EQUAL(Current->iga_addr, Addr)) {
  287. // Found a match, so return it.
  288. if (PrevPtr) {
  289. *PrevPtr = Temp;
  290. }
  291. return Current;
  292. }
  293. Temp = Current;
  294. Current = Current->iga_next;
  295. }
  296. }
  297. return NULL;
  298. }
  299. //* CreateIGMPAddr - Allocate memory and link the new IGMP address in
  300. //
  301. // Input: NTE - NetTableEntry to add group on
  302. // Addr - Group address to add
  303. //
  304. // Output: pAddrPtr - group entry added
  305. // pPrevPtr - previous group entry
  306. //
  307. // Assumes caller holds lock on NTE.
  308. //
  309. IP_STATUS
  310. CreateIGMPAddr(
  311. IN NetTableEntry *NTE,
  312. IN IPAddr Addr,
  313. OUT IGMPAddr **pAddrPtr,
  314. OUT IGMPAddr **pPrevPtr)
  315. {
  316. int bucket;
  317. IGMPAddr *AddrPtr;
  318. uint AddrAdded;
  319. // If this is not a multicast address, fail the request.
  320. if (!CLASSD_ADDR(Addr)) {
  321. return IP_BAD_REQ;
  322. }
  323. AddrPtr = CTEAllocMemN(sizeof(IGMPAddr), 'yICT');
  324. if (AddrPtr == NULL) {
  325. return IP_NO_RESOURCES;
  326. }
  327. // See if we added it succesfully. If we did, fill in
  328. // the structure and link it in.
  329. CTEMemSet(AddrPtr, 0, sizeof(IGMPAddr));
  330. AddrPtr->iga_addr = Addr;
  331. // check whether the hash table has been allocated
  332. if (NTE->nte_igmpcount == 0) {
  333. NTE->nte_igmplist = CTEAllocMemN(IGMP_TABLE_SIZE * sizeof(IGMPAddr *),
  334. 'VICT');
  335. if (NTE->nte_igmplist) {
  336. CTEMemSet(NTE->nte_igmplist, 0,
  337. IGMP_TABLE_SIZE * sizeof(IGMPAddr *));
  338. }
  339. }
  340. if (NTE->nte_igmplist == NULL) {
  341. // Alloc failure. Free the memory and fail the request.
  342. CTEFreeMem(AddrPtr);
  343. return IP_NO_RESOURCES;
  344. }
  345. NTE->nte_igmpcount++;
  346. bucket = IGMP_HASH(Addr);
  347. AddrPtr->iga_next = NTE->nte_igmplist[bucket];
  348. NTE->nte_igmplist[bucket] = AddrPtr;
  349. *pAddrPtr = AddrPtr;
  350. *pPrevPtr = STRUCT_OF(IGMPAddr, &NTE->nte_igmplist[bucket], iga_next);
  351. return IP_SUCCESS;
  352. }
  353. //* FindOrCreateIGMPAddr - Find or create a group entry
  354. //
  355. // Input: NTE - NetTableEntry to add group on
  356. // Addr - Group address to add
  357. //
  358. // Output: pGrp - group entry found or added
  359. // pPrevGrp - previous group entry
  360. //
  361. // Assumes caller holds lock on NTE
  362. IP_STATUS
  363. FindOrCreateIGMPAddr(
  364. IN NetTableEntry *NTE,
  365. IN IPAddr Addr,
  366. OUT IGMPAddr **pGrp,
  367. OUT IGMPAddr **pPrevGrp)
  368. {
  369. *pGrp = FindIGMPAddr(NTE, Addr, pPrevGrp);
  370. if (*pGrp)
  371. return IP_SUCCESS;
  372. return CreateIGMPAddr(NTE, Addr, pGrp, pPrevGrp);
  373. }
  374. //* DeleteIGMPAddr - delete a group entry
  375. //
  376. // Input: NTE - NetTableEntry to add group on
  377. // PrevPtr - Previous group entry
  378. // pPtr - Group entry to delete
  379. //
  380. // Output: pPtr - zeroed since group entry is freed
  381. //
  382. // Assumes caller holds lock on NTE
  383. void
  384. DeleteIGMPAddr(
  385. IN NetTableEntry *NTE,
  386. IN IGMPAddr *PrevPtr,
  387. IN OUT IGMPAddr **pPtr)
  388. {
  389. // Make sure all references have been released and retransmissions are done
  390. ASSERT(IS_GROUP_DELETABLE(*pPtr));
  391. // Unlink from the NTE
  392. PrevPtr->iga_next = (*pPtr)->iga_next;
  393. NTE->nte_igmpcount--;
  394. // Free the hash table if needed
  395. if (NTE->nte_igmpcount == 0) {
  396. CTEFreeMem(NTE->nte_igmplist);
  397. NTE->nte_igmplist = NULL;
  398. }
  399. // Free memory
  400. CTEFreeMem(*pPtr);
  401. *pPtr = NULL;
  402. }
  403. //////////////////////////////////////////////////////////////////////////////
  404. // Routines accessing source entries
  405. //////////////////////////////////////////////////////////////////////////////
  406. //* FindIGMPSrcAddr - Find an mcast source entry on a source list.
  407. //
  408. // Called to search an NTE for an IGMP source entry for a given address.
  409. // We walk down the chain on the group entry looking for it. If we find it,
  410. // we return a pointer to it and the one immediately preceding it. If we
  411. // don't find it we return NULL. We assume the caller has taken the lock
  412. // on the NTE before calling us.
  413. //
  414. // Input: IGA - group entry on which to search.
  415. // Addr - source address to find.
  416. // PrevPtr - Where to return pointer to preceding entry.
  417. //
  418. // Returns: Pointer to matching IGMPSrcAddr structure if found, or NULL
  419. // if not found.
  420. //
  421. IGMPSrcAddr *
  422. FindIGMPSrcAddr(
  423. IN IGMPAddr *IGA,
  424. IN IPAddr Addr,
  425. OUT IGMPSrcAddr **PrevPtr OPTIONAL)
  426. {
  427. IGMPSrcAddr *Current, *Temp;
  428. Temp = STRUCT_OF(IGMPSrcAddr, &IGA->iga_srclist, isa_next);
  429. Current = IGA->iga_srclist;
  430. while (Current != NULL) {
  431. if (IP_ADDR_EQUAL(Current->isa_addr, Addr)) {
  432. // Found a match, so return it.
  433. if (PrevPtr) {
  434. *PrevPtr = Temp;
  435. }
  436. return Current;
  437. }
  438. Temp = Current;
  439. Current = Current->isa_next;
  440. }
  441. return NULL;
  442. }
  443. //* CreateIGMPSrcAddr - Allocate memory and link the new source address in
  444. //
  445. // Input: GroupPtr - group entry to add source to.
  446. // SrcAddr - source address to add.
  447. //
  448. // Output: pSrcPtr - source entry added.
  449. // pPrevSrcPtr - previous source entry.
  450. //
  451. // Assumes caller holds lock on NTE.
  452. //
  453. IP_STATUS
  454. CreateIGMPSrcAddr(
  455. IN IGMPAddr *GroupPtr,
  456. IN IPAddr SrcAddr,
  457. OUT IGMPSrcAddr **pSrcPtr,
  458. OUT IGMPSrcAddr **pPrevSrcPtr OPTIONAL)
  459. {
  460. IGMPSrcAddr *SrcAddrPtr;
  461. // If this is a multicast address, fail the request.
  462. if (CLASSD_ADDR(SrcAddr)) {
  463. return IP_BAD_REQ;
  464. }
  465. // Allocate space for the new source entry
  466. SrcAddrPtr = CTEAllocMemN(sizeof(IGMPSrcAddr), 'yICT');
  467. if (SrcAddrPtr == NULL) {
  468. return IP_NO_RESOURCES;
  469. }
  470. // Initialize fields
  471. RtlZeroMemory(SrcAddrPtr, sizeof(IGMPSrcAddr));
  472. SrcAddrPtr->isa_addr = SrcAddr;
  473. // Link it off the group entry
  474. SrcAddrPtr->isa_next = GroupPtr->iga_srclist;
  475. GroupPtr->iga_srclist = SrcAddrPtr;
  476. *pSrcPtr = SrcAddrPtr;
  477. if (pPrevSrcPtr)
  478. *pPrevSrcPtr = STRUCT_OF(IGMPSrcAddr, &GroupPtr->iga_srclist, isa_next);
  479. return IP_SUCCESS;
  480. }
  481. //* FindOrCreateIGMPSrcAddr - Find or create a source entry
  482. //
  483. // Input: GroupPtr - group entry to add source to.
  484. // SrcAddr - source address to add.
  485. //
  486. // Output: pSrcPtr - source entry added.
  487. // pPrevSrcPtr - previous source entry.
  488. //
  489. // Assumes caller holds lock on NTE
  490. IP_STATUS
  491. FindOrCreateIGMPSrcAddr(
  492. IN IGMPAddr *AddrPtr,
  493. IN IPAddr SrcAddr,
  494. OUT IGMPSrcAddr **pSrc,
  495. OUT IGMPSrcAddr **pPrevSrc)
  496. {
  497. *pSrc = FindIGMPSrcAddr(AddrPtr, SrcAddr, pPrevSrc);
  498. if (*pSrc)
  499. return IP_SUCCESS;
  500. return CreateIGMPSrcAddr(AddrPtr, SrcAddr, pSrc, pPrevSrc);
  501. }
  502. //* DeleteIGMPSrcAddr - delete a source entry
  503. //
  504. // Input: pSrcPtr - source entry added.
  505. // PrevSrcPtr - previous source entry.
  506. //
  507. // Output: pSrcPtr - zeroed since source entry is freed.
  508. //
  509. // Caller is responsible for freeing group entry if needed
  510. // Assumes caller holds lock on NTE
  511. void
  512. DeleteIGMPSrcAddr(
  513. IN IGMPSrcAddr *PrevSrcPtr,
  514. IN OUT IGMPSrcAddr **pSrcPtr)
  515. {
  516. // Make sure all references have been released
  517. // and no retransmissions are left
  518. ASSERT(IS_SOURCE_DELETABLE(*pSrcPtr));
  519. // Unlink from the group entry
  520. PrevSrcPtr->isa_next = (*pSrcPtr)->isa_next;
  521. // Free memory
  522. CTEFreeMem(*pSrcPtr);
  523. *pSrcPtr = NULL;
  524. }
  525. //////////////////////////////////////////////////////////////////////////////
  526. // Timer routines
  527. //////////////////////////////////////////////////////////////////////////////
  528. //* ResetGeneralTimer - Reset timer for responding to a General Query in
  529. // IGMPv3 mode
  530. //
  531. // Input: IF - Interface to reset timer on
  532. // MaxRespTimeInHalfSec - Maximum expiration time
  533. void
  534. ResetGeneralTimer(
  535. IN Interface *IF,
  536. IN uint MaxRespTimeInHalfSec)
  537. {
  538. if ((IF->IgmpGeneralTimer == 0) ||
  539. (IF->IgmpGeneralTimer > MaxRespTimeInHalfSec)) {
  540. IF->IgmpGeneralTimer = IGMPRandomTicks(MaxRespTimeInHalfSec);
  541. }
  542. // We could walk all groups here to stop any timers longer
  543. // than IF->IgmpGeneralTimer, but is it really worth it?
  544. }
  545. //* CancelGroupResponseTimer - stop a group timer
  546. //
  547. // Caller is responsible for deleting AddrPtr if no longer needed.
  548. void
  549. CancelGroupResponseTimer(
  550. IN IGMPAddr *AddrPtr)
  551. {
  552. IGMPSrcAddr *Src, *PrevSrc;
  553. AddrPtr->iga_resptimer = 0;
  554. AddrPtr->iga_resptype = NO_RESP;
  555. // Make sure we never violate the invariant:
  556. // iga_resptimer>0 if isa_csmarked=TRUE for any source
  557. PrevSrc = STRUCT_OF(IGMPSrcAddr, &AddrPtr->iga_srclist, isa_next);
  558. for (Src=AddrPtr->iga_srclist; Src; PrevSrc=Src,Src=Src->isa_next) {
  559. Src->isa_csmarked = FALSE;
  560. if (IS_SOURCE_DELETABLE(Src)) {
  561. DeleteIGMPSrcAddr(PrevSrc, &Src);
  562. Src = PrevSrc;
  563. }
  564. }
  565. }
  566. //* ResetGroupResponseTimer - Reset timer for responding to a Group-specific
  567. // Query, or an IGMPv1/v2 General Query.
  568. //
  569. // Input: IF - Interface to reset timer on.
  570. // AddrPtr - Group entry whose timer should be reset.
  571. // MaxRespTimeInHalfSec - Maximum expiration time.
  572. //
  573. // Caller is responsible for deleting AddrPtr if no longer needed.
  574. void
  575. ResetGroupResponseTimer(
  576. IN Interface *IF,
  577. IN IGMPAddr *AddrPtr,
  578. IN uint MaxRespTimeInHalfSec)
  579. {
  580. if ((AddrPtr->iga_resptimer == 0) ||
  581. (AddrPtr->iga_resptimer > MaxRespTimeInHalfSec)) {
  582. AddrPtr->iga_resptimer = IGMPRandomTicks(MaxRespTimeInHalfSec);
  583. }
  584. // Check if superceded by a general query
  585. if ((IF->IgmpGeneralTimer != 0)
  586. && (IF->IgmpGeneralTimer <= AddrPtr->iga_resptimer)) {
  587. CancelGroupResponseTimer(AddrPtr);
  588. return;
  589. }
  590. // Supercede group-source responses
  591. AddrPtr->iga_resptype = GROUP_RESP;
  592. }
  593. //* ResetGroupAndSourceTimer - Reset timer for responding to a
  594. // Group-and-source-specific Query
  595. //
  596. // Input: IF - Interface to reset timer on.
  597. // AddrPtr - Group entry whose timer should be reset.
  598. // MaxRespTimeInHalfSec - Maximum expiration time.
  599. //
  600. // Caller is responsible for deleting AddrPtr if no longer needed
  601. void
  602. ResetGroupAndSourceTimer(
  603. IN Interface *IF,
  604. IN IGMPAddr *AddrPtr,
  605. IN uint MaxRespTimeInHalfSec)
  606. {
  607. if ((AddrPtr->iga_resptimer == 0) ||
  608. (AddrPtr->iga_resptimer > MaxRespTimeInHalfSec)) {
  609. AddrPtr->iga_resptimer = IGMPRandomTicks(MaxRespTimeInHalfSec);
  610. }
  611. // Check if superceded by a general query
  612. if ((IF->IgmpGeneralTimer != 0)
  613. && (IF->IgmpGeneralTimer < AddrPtr->iga_resptimer)) {
  614. CancelGroupResponseTimer(AddrPtr);
  615. return;
  616. }
  617. // Check if superceded by a group-specific responses
  618. if (AddrPtr->iga_resptype == NO_RESP)
  619. AddrPtr->iga_resptype = GROUP_SOURCE_RESP;
  620. }
  621. //////////////////////////////////////////////////////////////////////////////
  622. // Receive routines
  623. //////////////////////////////////////////////////////////////////////////////
  624. //* SetVersion - change the IGMP compatability mode on an interface.
  625. //
  626. // Input: NTE - NetTableEntry on which to set IGMP version.
  627. // Version - IGMP version number to set
  628. //
  629. // Caller is responsible for deleting AddrPtr if no longer needed
  630. void
  631. SetVersion(
  632. IN NetTableEntry *NTE,
  633. IN uint Version)
  634. {
  635. IGMPAddr **HashPtr, *AddrPtr, *PrevPtr;
  636. IGMPSrcAddr *Src, *PrevSrc;
  637. uint i;
  638. DEBUGMSG(DBG_INFO && DBG_IGMP,
  639. (DTEXT("Setting version on interface %d to %d\n"),
  640. NTE->nte_if->if_index, Version));
  641. NTE->nte_if->IgmpVersion = Version;
  642. // Cancel General Timer
  643. NTE->nte_if->IgmpGeneralTimer = 0;
  644. //
  645. // Cancel all Group-Response and Triggered Retransmission timers
  646. //
  647. HashPtr = NTE->nte_igmplist;
  648. for (i = 0; (i < IGMP_TABLE_SIZE) && (NTE->nte_igmplist != NULL); i++) {
  649. PrevPtr = STRUCT_OF(IGMPAddr, &HashPtr[i], iga_next);
  650. for (AddrPtr = HashPtr[i];
  651. (AddrPtr != NULL);
  652. PrevPtr = AddrPtr, AddrPtr = AddrPtr->iga_next)
  653. {
  654. PrevSrc = STRUCT_OF(IGMPSrcAddr, &AddrPtr->iga_srclist, isa_next);
  655. for (Src=AddrPtr->iga_srclist; Src; PrevSrc=Src,Src=Src->isa_next) {
  656. Src->isa_xmitleft = 0;
  657. Src->isa_csmarked = FALSE;
  658. if (IS_SOURCE_DELETABLE(Src)) {
  659. DeleteIGMPSrcAddr(PrevSrc, &Src);
  660. Src = PrevSrc;
  661. }
  662. }
  663. AddrPtr->iga_trtimer = 0;
  664. AddrPtr->iga_changetype = NO_CHANGE;
  665. AddrPtr->iga_xmitleft = 0;
  666. CancelGroupResponseTimer(AddrPtr);
  667. if (IS_GROUP_DELETABLE(AddrPtr)) {
  668. DeleteIGMPAddr(NTE, PrevPtr, &AddrPtr);
  669. AddrPtr = PrevPtr;
  670. }
  671. if (NTE->nte_igmplist == NULL)
  672. break;
  673. }
  674. }
  675. }
  676. //* ProcessGroupQuery - process an IGMP Group-specific query
  677. //
  678. // Caller is responsible for deleting AddrPtr if no longer needed.
  679. void
  680. ProcessGroupQuery(
  681. IN Interface *IF,
  682. IN IGMPAddr *AddrPtr,
  683. IN uint ReportingDelayInHalfSec)
  684. {
  685. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_RX,
  686. (DTEXT("Got group query on interface %d\n"), IF->if_index));
  687. // Ignore query if we won't report anything. This will happen
  688. // right after we leave and have retransmissions pending.
  689. if (!IS_GROUP_ALLOWED(AddrPtr))
  690. return;
  691. ResetGroupResponseTimer(IF, AddrPtr, ReportingDelayInHalfSec);
  692. }
  693. //* ProcessGeneralQuery - Process an IGMP General Query
  694. //
  695. // Assumes caller holds lock on NTE
  696. void
  697. ProcessGeneralQuery(
  698. IN NetTableEntry *NTE,
  699. IN uint ReportingDelayInHalfSec)
  700. {
  701. IGMPAddr **HashPtr, *AddrPtr, *PrevPtr;
  702. uint i;
  703. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_RX,
  704. (DTEXT("Got general query on interface %d\n"),
  705. NTE->nte_if->if_index));
  706. if (NTE->nte_if->IgmpVersion == IGMPV3) {
  707. // IGMPv3 can pack multiple group records into the same report
  708. // and hence does not stagger the timers.
  709. // Create a pending response record
  710. ResetGeneralTimer(NTE->nte_if, ReportingDelayInHalfSec);
  711. } else {
  712. //
  713. // Walk our list and set a random report timer for all those
  714. // multicast addresses (except for the all-hosts address) that
  715. // don't already have one running.
  716. //
  717. HashPtr = NTE->nte_igmplist;
  718. for (i=0; (i < IGMP_TABLE_SIZE) && (NTE->nte_igmplist != NULL); i++) {
  719. PrevPtr = STRUCT_OF(IGMPAddr, &HashPtr[i], iga_next);
  720. for (AddrPtr = HashPtr[i];
  721. (AddrPtr != NULL);
  722. PrevPtr=AddrPtr, AddrPtr = AddrPtr->iga_next)
  723. {
  724. if (IP_ADDR_EQUAL(AddrPtr->iga_addr, ALL_HOST_MCAST))
  725. continue;
  726. ProcessGroupQuery(NTE->nte_if, AddrPtr,
  727. ReportingDelayInHalfSec);
  728. if (IS_GROUP_DELETABLE(AddrPtr)) {
  729. DeleteIGMPAddr(NTE, PrevPtr, &AddrPtr);
  730. AddrPtr = PrevPtr;
  731. }
  732. if (NTE->nte_igmplist == NULL)
  733. break;
  734. }
  735. }
  736. }
  737. }
  738. //* Process an IGMP Group-and-source-specific Query
  739. //
  740. // Caller is responsible for deleting AddrPtr if no longer needed
  741. void
  742. ProcessGroupAndSourceQuery(
  743. IN NetTableEntry *NTE,
  744. IN IGMPv3QueryHeader UNALIGNED *IQH,
  745. IN IGMPAddr *AddrPtr,
  746. IN uint ReportingDelayInHalfSec)
  747. {
  748. uint i, NumSrc;
  749. IGMPSrcAddr *Src;
  750. IP_STATUS Status = IP_SUCCESS;
  751. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_RX,
  752. (DTEXT("Got source query on interface %d\n"),
  753. NTE->nte_if->if_index));
  754. NumSrc = net_short(IQH->igh_numsrc);
  755. ResetGroupAndSourceTimer(NTE->nte_if, AddrPtr, ReportingDelayInHalfSec);
  756. // Mark each source
  757. for (i=0; i<NumSrc; i++) {
  758. Src = FindIGMPSrcAddr(AddrPtr, IQH->igh_srclist[i], NULL);
  759. if (!Src) {
  760. if (AddrPtr->iga_grefcnt == 0)
  761. continue;
  762. // Create temporary source state
  763. Status = CreateIGMPSrcAddr(AddrPtr, IQH->igh_srclist[i],
  764. &Src, NULL);
  765. // If this fails, we have a problem since we won't be
  766. // able to override the leave and a temporary black
  767. // hole would result. To avoid this, we pretend we
  768. // just got a group-specific query instead.
  769. if (Status != IP_SUCCESS) {
  770. ProcessGroupQuery(NTE->nte_if, AddrPtr,
  771. ReportingDelayInHalfSec);
  772. break;
  773. }
  774. }
  775. // Mark source for current-state report inclusion
  776. Src->isa_csmarked = TRUE;
  777. }
  778. }
  779. //* Process an IGMP Query message
  780. //
  781. // Entry: NTE - Pointer to NTE on which IGMP message was received.
  782. // Dest - IPAddr of destination (should be a Class D address).
  783. // IPHdr - Pointer to the IP Header.
  784. // IPHdrLength - Bytes in IPHeader.
  785. // IQH - Pointer to IGMP Query received.
  786. // Size - Size in bytes of IGMP message.
  787. //
  788. // Assumes caller holds lock on NTE
  789. void
  790. IGMPRcvQuery(
  791. IN NetTableEntry *NTE,
  792. IN IPAddr Dest,
  793. IN IPHeader UNALIGNED *IPHdr,
  794. IN uint IPHdrLength,
  795. IN IGMPv3QueryHeader UNALIGNED *IQH,
  796. IN uint Size)
  797. {
  798. uint ReportingDelayInHalfSec, MaxResp, NumSrc, i;
  799. IP_STATUS Status;
  800. IGMPAddr *AddrPtr, *PrevPtr;
  801. IGMPSrcAddr *Src, *PrevSrc;
  802. uchar QRV;
  803. // Make sure we're running at least level 2 of IGMP support.
  804. if (IGMPLevel != 2)
  805. return;
  806. NumSrc = (Size >= 12)? net_short(IQH->igh_numsrc) : 0;
  807. QRV = (Size >= 12)? IQH->igh_qrv : 0;
  808. // Update Robustness to match querier's robustness variable
  809. g_IgmpRobustness = (QRV)? QRV : DEFAULT_ROBUSTNESS;
  810. //
  811. // If it is an older-version query, set the timer value for staying in
  812. // older-version mode
  813. //
  814. if ((Size == 8) && (IQH->igh_maxresp == 0)) {
  815. if (NTE->nte_if->IgmpVersion > IGMPV1) {
  816. SetVersion(NTE, IGMPV1);
  817. }
  818. MaxResp = DEFAULT_QUERY_RESP_INTERVAL;
  819. NTE->nte_if->IgmpVer1Timeout = g_IgmpRobustness * DEFAULT_QUERY_INTERVAL
  820. + (MaxResp+4)/5;
  821. } else if ((Size == 8) && (IQH->igh_maxresp != 0)) {
  822. if (NTE->nte_if->IgmpVersion > IGMPV2) {
  823. SetVersion(NTE, IGMPV2);
  824. }
  825. MaxResp = IQH->igh_maxresp;
  826. NTE->nte_if->IgmpVer2Timeout = g_IgmpRobustness * DEFAULT_QUERY_INTERVAL
  827. + (MaxResp+4)/5;
  828. } else if ((Size < 12) || (IQH->igh_rsvd2 != 0)) {
  829. // must silently ignore
  830. DEBUGMSG(DBG_WARN && DBG_IGMP,
  831. (DTEXT("Dropping IGMPv3 query with unrecognized version\n")));
  832. return;
  833. } else {
  834. // IGMPv3
  835. uchar* ptr = ((uchar*)IPHdr) + sizeof(IPHeader);
  836. int len = IPHdrLength - sizeof(IPHeader);
  837. uchar temp;
  838. BOOLEAN bRtrAlertFound = FALSE;
  839. // drop it if size is too short for advertised # sources
  840. if (Size < IGMPV3_QUERY_SIZE(NumSrc)) {
  841. DEBUGMSG(DBG_WARN && DBG_IGMP,
  842. (DTEXT("Dropping IGMPv3 query due to size too short\n")));
  843. return;
  844. }
  845. // drop it if it didn't have router alert
  846. while (!bRtrAlertFound && len>=2) {
  847. if (ptr[0] == IP_OPT_ROUTER_ALERT) {
  848. bRtrAlertFound = TRUE;
  849. break;
  850. }
  851. temp = ptr[1]; // length
  852. ptr += temp;
  853. len -= temp;
  854. }
  855. if (!bRtrAlertFound) {
  856. DEBUGMSG(DBG_WARN && DBG_IGMP,
  857. (DTEXT("Dropping IGMPv3 query due to lack of Router Alert option\n")));
  858. return;
  859. }
  860. if (IQH->igh_mrctype == 0) {
  861. MaxResp = IQH->igh_maxresp;
  862. } else {
  863. MaxResp = ((((uint)IQH->igh_mrcmant) + 16) << (((uint)IQH->igh_mrcexp) + 3));
  864. }
  865. }
  866. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_RX,
  867. (DTEXT("IGMPRcvQuery: Max response time = %d.%d seconds\n"),
  868. MaxResp/10, MaxResp%10));
  869. //
  870. // MaxResp has time in 100 msec (1/10 sec) units. Convert
  871. // to 500 msec units. If the time is < 500 msec, use 1.
  872. //
  873. ReportingDelayInHalfSec = ((MaxResp > 5) ? (MaxResp / 5) : 1);
  874. if (IQH->igh_addr == 0) {
  875. // General Query
  876. ProcessGeneralQuery(NTE, ReportingDelayInHalfSec);
  877. } else {
  878. // If all-hosts address, ignore it
  879. if (IP_ADDR_EQUAL(IQH->igh_addr, ALL_HOST_MCAST)) {
  880. DEBUGMSG(DBG_WARN && DBG_IGMP,
  881. (DTEXT("Dropping IGMPv3 query for the All-Hosts group\n")));
  882. return;
  883. }
  884. // Don't need to do anything if we have no group state for the group
  885. AddrPtr = FindIGMPAddr(NTE, IQH->igh_addr, &PrevPtr);
  886. if (!AddrPtr)
  887. return;
  888. if (NumSrc == 0) {
  889. // Group-specific query
  890. ProcessGroupQuery(NTE->nte_if, AddrPtr, ReportingDelayInHalfSec);
  891. } else {
  892. // Group-and-source-specific query
  893. ProcessGroupAndSourceQuery(NTE, IQH, AddrPtr,
  894. ReportingDelayInHalfSec);
  895. }
  896. // Delete group if no longer needed
  897. if (IS_GROUP_DELETABLE(AddrPtr))
  898. DeleteIGMPAddr(NTE, PrevPtr, &AddrPtr);
  899. }
  900. }
  901. //** IGMPRcv - Receive an IGMP datagram.
  902. //
  903. // Called by IP when we receive an IGMP datagram. We validate it to make
  904. // sure it's reasonable. Then if it it's a query for a group to which we
  905. // belong we'll start a response timer. If it's a report to a group to
  906. // which we belong we'll stop any running timer.
  907. //
  908. // The IGMP header is only 8 bytes long, and so should always fit in
  909. // exactly one IP rcv buffer. We check this to make sure, and if it
  910. // takes multiple buffers we discard it.
  911. //
  912. // Entry: NTE - Pointer to NTE on which IGMP message was received.
  913. // Dest - IPAddr of destination (should be a Class D address).
  914. // Src - IPAddr of source
  915. // LocalAddr - Local address of network which caused this to be
  916. // received.
  917. // SrcAddr - Address of local interface which received the
  918. // packet
  919. // IPHdr - Pointer to the IP Header.
  920. // IPHdrLength - Bytes in IPHeader.
  921. // RcvBuf - Pointer to IP receive buffer chain.
  922. // Size - Size in bytes of IGMP message.
  923. // IsBCast - Boolean indicator of whether or not this came in
  924. // as a bcast (should always be true).
  925. // Protocol - Protocol this came in on.
  926. // OptInfo - Pointer to info structure for received options.
  927. //
  928. // Returns: Status of reception
  929. IP_STATUS
  930. IGMPRcv(
  931. IN NetTableEntry * NTE,
  932. IN IPAddr Dest,
  933. IN IPAddr Src,
  934. IN IPAddr LocalAddr,
  935. IN IPAddr SrcAddr,
  936. IN IPHeader UNALIGNED * IPHdr,
  937. IN uint IPHdrLength,
  938. IN IPRcvBuf * RcvBuf,
  939. IN uint Size,
  940. IN uchar IsBCast,
  941. IN uchar Protocol,
  942. IN IPOptInfo * OptInfo)
  943. {
  944. IGMPHeader UNALIGNED *IGH;
  945. IGMPv3QueryHeader UNALIGNED *IQH;
  946. CTELockHandle Handle;
  947. IGMPAddr *AddrPtr, *PrevPtr;
  948. uchar DType;
  949. uint PromiscuousMode = 0;
  950. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_RX,
  951. (DTEXT("IGMPRcv entered\n")));
  952. PromiscuousMode = NTE->nte_if->if_promiscuousmode;
  953. // ASSERT(CLASSD_ADDR(Dest));
  954. // ASSERT(IsBCast);
  955. // Discard packets with invalid or broadcast source addresses.
  956. DType = GetAddrType(Src);
  957. if (DType == DEST_INVALID || IS_BCAST_DEST(DType)) {
  958. return IP_SUCCESS;
  959. }
  960. // Now get the pointer to the header, and validate the xsum.
  961. IGH = (IGMPHeader UNALIGNED *) RcvBuf->ipr_buffer;
  962. //
  963. // For mtrace like programs, use the entire IGMP packet to generate the xsum.
  964. //
  965. if ((Size < sizeof(IGMPHeader)) || (XsumBufChain(RcvBuf) != 0xffff)) {
  966. // Bad checksum, so fail.
  967. return IP_SUCCESS;
  968. }
  969. // OK, we may need to process this. See if we are a member of the
  970. // destination group. If we aren't, there's no need to proceed further.
  971. //
  972. // Since for any interface we always get notified with
  973. // same NTE, locking the NTE is fine. We don't have to
  974. // lock the interface structure
  975. //
  976. CTEGetLock(&NTE->nte_lock, &Handle);
  977. {
  978. if (!(NTE->nte_flags & NTE_VALID)) {
  979. CTEFreeLock(&NTE->nte_lock, Handle);
  980. return IP_SUCCESS;
  981. }
  982. //
  983. // The NTE is valid. Demux on type.
  984. //
  985. switch (IGH->igh_vertype) {
  986. case IGMP_QUERY:
  987. IGMPRcvQuery(NTE, Dest, IPHdr, IPHdrLength,
  988. (IGMPv3QueryHeader UNALIGNED *)IGH, Size);
  989. break;
  990. case IGMP_REPORT_V1:
  991. case IGMP_REPORT_V2:
  992. // Make sure we're running at least level 2 of IGMP support.
  993. if (IGMPLevel != 2) {
  994. CTEFreeLock(&NTE->nte_lock, Handle);
  995. return IP_SUCCESS;
  996. }
  997. //
  998. // This is a report. Check its validity and see if we have a
  999. // response timer running for that address. If we do, stop it.
  1000. // Make sure the destination address matches the address in the
  1001. // IGMP header.
  1002. //
  1003. if (IP_ADDR_EQUAL(Dest, IGH->igh_addr)) {
  1004. // The addresses match. See if we have a membership in this
  1005. // group.
  1006. AddrPtr = FindIGMPAddr(NTE, IGH->igh_addr, &PrevPtr);
  1007. if (AddrPtr != NULL) {
  1008. // We found a matching multicast address. Stop the response
  1009. // timer for any Group-specific or Group-and-source-
  1010. // specific queries.
  1011. CancelGroupResponseTimer(AddrPtr);
  1012. if (IS_GROUP_DELETABLE(AddrPtr))
  1013. DeleteIGMPAddr(NTE, PrevPtr, &AddrPtr);
  1014. }
  1015. }
  1016. break;
  1017. default:
  1018. break;
  1019. }
  1020. }
  1021. CTEFreeLock(&NTE->nte_lock, Handle);
  1022. //
  1023. // Pass the packet up to the raw layer if applicable.
  1024. // If promiscuous mode is set then we will anyway call rawrcv later
  1025. //
  1026. if ((RawPI != NULL) && (!PromiscuousMode)) {
  1027. if (RawPI->pi_rcv != NULL) {
  1028. (*(RawPI->pi_rcv)) (NTE, Dest, Src, LocalAddr, SrcAddr, IPHdr,
  1029. IPHdrLength, RcvBuf, Size, IsBCast, Protocol, OptInfo);
  1030. }
  1031. }
  1032. return IP_SUCCESS;
  1033. }
  1034. //////////////////////////////////////////////////////////////////////////////
  1035. // Send routines
  1036. //////////////////////////////////////////////////////////////////////////////
  1037. //* IGMPTransmit - transmit an IGMP message
  1038. IP_STATUS
  1039. IGMPTransmit(
  1040. IN PNDIS_BUFFER Buffer,
  1041. IN PVOID Body,
  1042. IN uint Size,
  1043. IN IPAddr SrcAddr,
  1044. IN IPAddr DestAddr)
  1045. {
  1046. uchar RtrAlertOpt[4] = { IP_OPT_ROUTER_ALERT, 4, 0, 0 };
  1047. IPOptInfo OptInfo; // Options for this transmit.
  1048. IP_STATUS Status;
  1049. RouteCacheEntry *RCE;
  1050. ushort MSS;
  1051. uchar DestType;
  1052. IPAddr Src;
  1053. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_TX,
  1054. (DTEXT("IGMPTransmit: Buffer=%x Body=%x Size=%d SrcAddr=%x\n"),
  1055. Buffer, Body, Size, SrcAddr));
  1056. IPInitOptions(&OptInfo);
  1057. OptInfo.ioi_ttl = 1;
  1058. OptInfo.ioi_options = (uchar *) & RtrAlertOpt;
  1059. OptInfo.ioi_optlength = ROUTER_ALERT_SIZE;
  1060. Src = OpenRCE(DestAddr, SrcAddr, &RCE, &DestType, &MSS, &OptInfo);
  1061. if (IP_ADDR_EQUAL(Src,NULL_IP_ADDR)) {
  1062. IGMPSendComplete(Body, Buffer, IP_SUCCESS);
  1063. return IP_DEST_HOST_UNREACHABLE;
  1064. }
  1065. #if GPC
  1066. if (DisableUserTOS) {
  1067. OptInfo.ioi_tos = (uchar) DefaultTOS;
  1068. }
  1069. if (GPCcfInfo) {
  1070. //
  1071. // we'll fall into here only if the GPC client is there
  1072. // and there is at least one CF_INFO_QOS installed
  1073. // (counted by GPCcfInfo).
  1074. //
  1075. GPC_STATUS status = STATUS_SUCCESS;
  1076. ULONG ServiceType = 0;
  1077. GPC_IP_PATTERN Pattern;
  1078. CLASSIFICATION_HANDLE GPCHandle;
  1079. Pattern.SrcAddr = SrcAddr;
  1080. Pattern.DstAddr = DestAddr;
  1081. Pattern.ProtocolId = PROT_ICMP;
  1082. Pattern.gpcSrcPort = 0;
  1083. Pattern.gpcDstPort = 0;
  1084. Pattern.InterfaceId.InterfaceId = 0;
  1085. Pattern.InterfaceId.LinkId = 0;
  1086. GPCHandle = 0;
  1087. GetIFAndLink(RCE,
  1088. &Pattern.InterfaceId.InterfaceId,
  1089. &Pattern.InterfaceId.LinkId
  1090. );
  1091. status = GpcEntries.GpcClassifyPatternHandler(
  1092. hGpcClient[GPC_CF_QOS],
  1093. GPC_PROTOCOL_TEMPLATE_IP,
  1094. &Pattern,
  1095. NULL, // context
  1096. &GPCHandle,
  1097. 0,
  1098. NULL,
  1099. FALSE);
  1100. OptInfo.ioi_GPCHandle = (int)GPCHandle;
  1101. //
  1102. // Only if QOS patterns exist, we get the TOS bits out.
  1103. //
  1104. if (NT_SUCCESS(status) && GpcCfCounts[GPC_CF_QOS]) {
  1105. status = GpcEntries.GpcGetUlongFromCfInfoHandler(
  1106. hGpcClient[GPC_CF_QOS],
  1107. OptInfo.ioi_GPCHandle,
  1108. ServiceTypeOffset,
  1109. &ServiceType);
  1110. //
  1111. // It is likely that the pattern has gone by now (Removed or
  1112. // whatever) and the handle that we are caching is INVALID.
  1113. // We need to pull up a new handle and get the
  1114. // TOS bit again.
  1115. //
  1116. if (STATUS_NOT_FOUND == status) {
  1117. GPCHandle = 0;
  1118. status = GpcEntries.GpcClassifyPatternHandler(
  1119. hGpcClient[GPC_CF_QOS],
  1120. GPC_PROTOCOL_TEMPLATE_IP,
  1121. &Pattern,
  1122. NULL, // context
  1123. &GPCHandle,
  1124. 0,
  1125. NULL,
  1126. FALSE);
  1127. OptInfo.ioi_GPCHandle = (int)GPCHandle;
  1128. //
  1129. // Only if QOS patterns exist, we get the TOS bits out.
  1130. //
  1131. if (NT_SUCCESS(status) && GpcCfCounts[GPC_CF_QOS]) {
  1132. status = GpcEntries.GpcGetUlongFromCfInfoHandler(
  1133. hGpcClient[GPC_CF_QOS],
  1134. OptInfo.ioi_GPCHandle,
  1135. ServiceTypeOffset,
  1136. &ServiceType);
  1137. }
  1138. }
  1139. }
  1140. if (status == STATUS_SUCCESS) {
  1141. OptInfo.ioi_tos = (OptInfo.ioi_tos & TOS_MASK) | (UCHAR) ServiceType;
  1142. }
  1143. } // if (GPCcfInfo)
  1144. #endif
  1145. Status = IPTransmit(IGMPProtInfo, Body, Buffer, Size,
  1146. DestAddr, SrcAddr, &OptInfo, RCE, PROT_IGMP, NULL);
  1147. CloseRCE(RCE);
  1148. if (Status != IP_PENDING)
  1149. IGMPSendComplete(Body, Buffer, IP_SUCCESS);
  1150. return Status;
  1151. }
  1152. //* GetAllowRecord - allocate and fill in an IGMPv3 ALLOW record for a group
  1153. //
  1154. // Caller is responsible for freeing pointer returned
  1155. IGMPv3GroupRecord *
  1156. GetAllowRecord(
  1157. IN IGMPAddr *AddrPtr,
  1158. IN uint *RecSize)
  1159. {
  1160. IGMPSrcAddr *Src, *PrevSrc;
  1161. IGMPv3GroupRecord *Rec;
  1162. ushort Count = 0;
  1163. // Count sources to include
  1164. for (Src=AddrPtr->iga_srclist; Src; Src=Src->isa_next) {
  1165. if (Src->isa_xmitleft == 0)
  1166. continue;
  1167. if (!IS_SOURCE_ALLOWED(AddrPtr, Src))
  1168. continue;
  1169. Count++;
  1170. }
  1171. if (Count == 0) {
  1172. *RecSize = 0;
  1173. return NULL;
  1174. }
  1175. Rec = CTEAllocMemN(RECORD_SIZE(Count,0), 'qICT');
  1176. //
  1177. // We need to walk the source list regardless of whether the
  1178. // allocation succeeded, so that we preserve the invariant that
  1179. // iga_xmitleft >= isa_xmitleft for all sources.
  1180. //
  1181. Count = 0;
  1182. PrevSrc = STRUCT_OF(IGMPSrcAddr, &AddrPtr->iga_srclist, isa_next);
  1183. for (Src=AddrPtr->iga_srclist; Src; PrevSrc=Src,Src=Src->isa_next) {
  1184. if (Src->isa_xmitleft == 0)
  1185. continue;
  1186. if (!IS_SOURCE_ALLOWED(AddrPtr, Src))
  1187. continue;
  1188. if (Rec)
  1189. Rec->igr_srclist[Count++] = Src->isa_addr;
  1190. Src->isa_xmitleft--;
  1191. if (IS_SOURCE_DELETABLE(Src)) {
  1192. DeleteIGMPSrcAddr(PrevSrc, &Src);
  1193. Src = PrevSrc;
  1194. }
  1195. }
  1196. if (Rec == NULL) {
  1197. *RecSize = 0;
  1198. return NULL;
  1199. }
  1200. Rec->igr_type = ALLOW_NEW_SOURCES;
  1201. Rec->igr_datalen = 0;
  1202. Rec->igr_numsrc = net_short(Count);
  1203. Rec->igr_addr = AddrPtr->iga_addr;
  1204. *RecSize = RECORD_SIZE(Count,Rec->igr_datalen);
  1205. return Rec;
  1206. }
  1207. // Count a state-change report as going out, and preserve the invariant
  1208. // that iga_xmitleft>0 if iga_changetype!=NO_CHANGE
  1209. //
  1210. VOID
  1211. IgmpDecXmitLeft(
  1212. IN IGMPAddr *AddrPtr)
  1213. {
  1214. AddrPtr->iga_xmitleft--;
  1215. if (!AddrPtr->iga_xmitleft) {
  1216. AddrPtr->iga_changetype = NO_CHANGE;
  1217. }
  1218. }
  1219. //* GetBlockRecord - allocate and fill in an IGMPv3 BLOCK record for a group
  1220. //
  1221. // Caller is responsible for freeing pointer returned
  1222. IGMPv3GroupRecord *
  1223. GetBlockRecord(
  1224. IN IGMPAddr *AddrPtr,
  1225. IN uint *RecSize)
  1226. {
  1227. IGMPSrcAddr *Src, *PrevSrc;
  1228. IGMPv3GroupRecord *Rec;
  1229. ushort Count = 0;
  1230. // We now need to decrement the retransmission count on the group.
  1231. // This must be done exactly once for every pair of ALLOW/BLOCK
  1232. // records possibly generated. We centralize this code in one place
  1233. // by putting it in either GetAllowRecord or GetBlockRecord (which
  1234. // are always called together). We arbitrarily choose to put it
  1235. // in GetBlockRecord, rather than GetAllowRecord (which isn't currently
  1236. // called from LeaveAllIGMPAddr).
  1237. //
  1238. IgmpDecXmitLeft(AddrPtr);
  1239. // Count sources to include
  1240. for (Src=AddrPtr->iga_srclist; Src; Src=Src->isa_next) {
  1241. if (Src->isa_xmitleft == 0)
  1242. continue;
  1243. if (IS_SOURCE_ALLOWED(AddrPtr, Src))
  1244. continue;
  1245. Count++;
  1246. }
  1247. if (Count == 0) {
  1248. *RecSize = 0;
  1249. return NULL;
  1250. }
  1251. // Allocate record
  1252. Rec = CTEAllocMemN(RECORD_SIZE(Count,0), 'qICT');
  1253. //
  1254. // We need to walk the source list regardless of whether the
  1255. // allocation succeeded, so that we preserve the invariant that
  1256. // iga_xmitleft >= isa_xmitleft for all sources.
  1257. //
  1258. Count = 0;
  1259. PrevSrc = STRUCT_OF(IGMPSrcAddr, &AddrPtr->iga_srclist, isa_next);
  1260. for (Src=AddrPtr->iga_srclist; Src; PrevSrc=Src,Src=Src->isa_next) {
  1261. if (Src->isa_xmitleft == 0)
  1262. continue;
  1263. if (IS_SOURCE_ALLOWED(AddrPtr, Src))
  1264. continue;
  1265. if (Rec)
  1266. Rec->igr_srclist[Count++] = Src->isa_addr;
  1267. Src->isa_xmitleft--;
  1268. if (IS_SOURCE_DELETABLE(Src)) {
  1269. DeleteIGMPSrcAddr(PrevSrc, &Src);
  1270. Src = PrevSrc;
  1271. }
  1272. }
  1273. if (Rec == NULL) {
  1274. *RecSize = 0;
  1275. return NULL;
  1276. }
  1277. Rec->igr_type = BLOCK_OLD_SOURCES;
  1278. Rec->igr_datalen = 0;
  1279. Rec->igr_numsrc = net_short(Count);
  1280. Rec->igr_addr = AddrPtr->iga_addr;
  1281. *RecSize = RECORD_SIZE(Count,Rec->igr_datalen);
  1282. return Rec;
  1283. }
  1284. //* GetGSIsInRecord - allocate and fill in an IGMPv3 IS_IN record for a
  1285. // group-and-source query response.
  1286. //
  1287. // Caller is responsible for freeing pointer returned
  1288. IGMPv3GroupRecord *
  1289. GetGSIsInRecord(
  1290. IN IGMPAddr *AddrPtr,
  1291. IN uint *RecSize)
  1292. {
  1293. IGMPSrcAddr *Src, *PrevSrc;
  1294. IGMPv3GroupRecord *Rec;
  1295. ushort Count = 0;
  1296. // Count sources marked and included
  1297. for (Src=AddrPtr->iga_srclist; Src; Src=Src->isa_next) {
  1298. if (!IS_SOURCE_ALLOWED(AddrPtr, Src))
  1299. continue;
  1300. if (!Src->isa_csmarked)
  1301. continue;
  1302. Count++;
  1303. }
  1304. // Allocate record
  1305. Rec = CTEAllocMemN(RECORD_SIZE(Count,0), 'qICT');
  1306. if (Rec == NULL) {
  1307. *RecSize = 0;
  1308. return NULL;
  1309. }
  1310. Count = 0;
  1311. PrevSrc = STRUCT_OF(IGMPSrcAddr, &AddrPtr->iga_srclist, isa_next);
  1312. for (Src=AddrPtr->iga_srclist; Src; PrevSrc=Src,Src=Src->isa_next) {
  1313. if (!IS_SOURCE_ALLOWED(AddrPtr, Src))
  1314. continue;
  1315. if (!Src->isa_csmarked)
  1316. continue;
  1317. Rec->igr_srclist[Count++] = Src->isa_addr;
  1318. Src->isa_csmarked = FALSE;
  1319. if (IS_SOURCE_DELETABLE(Src)) {
  1320. DeleteIGMPSrcAddr(PrevSrc, &Src);
  1321. Src = PrevSrc;
  1322. }
  1323. }
  1324. Rec->igr_type = MODE_IS_INCLUDE;
  1325. Rec->igr_datalen = 0;
  1326. Rec->igr_numsrc = net_short(Count);
  1327. Rec->igr_addr = AddrPtr->iga_addr;
  1328. *RecSize = RECORD_SIZE(Count,Rec->igr_datalen);
  1329. return Rec;
  1330. }
  1331. //* GetInclRecord - allocate and fill in an IGMPv3 TO_IN or IS_IN record for
  1332. // a group
  1333. //
  1334. // Caller is responsible for freeing pointer returned
  1335. IGMPv3GroupRecord *
  1336. GetInclRecord(
  1337. IN IGMPAddr *AddrPtr,
  1338. IN uint *RecSize,
  1339. IN uchar Type)
  1340. {
  1341. IGMPSrcAddr *Src, *PrevSrc;
  1342. IGMPv3GroupRecord *Rec;
  1343. ushort Count = 0;
  1344. // Count sources
  1345. for (Src=AddrPtr->iga_srclist; Src; Src=Src->isa_next) {
  1346. if (!IS_SOURCE_ALLOWED(AddrPtr, Src))
  1347. continue;
  1348. Count++;
  1349. }
  1350. // Allocate record
  1351. Rec = CTEAllocMemN(RECORD_SIZE(Count,0), 'qICT');
  1352. if (Rec == NULL) {
  1353. *RecSize = 0;
  1354. return NULL;
  1355. }
  1356. //
  1357. // Walk the source list, making sure to preserve the invariants:
  1358. // iga_xmitleft >= isa_xmitleft for all sources, and
  1359. // iga_resptimer>0 whenever isa_csmarked is TRUE.
  1360. //
  1361. Count = 0;
  1362. PrevSrc = STRUCT_OF(IGMPSrcAddr, &AddrPtr->iga_srclist, isa_next);
  1363. for (Src=AddrPtr->iga_srclist; Src; PrevSrc=Src,Src=Src->isa_next) {
  1364. if ((Type == CHANGE_TO_INCLUDE_MODE) && (Src->isa_xmitleft > 0))
  1365. Src->isa_xmitleft--;
  1366. if (IS_SOURCE_ALLOWED(AddrPtr, Src)) {
  1367. Rec->igr_srclist[Count++] = Src->isa_addr;
  1368. Src->isa_csmarked = FALSE;
  1369. }
  1370. if (IS_SOURCE_DELETABLE(Src)) {
  1371. DeleteIGMPSrcAddr(PrevSrc, &Src);
  1372. Src = PrevSrc;
  1373. }
  1374. }
  1375. Rec->igr_type = Type;
  1376. Rec->igr_datalen = 0;
  1377. Rec->igr_numsrc = net_short(Count);
  1378. Rec->igr_addr = AddrPtr->iga_addr;
  1379. if (Type == CHANGE_TO_INCLUDE_MODE) {
  1380. IgmpDecXmitLeft(AddrPtr);
  1381. }
  1382. *RecSize = RECORD_SIZE(Count,Rec->igr_datalen);
  1383. return Rec;
  1384. }
  1385. #define GetIsInRecord(Grp, RecSz) \
  1386. GetInclRecord(Grp, RecSz, MODE_IS_INCLUDE)
  1387. #define GetToInRecord(Grp, RecSz) \
  1388. GetInclRecord(Grp, RecSz, CHANGE_TO_INCLUDE_MODE)
  1389. //* GetExclRecord - allocate and fill in an IGMPv3 TO_EX or IS_EX record for
  1390. // a group
  1391. //
  1392. // Caller is responsible for freeing pointer returned
  1393. IGMPv3GroupRecord *
  1394. GetExclRecord(
  1395. IN IGMPAddr *AddrPtr,
  1396. IN uint *RecSize,
  1397. IN uint BodyMTU,
  1398. IN uchar Type)
  1399. {
  1400. IGMPSrcAddr *Src, *PrevSrc;
  1401. IGMPv3GroupRecord *Rec;
  1402. ushort Count = 0;
  1403. // Count sources
  1404. for (Src=AddrPtr->iga_srclist; Src; Src=Src->isa_next) {
  1405. if (IS_SOURCE_ALLOWED(AddrPtr, Src))
  1406. continue;
  1407. Count++;
  1408. }
  1409. // Allocate record
  1410. Rec = CTEAllocMemN(RECORD_SIZE(Count,0), 'qICT');
  1411. if (Rec == NULL) {
  1412. *RecSize = 0;
  1413. return NULL;
  1414. }
  1415. //
  1416. // Walk the source list, making sure to preserve the invariants:
  1417. // iga_xmitleft <= isa_xmitleft for all sources, and
  1418. // iga_resptimer>0 whenever isa_csmarked is TRUE.
  1419. //
  1420. Count = 0;
  1421. PrevSrc = STRUCT_OF(IGMPSrcAddr, &AddrPtr->iga_srclist, isa_next);
  1422. for (Src=AddrPtr->iga_srclist; Src; PrevSrc=Src,Src=Src->isa_next) {
  1423. if ((Type == CHANGE_TO_EXCLUDE_MODE) && (Src->isa_xmitleft > 0))
  1424. Src->isa_xmitleft--;
  1425. if (!IS_SOURCE_ALLOWED(AddrPtr, Src)) {
  1426. Rec->igr_srclist[Count++] = Src->isa_addr;
  1427. Src->isa_csmarked = FALSE;
  1428. }
  1429. if (IS_SOURCE_DELETABLE(Src)) {
  1430. DeleteIGMPSrcAddr(PrevSrc, &Src);
  1431. Src = PrevSrc;
  1432. }
  1433. }
  1434. Rec->igr_type = Type;
  1435. Rec->igr_datalen = 0;
  1436. Rec->igr_numsrc = net_short(Count);
  1437. Rec->igr_addr = AddrPtr->iga_addr;
  1438. if (Type == CHANGE_TO_EXCLUDE_MODE) {
  1439. IgmpDecXmitLeft(AddrPtr);
  1440. }
  1441. *RecSize = RECORD_SIZE(Count,Rec->igr_datalen);
  1442. // Truncate at MTU boundary
  1443. if (*RecSize > BodyMTU) {
  1444. *RecSize = BodyMTU;
  1445. }
  1446. return Rec;
  1447. }
  1448. #define GetIsExRecord(Grp, RecSz, BodyMTU) \
  1449. GetExclRecord(Grp, RecSz, BodyMTU, MODE_IS_EXCLUDE)
  1450. #define GetToExRecord(Grp, RecSz, BodyMTU) \
  1451. GetExclRecord(Grp, RecSz, BodyMTU, CHANGE_TO_EXCLUDE_MODE)
  1452. //* QueueRecord - Queue an IGMPv3 group record for transmission.
  1453. // If the record cannot be queued, the record is dropped and the
  1454. // memory freed.
  1455. //
  1456. // Input: pCurr = pointer to last queue entry
  1457. // Record = record to append to end of queue
  1458. // RecSize = size of record to queue
  1459. //
  1460. // Output: pCurr = pointer to new queue entry
  1461. // Record = zeroed if queue failed and record was freed
  1462. //
  1463. // Returns: status
  1464. //
  1465. IP_STATUS
  1466. QueueRecord(
  1467. IN OUT IGMPv3RecordQueueEntry **pCurr,
  1468. IN OUT IGMPv3GroupRecord **pRecord,
  1469. IN uint RecSize)
  1470. {
  1471. IGMPv3RecordQueueEntry *rqe;
  1472. IGMPv3GroupRecord *Record = *pRecord;
  1473. IP_STATUS Status = IP_SUCCESS;
  1474. if (!Record) {
  1475. return IP_SUCCESS;
  1476. }
  1477. do {
  1478. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_TX,
  1479. (DTEXT("QueueRecord: Record=%x Type=%d Group=%x NumSrc=%d\n"),
  1480. Record, Record->igr_type, Record->igr_addr,
  1481. net_short(Record->igr_numsrc)));
  1482. //
  1483. // Make sure we never add a record for the all-hosts mcast address.
  1484. //
  1485. if (IP_ADDR_EQUAL(Record->igr_addr, ALL_HOST_MCAST)) {
  1486. Status = IP_BAD_REQ;
  1487. break;
  1488. }
  1489. // Allocate a queue entry
  1490. rqe = CTEAllocMemN(sizeof(IGMPv3RecordQueueEntry), 'qICT');
  1491. if (rqe == NULL) {
  1492. Status = IP_NO_RESOURCES;
  1493. break;
  1494. }
  1495. rqe->i3qe_next = NULL;
  1496. rqe->i3qe_buff = Record;
  1497. rqe->i3qe_size = RecSize;
  1498. // Append to queue
  1499. (*pCurr)->i3qe_next = rqe;
  1500. *pCurr = rqe;
  1501. } while (FALSE);
  1502. if (Status != IP_SUCCESS) {
  1503. // Free buffers
  1504. CTEFreeMem(Record);
  1505. *pRecord = NULL;
  1506. }
  1507. return Status;
  1508. }
  1509. VOID
  1510. FlushIGMPv3Queue(
  1511. IN IGMPv3RecordQueueEntry *Head)
  1512. {
  1513. IGMPv3RecordQueueEntry *Rqe;
  1514. while ((Rqe = Head) != NULL) {
  1515. // Remove entry from queue
  1516. Head = Rqe->i3qe_next;
  1517. Rqe->i3qe_next = NULL;
  1518. // Free queued record
  1519. CTEFreeMem(Rqe->i3qe_buff);
  1520. CTEFreeMem(Rqe);
  1521. }
  1522. }
  1523. //* SendIGMPv3Reports - send pending IGMPv3 reports
  1524. //
  1525. // Input: Head - queue of IGMPv3 records to transmit
  1526. // SrcAddr - source address to send with
  1527. // BodyMTU - message payload size available to pack records in
  1528. IP_STATUS
  1529. SendIGMPv3Reports(
  1530. IN IGMPv3RecordQueueEntry *Head,
  1531. IN IPAddr SrcAddr,
  1532. IN uint BodyMTU)
  1533. {
  1534. PNDIS_BUFFER HdrBuffer;
  1535. uint HdrSize;
  1536. IGMPv3ReportHeader *IGH;
  1537. PNDIS_BUFFER BodyBuffer;
  1538. uint BodySize;
  1539. uchar* Body;
  1540. IP_STATUS Status;
  1541. uint NumRecords;
  1542. ushort NumOldSources, NumNewSources;
  1543. IGMPv3RecordQueueEntry *Rqe;
  1544. IGMPv3GroupRecord *Rec, *HeadRec;
  1545. BOOLEAN Ret;
  1546. ulong csum;
  1547. while (Head != NULL) {
  1548. // Get header buffer
  1549. HdrSize = sizeof(IGMPv3ReportHeader);
  1550. IGH = (IGMPv3ReportHeader*) GetIGMPBuffer(HdrSize, &HdrBuffer);
  1551. if (IGH == NULL) {
  1552. FlushIGMPv3Queue(Head);
  1553. return IP_NO_RESOURCES;
  1554. }
  1555. // We got the buffer. Fill it in and send it.
  1556. IGH->igh_vertype = (UCHAR) IGMP_REPORT_V3;
  1557. IGH->igh_rsvd = 0;
  1558. IGH->igh_rsvd2 = 0;
  1559. // Compute optimum body size
  1560. for (;;) {
  1561. NumRecords = 0;
  1562. BodySize = 0;
  1563. for (Rqe=Head; Rqe; Rqe=Rqe->i3qe_next) {
  1564. if (BodySize + Rqe->i3qe_size > BodyMTU)
  1565. break;
  1566. BodySize += Rqe->i3qe_size;
  1567. NumRecords++;
  1568. }
  1569. // Make sure we fit at least one record
  1570. if (NumRecords > 0)
  1571. break;
  1572. //
  1573. // No records fit. Let's split the first record and try again.
  1574. // Note that igr_datalen is always 0 today. If there is data
  1575. // later, then splitting will need to know whether to copy
  1576. // the data or not. Today we assume not.
  1577. //
  1578. HeadRec = Head->i3qe_buff;
  1579. NumOldSources = (BodyMTU - sizeof(IGMPv3GroupRecord)) / sizeof(IPAddr);
  1580. NumNewSources = net_short(HeadRec->igr_numsrc) - NumOldSources;
  1581. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_TX,
  1582. (DTEXT("SendIGMPv3Reports: Splitting queue entry %x Srcs=%d+%d\n"),
  1583. HeadRec, NumOldSources, NumNewSources));
  1584. // Truncate head
  1585. HeadRec->igr_numsrc = net_short(NumOldSources);
  1586. Head->i3qe_size = RECORD_SIZE(NumOldSources, HeadRec->igr_datalen);
  1587. // Special case for IS_EX/TO_EX: just truncate or else the router
  1588. // will end up forwarding all the sources we exclude in messages
  1589. // other than the last one.
  1590. if (HeadRec->igr_type == MODE_IS_EXCLUDE
  1591. || HeadRec->igr_type == CHANGE_TO_EXCLUDE_MODE) {
  1592. continue;
  1593. }
  1594. // Create a new record with NumNewSources sources
  1595. Rec = CTEAllocMemN(RECORD_SIZE(NumNewSources,0), 'qICT');
  1596. if (Rec == NULL) {
  1597. // Forget the continuation, just send the truncated original.
  1598. continue;
  1599. }
  1600. Rec->igr_type = HeadRec->igr_type;
  1601. Rec->igr_datalen = 0;
  1602. Rec->igr_numsrc = net_short(NumNewSources);
  1603. Rec->igr_addr = HeadRec->igr_addr;
  1604. RtlCopyMemory(Rec->igr_srclist,
  1605. &HeadRec->igr_srclist[NumOldSources],
  1606. NumNewSources * sizeof(IPAddr));
  1607. // Append it
  1608. Rqe = Head;
  1609. QueueRecord(&Rqe, &Rec, RECORD_SIZE(NumNewSources,
  1610. Rec->igr_datalen));
  1611. }
  1612. // Get another ndis buffer for the body
  1613. Body = CTEAllocMemN(BodySize, 'bICT');
  1614. if (Body == NULL) {
  1615. FreeIGMPBuffer(HdrBuffer);
  1616. FlushIGMPv3Queue(Head);
  1617. return IP_NO_RESOURCES;
  1618. }
  1619. NdisAllocateBuffer(&Status, &BodyBuffer, BufferPool, Body, BodySize);
  1620. NDIS_BUFFER_LINKAGE(HdrBuffer) = BodyBuffer;
  1621. // Fill in records
  1622. NumRecords = 0;
  1623. BodySize = 0;
  1624. csum = 0;
  1625. while ((Rqe = Head) != NULL) {
  1626. if (BodySize + Rqe->i3qe_size > BodyMTU)
  1627. break;
  1628. // Remove from queue
  1629. Head = Rqe->i3qe_next;
  1630. Rqe->i3qe_next = NULL;
  1631. // update checksum
  1632. csum += xsum((uchar *)Rqe->i3qe_buff, Rqe->i3qe_size);
  1633. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_TX,
  1634. (DTEXT("SendRecord: Record=%x RecSize=%d Type=%d Group=%x Body=%x Offset=%d\n"),
  1635. Rqe->i3qe_buff, Rqe->i3qe_size, Rqe->i3qe_buff->igr_type,
  1636. Rqe->i3qe_buff->igr_addr, Body, BodySize));
  1637. RtlCopyMemory(Body + BodySize, (uchar *)Rqe->i3qe_buff,
  1638. Rqe->i3qe_size);
  1639. BodySize += Rqe->i3qe_size;
  1640. NumRecords++;
  1641. CTEFreeMem(Rqe->i3qe_buff);
  1642. CTEFreeMem(Rqe);
  1643. }
  1644. // Finish header
  1645. IGH->igh_xsum = 0;
  1646. IGH->igh_numrecords = net_short(NumRecords);
  1647. csum += xsum(IGH, sizeof(IGMPv3ReportHeader));
  1648. // Fold the checksum down.
  1649. csum = (csum >> 16) + (csum & 0xffff);
  1650. csum += (csum >> 16);
  1651. IGH->igh_xsum = (ushort)~csum;
  1652. Status = IGMPTransmit(HdrBuffer, Body, HdrSize + BodySize, SrcAddr,
  1653. IGMPV3_RTRS_MCAST);
  1654. }
  1655. return Status;
  1656. }
  1657. //* QueueIGMPv3GeneralResponse - compose and queue IGMPv3 responses to general
  1658. // query
  1659. IP_STATUS
  1660. QueueIGMPv3GeneralResponse(
  1661. IN IGMPv3RecordQueueEntry **pCurr,
  1662. IN NetTableEntry *NTE)
  1663. {
  1664. IGMPAddr **HashPtr, *AddrPtr;
  1665. uint i;
  1666. IGMPv3GroupRecord *StateRec;
  1667. uint StateRecSize;
  1668. uint BodyMTU;
  1669. BodyMTU = RECORD_MTU(NTE);
  1670. //
  1671. // Walk our list and set a random report timer for all those
  1672. // multicast addresses (except for the all-hosts address) that
  1673. // don't already have one running.
  1674. //
  1675. HashPtr = NTE->nte_igmplist;
  1676. if (HashPtr != NULL) {
  1677. for (i = 0; i < IGMP_TABLE_SIZE; i++) {
  1678. for (AddrPtr = HashPtr[i];
  1679. AddrPtr != NULL;
  1680. AddrPtr = AddrPtr->iga_next)
  1681. {
  1682. if (IP_ADDR_EQUAL(AddrPtr->iga_addr, ALL_HOST_MCAST))
  1683. continue;
  1684. if (AddrPtr->iga_grefcnt == 0)
  1685. StateRec = GetIsInRecord(AddrPtr, &StateRecSize);
  1686. else
  1687. StateRec = GetIsExRecord(AddrPtr, &StateRecSize, BodyMTU);
  1688. QueueRecord(pCurr, &StateRec, StateRecSize);
  1689. }
  1690. }
  1691. }
  1692. return IP_SUCCESS;
  1693. }
  1694. //* QueueOldReport - create and queue an IGMPv1/v2 membership report to be sent
  1695. IP_STATUS
  1696. QueueOldReport(
  1697. IN IGMPReportQueueEntry **pCurr,
  1698. IN uint ChangeType,
  1699. IN uint IgmpVersion,
  1700. IN IPAddr Group)
  1701. {
  1702. IGMPReportQueueEntry *rqe;
  1703. IGMPHeader *IGH;
  1704. uint ReportType, Size;
  1705. IPAddr Dest;
  1706. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_TX,
  1707. (DTEXT("QueueOldReport: Type=%d Vers=%d Group=%x\n"),
  1708. ChangeType, IgmpVersion, Group));
  1709. //
  1710. // Make sure we never queue a report for the all-hosts mcast address.
  1711. //
  1712. if (IP_ADDR_EQUAL(Group, ALL_HOST_MCAST)) {
  1713. return IP_BAD_REQ;
  1714. }
  1715. //
  1716. // If the report to be sent is a "Leave Group" report but we have
  1717. // detected an igmp v1 router on this net, do not send the report
  1718. //
  1719. if (IgmpVersion == IGMPV1) {
  1720. if (ChangeType == IGMP_DELETE) {
  1721. return IP_SUCCESS;
  1722. } else {
  1723. ReportType = IGMP_REPORT_V1;
  1724. Dest = Group;
  1725. }
  1726. } else {
  1727. if (ChangeType == IGMP_DELETE) {
  1728. ReportType = IGMP_LEAVE;
  1729. Dest = ALL_ROUTER_MCAST;
  1730. } else {
  1731. ReportType = IGMP_REPORT_V2;
  1732. Dest = Group;
  1733. }
  1734. }
  1735. // Allocate an IGMP report
  1736. Size = sizeof(IGMPHeader);
  1737. IGH = (IGMPHeader *) CTEAllocMemN(Size, 'hICT');
  1738. if (IGH == NULL) {
  1739. return IP_NO_RESOURCES;
  1740. }
  1741. IGH->igh_vertype = (UCHAR) ReportType;
  1742. IGH->igh_rsvd = 0;
  1743. IGH->igh_xsum = 0;
  1744. IGH->igh_addr = Group;
  1745. IGH->igh_xsum = ~xsum(IGH, Size);
  1746. // Allocate a queue entry
  1747. rqe = (IGMPReportQueueEntry *) CTEAllocMemN(sizeof(IGMPReportQueueEntry),
  1748. 'qICT');
  1749. if (rqe == NULL) {
  1750. CTEFreeMem(IGH);
  1751. return IP_NO_RESOURCES;
  1752. }
  1753. rqe->iqe_next = NULL;
  1754. rqe->iqe_buff = IGH;
  1755. rqe->iqe_size = Size;
  1756. rqe->iqe_dest = Dest;
  1757. ASSERT((IGH != NULL) && (Size > 0));
  1758. // Append to queue
  1759. (*pCurr)->iqe_next = rqe;
  1760. *pCurr = rqe;
  1761. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_TX,
  1762. (DTEXT("QueueOldReport: added rqe=%x buff=%x size=%d\n"),
  1763. rqe, rqe->iqe_buff, rqe->iqe_size));
  1764. return IP_SUCCESS;
  1765. }
  1766. //* SendOldReport - send an IGMPv1/v2 membership report
  1767. IP_STATUS
  1768. SendOldReport(
  1769. IN IGMPReportQueueEntry *Rqe,
  1770. IN IPAddr SrcAddr)
  1771. {
  1772. PNDIS_BUFFER Buffer;
  1773. IPOptInfo OptInfo; // Options for this transmit.
  1774. IP_STATUS Status;
  1775. int ReportType, RecordType;
  1776. IPAddr GrpAdd;
  1777. uchar RtrAlertOpt[4] = { IP_OPT_ROUTER_ALERT, 4, 0, 0 };
  1778. uint Size, Offset;
  1779. IGMPHeader *IGH;
  1780. uchar **pIGMPBuff, *IGH2;
  1781. IPAddr DestAddr;
  1782. //ASSERT(!IP_ADDR_EQUAL(SrcAddr, NULL_IP_ADDR));
  1783. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_TX,
  1784. (DTEXT("SendOldReport: rqe=%x buff=%x size=%x\n"),
  1785. Rqe, Rqe->iqe_buff, Rqe->iqe_size));
  1786. IGH = Rqe->iqe_buff;
  1787. ASSERT(IGH != NULL);
  1788. Size = Rqe->iqe_size;
  1789. ASSERT(Size > 0);
  1790. DestAddr = Rqe->iqe_dest;
  1791. IGH2 = (uchar*)GetIGMPBuffer(Size, &Buffer);
  1792. if (IGH2 == NULL) {
  1793. CTEFreeMem(IGH);
  1794. Rqe->iqe_buff = NULL;
  1795. return IP_NO_RESOURCES;
  1796. }
  1797. RtlCopyMemory(IGH2, (uchar *)IGH, Size);
  1798. CTEFreeMem(IGH);
  1799. Rqe->iqe_buff = NULL;
  1800. return IGMPTransmit(Buffer, NULL, Size, SrcAddr, DestAddr);
  1801. }
  1802. //* SendOldReports - send pending IGMPv1/v2 membership reports
  1803. void
  1804. SendOldReports(
  1805. IN IGMPReportQueueEntry *Head,
  1806. IN IPAddr SrcAddr)
  1807. {
  1808. IGMPReportQueueEntry *rqe;
  1809. while ((rqe = Head) != NULL) {
  1810. // Remove from queue
  1811. Head = rqe->iqe_next;
  1812. rqe->iqe_next = NULL;
  1813. SendOldReport(rqe, SrcAddr);
  1814. CTEFreeMem(rqe);
  1815. }
  1816. }
  1817. //////////////////////////////////////////////////////////////////////////////
  1818. // Mark changes for triggered reports
  1819. //////////////////////////////////////////////////////////////////////////////
  1820. // Should only be called for leaves if in IGMPv3 mode,
  1821. // but should be called for joins always.
  1822. void
  1823. MarkGroup(
  1824. IN IGMPAddr *Grp)
  1825. {
  1826. // No reports are sent for the ALL_HOST_MCAST group
  1827. if (IP_ADDR_EQUAL(Grp->iga_addr, ALL_HOST_MCAST)) {
  1828. return;
  1829. }
  1830. Grp->iga_changetype = MODE_CHANGE;
  1831. Grp->iga_xmitleft = g_IgmpRobustness;
  1832. }
  1833. // Should only be called if in IGMPv3 mode
  1834. void
  1835. MarkSource(
  1836. IN IGMPAddr *Grp,
  1837. IN IGMPSrcAddr *Src)
  1838. {
  1839. // No reports are sent for the ALL_HOST_MCAST group
  1840. if (IP_ADDR_EQUAL(Grp->iga_addr, ALL_HOST_MCAST)) {
  1841. return;
  1842. }
  1843. Src->isa_xmitleft = g_IgmpRobustness;
  1844. Grp->iga_xmitleft = g_IgmpRobustness;
  1845. if (Grp->iga_changetype == NO_CHANGE) {
  1846. Grp->iga_changetype = SOURCE_CHANGE;
  1847. }
  1848. }
  1849. //* IGMPDelExclList - delete sources from an internal source exclude list
  1850. //
  1851. // This never affects link-layer filters.
  1852. // Assumes caller holds lock on NTE
  1853. void
  1854. IGMPDelExclList(
  1855. IN NetTableEntry *NTE,
  1856. IN IGMPAddr *PrevAddrPtr,
  1857. IN OUT IGMPAddr **pAddrPtr,
  1858. IN uint NumDelSources,
  1859. IN IPAddr *DelSourceList,
  1860. IN BOOLEAN AllowMsg)
  1861. {
  1862. uint i, j;
  1863. IGMPSrcAddr *Src, *PrevSrc;
  1864. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  1865. (DTEXT("IGMPDelExclList: AddrPtr=%x NumDelSources=%d DelSourceList=%x\n"),
  1866. *pAddrPtr, NumDelSources, DelSourceList));
  1867. for (i=0; i<NumDelSources; i++) {
  1868. // Find the source entry
  1869. Src = FindIGMPSrcAddr(*pAddrPtr, DelSourceList[i], &PrevSrc);
  1870. // Break if not there or xrefcnt=0
  1871. ASSERT(Src && (Src->isa_xrefcnt!=0));
  1872. if (AllowMsg && (NTE->nte_if->IgmpVersion == IGMPV3)) {
  1873. // If all sockets exclude and no sockets include, add source
  1874. // to IGMP ALLOW message
  1875. if (!IS_SOURCE_ALLOWED(*pAddrPtr, Src)) {
  1876. // Add source to ALLOW message
  1877. MarkSource(*pAddrPtr, Src);
  1878. }
  1879. }
  1880. // Decrement the xrefcnt
  1881. Src->isa_xrefcnt--;
  1882. // If irefcnt and xrefcnt are both 0 and no rexmits left,
  1883. // delete the source entry
  1884. if (IS_SOURCE_DELETABLE(Src))
  1885. DeleteIGMPSrcAddr(PrevSrc, &Src);
  1886. // If the group refcount=0, and srclist is null, delete group entry
  1887. if (IS_GROUP_DELETABLE(*pAddrPtr))
  1888. DeleteIGMPAddr(NTE, PrevAddrPtr, pAddrPtr);
  1889. }
  1890. }
  1891. //* IGMPDelInclList - delete sources from an internal source include list
  1892. //
  1893. // Assumes caller holds lock on NTE
  1894. void
  1895. IGMPDelInclList(
  1896. IN CTELockHandle *pHandle,
  1897. IN NetTableEntry *NTE,
  1898. IN IGMPAddr **pPrevAddrPtr,
  1899. IN OUT IGMPAddr **pAddrPtr,
  1900. IN uint NumDelSources,
  1901. IN IPAddr *DelSourceList,
  1902. IN BOOLEAN BlockMsg)
  1903. {
  1904. uint i, j;
  1905. IGMPSrcAddr *Src, *PrevSrc;
  1906. BOOLEAN GroupWasAllowed;
  1907. BOOLEAN GroupNowAllowed;
  1908. IPAddr Addr;
  1909. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  1910. (DTEXT("IGMPDelInclList: AddrPtr=%x NumDelSources=%d DelSourceList=%x\n"),
  1911. *pAddrPtr, NumDelSources, DelSourceList));
  1912. Addr = (*pAddrPtr)->iga_addr;
  1913. GroupWasAllowed = IS_GROUP_ALLOWED(*pAddrPtr);
  1914. for (i=0; i<NumDelSources; i++) {
  1915. // Find the source entry
  1916. Src = FindIGMPSrcAddr(*pAddrPtr, DelSourceList[i], &PrevSrc);
  1917. // Break if not there or irefcnt=0
  1918. ASSERT(Src && (Src->isa_irefcnt!=0));
  1919. // Decrement the irefcnt
  1920. Src->isa_irefcnt--;
  1921. if (Src->isa_irefcnt == 0) {
  1922. (*pAddrPtr)->iga_isrccnt--;
  1923. }
  1924. if (BlockMsg && (NTE->nte_if->IgmpVersion == IGMPV3)) {
  1925. // If all sockets exclude and no sockets include, add source
  1926. // to IGMP BLOCK message
  1927. if (!IS_SOURCE_ALLOWED(*pAddrPtr, Src)) {
  1928. // Add source to BLOCK message
  1929. MarkSource(*pAddrPtr, Src);
  1930. }
  1931. }
  1932. // If irefcnt and xrefcnt are both 0 and no rexmits left,
  1933. // delete the source entry
  1934. if (IS_SOURCE_DELETABLE(Src))
  1935. DeleteIGMPSrcAddr(PrevSrc, &Src);
  1936. // If the group refcount=0, and srclist is null, delete group entry
  1937. if (IS_GROUP_DELETABLE(*pAddrPtr))
  1938. DeleteIGMPAddr(NTE, *pPrevAddrPtr, pAddrPtr);
  1939. }
  1940. GroupNowAllowed = (*pAddrPtr != NULL) && IS_GROUP_ALLOWED(*pAddrPtr);
  1941. if (GroupWasAllowed && !GroupNowAllowed) {
  1942. if (*pAddrPtr) {
  1943. // Cancel response timer if running
  1944. CancelGroupResponseTimer(*pAddrPtr);
  1945. if (IS_GROUP_DELETABLE(*pAddrPtr))
  1946. DeleteIGMPAddr(NTE, *pPrevAddrPtr, pAddrPtr);
  1947. }
  1948. // update link-layer filter
  1949. CTEFreeLock(&NTE->nte_lock, *pHandle);
  1950. {
  1951. (*NTE->nte_if->if_deladdr) (NTE->nte_if->if_lcontext,
  1952. LLIP_ADDR_MCAST, Addr, 0);
  1953. }
  1954. CTEGetLock(&NTE->nte_lock, pHandle);
  1955. // Revalidate NTE, AddrPtr, PrevPtr
  1956. if (!(NTE->nte_flags & NTE_VALID)) {
  1957. *pAddrPtr = *pPrevAddrPtr = NULL;
  1958. return;
  1959. }
  1960. *pAddrPtr = FindIGMPAddr(NTE, Addr, pPrevAddrPtr);
  1961. }
  1962. }
  1963. //* IGMPAddExclList - add sources to an internal source exclude list
  1964. //
  1965. // This never affects link-layer filters.
  1966. // Assumes caller holds lock on NTE
  1967. // If failure results, the source list will be unchanged afterwards
  1968. // but the group entry may have been deleted.
  1969. IP_STATUS
  1970. IGMPAddExclList(
  1971. IN NetTableEntry *NTE,
  1972. IN IGMPAddr *PrevAddrPtr,
  1973. IN OUT IGMPAddr **pAddrPtr,
  1974. IN uint NumAddSources,
  1975. IN IPAddr *AddSourceList)
  1976. {
  1977. uint i, j;
  1978. IGMPSrcAddr *Src, *PrevSrc;
  1979. IP_STATUS Status = IP_SUCCESS;
  1980. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  1981. (DTEXT("IGMPAddExclList: AddrPtr=%x NumAddSources=%d AddSourceList=%x\n"),
  1982. *pAddrPtr, NumAddSources, AddSourceList));
  1983. for (i=0; i<NumAddSources; i++) {
  1984. // If an IGMPSrcAddr entry for the source doesn't exist, create one.
  1985. Status = FindOrCreateIGMPSrcAddr(*pAddrPtr, AddSourceList[i], &Src,
  1986. &PrevSrc);
  1987. if (Status != IP_SUCCESS) {
  1988. break;
  1989. }
  1990. // Bump the xrefcnt on the source entry
  1991. Src->isa_xrefcnt++;
  1992. // If all sockets exclude and no sockets include, add source
  1993. // to IGMP BLOCK message
  1994. if (!IS_SOURCE_ALLOWED(*pAddrPtr, Src)
  1995. && (NTE->nte_if->IgmpVersion == IGMPV3)) {
  1996. // Add source to BLOCK message
  1997. MarkSource(*pAddrPtr, Src);
  1998. }
  1999. }
  2000. if (Status == IP_SUCCESS)
  2001. return Status;
  2002. // undo previous
  2003. IGMPDelExclList(NTE, PrevAddrPtr, pAddrPtr, i, AddSourceList, FALSE);
  2004. return Status;
  2005. }
  2006. //* IGMPAddInclList - add sources to an internal source include list
  2007. //
  2008. // Assumes caller holds lock on NTE
  2009. //
  2010. // If failure results, the source list will be unchanged afterwards
  2011. // but the group entry may have been deleted.
  2012. IP_STATUS
  2013. IGMPAddInclList(
  2014. IN CTELockHandle *pHandle,
  2015. IN NetTableEntry *NTE,
  2016. IN IGMPAddr **pPrevAddrPtr,
  2017. IN OUT IGMPAddr **pAddrPtr,
  2018. IN uint NumAddSources,
  2019. IN IPAddr *AddSourceList)
  2020. {
  2021. uint i, j, AddrAdded;
  2022. IGMPSrcAddr *Src, *PrevSrc;
  2023. IP_STATUS Status = IP_SUCCESS;
  2024. BOOLEAN GroupWasAllowed;
  2025. BOOLEAN GroupNowAllowed;
  2026. IPAddr Addr;
  2027. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  2028. (DTEXT("IGMPAddInclList: AddrPtr=%x NumAddSources=%d AddSourceList=%x\n"),
  2029. *pAddrPtr, NumAddSources, AddSourceList));
  2030. Addr = (*pAddrPtr)->iga_addr;
  2031. GroupWasAllowed = IS_GROUP_ALLOWED(*pAddrPtr);
  2032. for (i=0; i<NumAddSources; i++) {
  2033. // If an IGMPSrcAddr entry for the source doesn't exist, create one.
  2034. Status = FindOrCreateIGMPSrcAddr(*pAddrPtr, AddSourceList[i], &Src,
  2035. &PrevSrc);
  2036. if (Status != IP_SUCCESS) {
  2037. break;
  2038. }
  2039. // If all sockets exclude and no sockets include, add source
  2040. // to IGMP ALLOW message
  2041. if (!IS_SOURCE_ALLOWED(*pAddrPtr, Src)
  2042. && (NTE->nte_if->IgmpVersion == IGMPV3)) {
  2043. // Add source to ALLOW message
  2044. MarkSource(*pAddrPtr, Src);
  2045. }
  2046. // Bump the irefcnt on the source entry
  2047. if (Src->isa_irefcnt == 0) {
  2048. (*pAddrPtr)->iga_isrccnt++;
  2049. }
  2050. Src->isa_irefcnt++;
  2051. }
  2052. GroupNowAllowed = IS_GROUP_ALLOWED(*pAddrPtr);
  2053. if (!GroupWasAllowed && GroupNowAllowed) {
  2054. // update link-layer filter
  2055. CTEFreeLock(&NTE->nte_lock, *pHandle);
  2056. {
  2057. AddrAdded = (*NTE->nte_if->if_addaddr) (NTE->nte_if->if_lcontext,
  2058. LLIP_ADDR_MCAST, Addr, 0, NULL);
  2059. }
  2060. CTEGetLock(&NTE->nte_lock, pHandle);
  2061. // Revalidate NTE, AddrPtr, PrevPtr
  2062. do {
  2063. if (!(NTE->nte_flags & NTE_VALID)) {
  2064. Status = IP_BAD_REQ;
  2065. break;
  2066. }
  2067. // Find the IGMPAddr entry
  2068. *pAddrPtr = FindIGMPAddr(NTE, Addr, pPrevAddrPtr);
  2069. if (!*pAddrPtr) {
  2070. Status = IP_BAD_REQ;
  2071. break;
  2072. }
  2073. } while (FALSE);
  2074. if (!AddrAdded) {
  2075. Status = IP_NO_RESOURCES;
  2076. }
  2077. }
  2078. if (Status == IP_SUCCESS)
  2079. return Status;
  2080. // undo previous
  2081. IGMPDelInclList(pHandle, NTE, pPrevAddrPtr, pAddrPtr, i, AddSourceList,
  2082. FALSE);
  2083. return Status;
  2084. }
  2085. //* IGMPInclChange - update source inclusion list
  2086. //
  2087. // On failure, inclusion list will be unchanged
  2088. IP_STATUS
  2089. IGMPInclChange(
  2090. IN NetTableEntry *NTE,
  2091. IN IPAddr Addr,
  2092. IN uint NumAddSources,
  2093. IN IPAddr *AddSourceList,
  2094. IN uint NumDelSources,
  2095. IN IPAddr *DelSourceList)
  2096. {
  2097. CTELockHandle Handle;
  2098. IGMPAddr *AddrPtr, *PrevPtr;
  2099. IP_STATUS Status;
  2100. Interface *IF;
  2101. IGMPBlockStruct Block;
  2102. IGMPBlockStruct *BlockPtr;
  2103. uint IgmpVersion = 0, BodyMTU;
  2104. IPAddr SrcAddr;
  2105. IGMPv3GroupRecord *AllowRec = NULL, *BlockRec = NULL;
  2106. uint AllowRecSize = 0, BlockRecSize = 0;
  2107. BOOLEAN GroupWasAllowed = FALSE;
  2108. BOOLEAN GroupNowAllowed = FALSE;
  2109. // First make sure we're at level 2 of IGMP support.
  2110. if (IGMPLevel != 2)
  2111. return IP_BAD_REQ;
  2112. // Make sure addlist and dellist aren't both empty
  2113. ASSERT((NumAddSources > 0) || (NumDelSources > 0));
  2114. if (NTE->nte_flags & NTE_VALID) {
  2115. //
  2116. // If this is an unnumbered interface
  2117. //
  2118. if ((NTE->nte_if->if_flags & IF_FLAGS_NOIPADDR) &&
  2119. IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
  2120. SrcAddr = g_ValidAddr;
  2121. if (IP_ADDR_EQUAL(SrcAddr, NULL_IP_ADDR)) {
  2122. return IP_BAD_REQ;
  2123. }
  2124. } else {
  2125. SrcAddr = NTE->nte_addr;
  2126. }
  2127. }
  2128. CTEInitBlockStruc(&Block.ibs_block);
  2129. // Make sure we're the only ones in this routine. If someone else is
  2130. // already here, block.
  2131. CTEGetLock(&IGMPLock, &Handle);
  2132. if (IGMPBlockFlag) {
  2133. // Someone else is already here. Walk down the block list, and
  2134. // put ourselves on the end. Then free the lock and block on our
  2135. // IGMPBlock structure.
  2136. BlockPtr = STRUCT_OF(IGMPBlockStruct, &IGMPBlockList, ibs_next);
  2137. while (BlockPtr->ibs_next != NULL)
  2138. BlockPtr = BlockPtr->ibs_next;
  2139. Block.ibs_next = NULL;
  2140. BlockPtr->ibs_next = &Block;
  2141. CTEFreeLock(&IGMPLock, Handle);
  2142. CTEBlock(&Block.ibs_block);
  2143. } else {
  2144. // Noone else here, set the flag so noone else gets in and free the
  2145. // lock.
  2146. IGMPBlockFlag = 1;
  2147. CTEFreeLock(&IGMPLock, Handle);
  2148. }
  2149. // Now we're in the routine, and we won't be reentered here by another
  2150. // thread of execution. Make sure everything's valid, and figure out
  2151. // what to do.
  2152. Status = IP_SUCCESS;
  2153. // Now get the lock on the NTE and make sure it's valid.
  2154. CTEGetLock(&NTE->nte_lock, &Handle);
  2155. do {
  2156. if (!(NTE->nte_flags & NTE_VALID)) {
  2157. Status = IP_BAD_REQ;
  2158. break;
  2159. }
  2160. IF = NTE->nte_if;
  2161. BodyMTU = RECORD_MTU(NTE);
  2162. IgmpVersion = IF->IgmpVersion;
  2163. // If an IGMPAddr entry for the group on the interface doesn't
  2164. // exist, create one.
  2165. Status = FindOrCreateIGMPAddr(NTE, Addr, &AddrPtr, &PrevPtr);
  2166. if (Status != IP_SUCCESS) {
  2167. break;
  2168. }
  2169. GroupWasAllowed = IS_GROUP_ALLOWED(AddrPtr);
  2170. // Perform IADDLIST
  2171. Status = IGMPAddInclList(&Handle, NTE, &PrevPtr, &AddrPtr,
  2172. NumAddSources, AddSourceList);
  2173. if (Status != IP_SUCCESS) {
  2174. break;
  2175. }
  2176. // Perform IDELLLIST
  2177. IGMPDelInclList(&Handle, NTE, &PrevPtr, &AddrPtr,
  2178. NumDelSources, DelSourceList, TRUE);
  2179. if (AddrPtr == NULL) {
  2180. GroupNowAllowed = FALSE;
  2181. break;
  2182. } else {
  2183. GroupNowAllowed = IS_GROUP_ALLOWED(AddrPtr);
  2184. }
  2185. if (IgmpVersion == IGMPV3) {
  2186. // Get ALLOC/BLOCK records
  2187. AllowRec = GetAllowRecord(AddrPtr, &AllowRecSize);
  2188. BlockRec = GetBlockRecord(AddrPtr, &BlockRecSize);
  2189. // Set retransmission timer
  2190. AddrPtr->iga_trtimer = IGMPRandomTicks(UNSOLICITED_REPORT_INTERVAL);
  2191. } else if (!GroupWasAllowed && GroupNowAllowed) {
  2192. // Set retransmission timer only for joins, not leaves
  2193. AddrPtr->iga_trtimer = IGMPRandomTicks(UNSOLICITED_REPORT_INTERVAL);
  2194. }
  2195. } while (FALSE);
  2196. CTEFreeLock(&NTE->nte_lock, Handle);
  2197. if (IgmpVersion == IGMPV3) {
  2198. IGMPv3RecordQueueEntry *Head = NULL, *rqe;
  2199. rqe = STRUCT_OF(IGMPv3RecordQueueEntry, &Head, i3qe_next);
  2200. // Send IGMP ALLOW/BLOCK messages if non-empty
  2201. QueueRecord(&rqe, &AllowRec, AllowRecSize);
  2202. QueueRecord(&rqe, &BlockRec, BlockRecSize);
  2203. SendIGMPv3Reports(Head, SrcAddr, BodyMTU);
  2204. } else if (!GroupWasAllowed && GroupNowAllowed) {
  2205. IGMPReportQueueEntry *Head = NULL, *rqe;
  2206. rqe = STRUCT_OF(IGMPReportQueueEntry, &Head, iqe_next);
  2207. QueueOldReport(&rqe, IGMP_ADD, IgmpVersion, Addr);
  2208. SendOldReports(Head, SrcAddr);
  2209. } else if (GroupWasAllowed && !GroupNowAllowed) {
  2210. IGMPReportQueueEntry *Head = NULL, *rqe;
  2211. rqe = STRUCT_OF(IGMPReportQueueEntry, &Head, iqe_next);
  2212. QueueOldReport(&rqe, IGMP_DELETE, IgmpVersion, Addr);
  2213. SendOldReports(Head, SrcAddr);
  2214. }
  2215. // We finished the request, and Status contains the completion status.
  2216. // If there are any pending blocks for this routine, signal the next
  2217. // one now. Otherwise clear the block flag.
  2218. CTEGetLock(&IGMPLock, &Handle);
  2219. if ((BlockPtr = IGMPBlockList) != NULL) {
  2220. // Someone is blocking. Pull him from the list and signal him.
  2221. IGMPBlockList = BlockPtr->ibs_next;
  2222. CTEFreeLock(&IGMPLock, Handle);
  2223. CTESignal(&BlockPtr->ibs_block, IP_SUCCESS);
  2224. } else {
  2225. // No one blocking, just clear the flag.
  2226. IGMPBlockFlag = 0;
  2227. CTEFreeLock(&IGMPLock, Handle);
  2228. }
  2229. return Status;
  2230. }
  2231. //* IGMPExclChange - update source exclusion list
  2232. //
  2233. // On failure, exclusion list will be unchanged
  2234. IP_STATUS
  2235. IGMPExclChange(
  2236. IN NetTableEntry * NTE,
  2237. IN IPAddr Addr,
  2238. IN uint NumAddSources,
  2239. IN IPAddr * AddSourceList,
  2240. IN uint NumDelSources,
  2241. IN IPAddr * DelSourceList)
  2242. {
  2243. CTELockHandle Handle;
  2244. IGMPAddr *AddrPtr, *PrevPtr;
  2245. IP_STATUS Status;
  2246. Interface *IF;
  2247. IGMPBlockStruct Block;
  2248. IGMPBlockStruct *BlockPtr;
  2249. uint IgmpVersion = 0, BodyMTU;
  2250. IPAddr SrcAddr;
  2251. IGMPv3GroupRecord *AllowRec = NULL, *BlockRec = NULL;
  2252. uint AllowRecSize = 0, BlockRecSize = 0;
  2253. // First make sure we're at level 2 of IGMP support.
  2254. if (IGMPLevel != 2)
  2255. return IP_BAD_REQ;
  2256. // Make sure addlist and dellist aren't both empty
  2257. ASSERT((NumAddSources > 0) || (NumDelSources > 0));
  2258. if (NTE->nte_flags & NTE_VALID) {
  2259. //
  2260. // If this is an unnumbered interface
  2261. //
  2262. if ((NTE->nte_if->if_flags & IF_FLAGS_NOIPADDR) &&
  2263. IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
  2264. SrcAddr = g_ValidAddr;
  2265. if (IP_ADDR_EQUAL(SrcAddr, NULL_IP_ADDR)) {
  2266. return IP_BAD_REQ;
  2267. }
  2268. } else {
  2269. SrcAddr = NTE->nte_addr;
  2270. }
  2271. }
  2272. CTEInitBlockStruc(&Block.ibs_block);
  2273. // Make sure we're the only ones in this routine. If someone else is
  2274. // already here, block.
  2275. CTEGetLock(&IGMPLock, &Handle);
  2276. if (IGMPBlockFlag) {
  2277. // Someone else is already here. Walk down the block list, and
  2278. // put ourselves on the end. Then free the lock and block on our
  2279. // IGMPBlock structure.
  2280. BlockPtr = STRUCT_OF(IGMPBlockStruct, &IGMPBlockList, ibs_next);
  2281. while (BlockPtr->ibs_next != NULL)
  2282. BlockPtr = BlockPtr->ibs_next;
  2283. Block.ibs_next = NULL;
  2284. BlockPtr->ibs_next = &Block;
  2285. CTEFreeLock(&IGMPLock, Handle);
  2286. CTEBlock(&Block.ibs_block);
  2287. } else {
  2288. // No one else here, set the flag so no one else gets in and free the
  2289. // lock.
  2290. IGMPBlockFlag = 1;
  2291. CTEFreeLock(&IGMPLock, Handle);
  2292. }
  2293. // Now we're in the routine, and we won't be reentered here by another
  2294. // thread of execution. Make sure everything's valid, and figure out
  2295. // what to do.
  2296. Status = IP_SUCCESS;
  2297. // Now get the lock on the NTE and make sure it's valid.
  2298. CTEGetLock(&NTE->nte_lock, &Handle);
  2299. do {
  2300. if (!(NTE->nte_flags & NTE_VALID)) {
  2301. Status = IP_BAD_REQ;
  2302. break;
  2303. }
  2304. IF = NTE->nte_if;
  2305. BodyMTU = RECORD_MTU(NTE);
  2306. IgmpVersion = IF->IgmpVersion;
  2307. // Find the IGMPAddr entry
  2308. AddrPtr = FindIGMPAddr(NTE, Addr, &PrevPtr);
  2309. // Break if not there or refcount=0
  2310. ASSERT(AddrPtr && (AddrPtr->iga_grefcnt!=0));
  2311. // Perform XADDLIST
  2312. Status = IGMPAddExclList(NTE, PrevPtr, &AddrPtr, NumAddSources,
  2313. AddSourceList);
  2314. if (Status != IP_SUCCESS) {
  2315. break;
  2316. }
  2317. // Perform XDELLLIST
  2318. IGMPDelExclList(NTE, PrevPtr, &AddrPtr, NumDelSources, DelSourceList,
  2319. TRUE);
  2320. // Don't need to reget AddrPtr here since the NTE lock is never
  2321. // released while modifying the exclusion list above, since the
  2322. // linklayer filter is unaffected.
  2323. if (IgmpVersion == IGMPV3) {
  2324. AllowRec = GetAllowRecord(AddrPtr, &AllowRecSize);
  2325. BlockRec = GetBlockRecord(AddrPtr, &BlockRecSize);
  2326. // Set retransmission timer
  2327. AddrPtr->iga_trtimer = IGMPRandomTicks(UNSOLICITED_REPORT_INTERVAL);
  2328. }
  2329. } while (FALSE);
  2330. CTEFreeLock(&NTE->nte_lock, Handle);
  2331. // Since AddrPtr->iga_grefcnt cannot be zero, and is unchanged by
  2332. // this function, we never need to update the link-layer filter.
  2333. // Send IGMP ALLOW/BLOCK messages if non-empty
  2334. // Note that we never need to do anything here in IGMPv1/v2 mode.
  2335. if (IgmpVersion == IGMPV3) {
  2336. IGMPv3RecordQueueEntry *Head = NULL, *rqe;
  2337. rqe = STRUCT_OF(IGMPv3RecordQueueEntry, &Head, i3qe_next);
  2338. QueueRecord(&rqe, &AllowRec, AllowRecSize);
  2339. QueueRecord(&rqe, &BlockRec, BlockRecSize);
  2340. SendIGMPv3Reports(Head, SrcAddr, BodyMTU);
  2341. }
  2342. // We finished the request, and Status contains the completion status.
  2343. // If there are any pending blocks for this routine, signal the next
  2344. // one now. Otherwise clear the block flag.
  2345. CTEGetLock(&IGMPLock, &Handle);
  2346. if ((BlockPtr = IGMPBlockList) != NULL) {
  2347. // Someone is blocking. Pull him from the list and signal him.
  2348. IGMPBlockList = BlockPtr->ibs_next;
  2349. CTEFreeLock(&IGMPLock, Handle);
  2350. CTESignal(&BlockPtr->ibs_block, IP_SUCCESS);
  2351. } else {
  2352. // No one blocking, just clear the flag.
  2353. IGMPBlockFlag = 0;
  2354. CTEFreeLock(&IGMPLock, Handle);
  2355. }
  2356. return Status;
  2357. }
  2358. //* JoinIGMPAddr - add a membership reference to an entire group, and
  2359. // update associated source list refcounts.
  2360. //
  2361. // On failure, state will remain unchanged.
  2362. IP_STATUS
  2363. JoinIGMPAddr(
  2364. IN NetTableEntry *NTE,
  2365. IN IPAddr Addr,
  2366. IN uint NumExclSources,
  2367. IN OUT IPAddr *ExclSourceList, // volatile
  2368. IN uint NumInclSources,
  2369. IN IPAddr *InclSourceList,
  2370. IN IPAddr SrcAddr)
  2371. {
  2372. IGMPAddr *AddrPtr, *PrevPtr;
  2373. IGMPSrcAddr *SrcAddrPtr, *PrevSrc;
  2374. Interface *IF;
  2375. uint IgmpVersion, i, AddrAdded, BodyMTU;
  2376. IP_STATUS Status;
  2377. CTELockHandle Handle;
  2378. IGMPv3GroupRecord *ToExRec = NULL, *AllowRec = NULL, *BlockRec = NULL;
  2379. uint ToExRecSize, AllowRecSize, BlockRecSize;
  2380. BOOLEAN GroupWasAllowed;
  2381. uint InitialRefOnIgmpAddr;
  2382. Status = IP_SUCCESS;
  2383. CTEGetLock(&NTE->nte_lock, &Handle);
  2384. do {
  2385. if (!(NTE->nte_flags & NTE_VALID)) {
  2386. Status = IP_BAD_REQ;
  2387. break;
  2388. }
  2389. IF = NTE->nte_if;
  2390. IgmpVersion = IF->IgmpVersion;
  2391. BodyMTU = RECORD_MTU(NTE);
  2392. // If no group entry exists, create one in exclusion mode
  2393. Status = FindOrCreateIGMPAddr(NTE, Addr, &AddrPtr, &PrevPtr);
  2394. if (Status != IP_SUCCESS) {
  2395. break;
  2396. }
  2397. // Store the ref count at this point in a local variable.
  2398. InitialRefOnIgmpAddr = AddrPtr->iga_grefcnt;
  2399. GroupWasAllowed = IS_GROUP_ALLOWED(AddrPtr);
  2400. if (!GroupWasAllowed) {
  2401. // We have to be careful not to release the lock while
  2402. // IS_GROUP_DELETABLE() is true, or else it might be
  2403. // deleted by IGMPTimer(). So before releasing the lock,
  2404. // we bump the join refcount (which we want to do anyway
  2405. // later on, so it won't hurt anything now).
  2406. (AddrPtr->iga_grefcnt)++;
  2407. // Update link-layer filter
  2408. CTEFreeLock(&NTE->nte_lock, Handle);
  2409. {
  2410. AddrAdded = (*IF->if_addaddr) (IF->if_lcontext,
  2411. LLIP_ADDR_MCAST, Addr, 0, NULL);
  2412. }
  2413. CTEGetLock(&NTE->nte_lock, &Handle);
  2414. // Revalidate NTE, AddrPtr, PrevPtr
  2415. if (!(NTE->nte_flags & NTE_VALID)) {
  2416. // Don't need to undo any refcount here as the refcount
  2417. // was blown away by StopIGMPForNTE.
  2418. Status = IP_BAD_REQ;
  2419. break;
  2420. }
  2421. // Find the IGMPAddr entry
  2422. AddrPtr = FindIGMPAddr(NTE, Addr, &PrevPtr);
  2423. if (!AddrPtr) {
  2424. Status = IP_BAD_REQ;
  2425. break;
  2426. }
  2427. // Now release the refcount we grabbed above
  2428. // so the rest of the logic is the same for
  2429. // all cases.
  2430. (AddrPtr->iga_grefcnt)--;
  2431. if (!AddrAdded) {
  2432. if (IS_GROUP_DELETABLE(AddrPtr))
  2433. DeleteIGMPAddr(NTE, PrevPtr, &AddrPtr);
  2434. Status = IP_NO_RESOURCES;
  2435. break;
  2436. }
  2437. }
  2438. // For each existing source entry,
  2439. // If not in {xaddlist}, xrefcnt=refcount, irefcnt=0
  2440. // Add source to ALLOW message
  2441. // If in {xaddlist},
  2442. // Increment xrefcnt and remove from {xaddlist}
  2443. for (SrcAddrPtr = AddrPtr->iga_srclist;
  2444. SrcAddrPtr;
  2445. SrcAddrPtr = SrcAddrPtr->isa_next) {
  2446. for (i=0; i<NumExclSources; i++) {
  2447. if (IP_ADDR_EQUAL(SrcAddrPtr->isa_addr, ExclSourceList[i])) {
  2448. (SrcAddrPtr->isa_xrefcnt)++;
  2449. ExclSourceList[i] = ExclSourceList[--NumExclSources];
  2450. break;
  2451. }
  2452. }
  2453. if ((i == NumExclSources)
  2454. && !IS_SOURCE_ALLOWED(AddrPtr, SrcAddrPtr)
  2455. && (NTE->nte_if->IgmpVersion == IGMPV3)) {
  2456. // Add source to ALLOW message
  2457. MarkSource(AddrPtr, SrcAddrPtr);
  2458. }
  2459. }
  2460. // The purpose of this check is to mark this Address 'only the first time'.
  2461. // To take care of race conditions, this has to be stored in a local variable.
  2462. if (InitialRefOnIgmpAddr == 0) {
  2463. MarkGroup(AddrPtr);
  2464. }
  2465. // Bump the refcount on the group entry
  2466. (AddrPtr->iga_grefcnt)++;
  2467. // For each entry left in {xaddlist}
  2468. // Add source entry and increment xrefcnt
  2469. for (i=0; i<NumExclSources; i++) {
  2470. Status = CreateIGMPSrcAddr(AddrPtr, ExclSourceList[i],
  2471. &SrcAddrPtr, &PrevSrc);
  2472. if (Status != IP_SUCCESS) {
  2473. break;
  2474. }
  2475. (SrcAddrPtr->isa_xrefcnt)++;
  2476. }
  2477. if (Status != IP_SUCCESS) {
  2478. // undo source adds
  2479. IGMPDelExclList(NTE, PrevPtr, &AddrPtr, i, ExclSourceList, FALSE);
  2480. // undo group join
  2481. (AddrPtr->iga_grefcnt)--;
  2482. if (IS_GROUP_DELETABLE(AddrPtr))
  2483. DeleteIGMPAddr(NTE, PrevPtr, &AddrPtr);
  2484. break;
  2485. }
  2486. // Perform IDELLIST
  2487. IGMPDelInclList(&Handle, NTE, &PrevPtr, &AddrPtr,
  2488. NumInclSources, InclSourceList, TRUE);
  2489. // Make sure AddrPtr didn't go away somehow
  2490. if (AddrPtr == NULL) {
  2491. Status = IP_BAD_REQ;
  2492. break;
  2493. }
  2494. // No reports are sent for the ALL_HOST_MCAST group
  2495. if (!IP_ADDR_EQUAL(AddrPtr->iga_addr, ALL_HOST_MCAST)) {
  2496. if (IgmpVersion == IGMPV3) {
  2497. // If filter mode was inclusion,
  2498. // Send TO_EX with list of sources where irefcnt=0,xrefcnt=refcnt
  2499. // Else
  2500. // Send ALLOW/BLOCK messages if non-empty
  2501. if (AddrPtr->iga_grefcnt == 1) {
  2502. ToExRec = GetToExRecord( AddrPtr, &ToExRecSize, BodyMTU);
  2503. } else {
  2504. AllowRec = GetAllowRecord(AddrPtr, &AllowRecSize);
  2505. BlockRec = GetBlockRecord(AddrPtr, &BlockRecSize);
  2506. }
  2507. // set triggered group retransmission timer
  2508. AddrPtr->iga_trtimer = IGMPRandomTicks(UNSOLICITED_REPORT_INTERVAL);
  2509. } else if (!GroupWasAllowed) {
  2510. // Set retransmission timer
  2511. AddrPtr->iga_trtimer = IGMPRandomTicks(UNSOLICITED_REPORT_INTERVAL);
  2512. }
  2513. }
  2514. } while (FALSE);
  2515. CTEFreeLock(&NTE->nte_lock, Handle);
  2516. if (Status != IP_SUCCESS) {
  2517. return Status;
  2518. }
  2519. if (IP_ADDR_EQUAL(Addr, ALL_HOST_MCAST))
  2520. return Status;
  2521. if (IgmpVersion == IGMPV3) {
  2522. IGMPv3RecordQueueEntry *Head = NULL, *rqe;
  2523. rqe = STRUCT_OF(IGMPv3RecordQueueEntry, &Head, i3qe_next);
  2524. QueueRecord(&rqe, &ToExRec, ToExRecSize);
  2525. QueueRecord(&rqe, &AllowRec, AllowRecSize);
  2526. QueueRecord(&rqe, &BlockRec, BlockRecSize);
  2527. SendIGMPv3Reports(Head, SrcAddr, BodyMTU);
  2528. } else if (!GroupWasAllowed) {
  2529. IGMPReportQueueEntry *Head = NULL, *rqe;
  2530. rqe = STRUCT_OF(IGMPReportQueueEntry, &Head, iqe_next);
  2531. QueueOldReport(&rqe, IGMP_ADD, IgmpVersion, Addr);
  2532. SendOldReports(Head, SrcAddr);
  2533. }
  2534. return Status;
  2535. }
  2536. //* LeaveIGMPAddr - remove a membership reference to an entire group, and
  2537. // update associated source list refcounts.
  2538. IP_STATUS
  2539. LeaveIGMPAddr(
  2540. IN NetTableEntry *NTE,
  2541. IN IPAddr Addr,
  2542. IN uint NumExclSources,
  2543. IN OUT IPAddr *ExclSourceList, // volatile
  2544. IN uint NumInclSources,
  2545. IN IPAddr *InclSourceList,
  2546. IN IPAddr SrcAddr)
  2547. {
  2548. IGMPAddr *AddrPtr, *PrevPtr;
  2549. IGMPSrcAddr *Src, *PrevSrc;
  2550. IP_STATUS Status;
  2551. CTELockHandle Handle;
  2552. Interface *IF;
  2553. uint IgmpVersion, i, BodyMTU;
  2554. BOOLEAN GroupNowAllowed = TRUE;
  2555. IGMPv3GroupRecord *ToInRec = NULL, *AllowRec = NULL, *BlockRec = NULL;
  2556. uint ToInRecSize, AllowRecSize, BlockRecSize;
  2557. Status = IP_SUCCESS;
  2558. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  2559. (DTEXT("LeaveIGMPAddr NTE=%x Addr=%x NumExcl=%d ExclSList=%x NumIncl=%d InclSList=%x SrcAddr=%x\n"),
  2560. NTE, Addr, NumExclSources, ExclSourceList, NumInclSources,
  2561. InclSourceList, SrcAddr));
  2562. // Now get the lock on the NTE and make sure it's valid.
  2563. CTEGetLock(&NTE->nte_lock, &Handle);
  2564. do {
  2565. if (!(NTE->nte_flags & NTE_VALID)) {
  2566. Status = IP_BAD_REQ;
  2567. break;
  2568. }
  2569. IF = NTE->nte_if;
  2570. IgmpVersion = IF->IgmpVersion;
  2571. BodyMTU = RECORD_MTU(NTE);
  2572. // The NTE is valid. Try to find an existing IGMPAddr structure
  2573. // that matches the input address.
  2574. AddrPtr = FindIGMPAddr(NTE, Addr, &PrevPtr);
  2575. // This is a delete request. If we didn't find the requested
  2576. // address, fail the request.
  2577. // For now, if the ref count is 0, we will treat it as equivalent to
  2578. // not-found. This is done to take care of the ref count on an
  2579. // IGMPAddr going bad because of a race condition between the
  2580. // invalidation and revalidation of an NTE and deletion and creation
  2581. // of an IGMPAddr.
  2582. if ((AddrPtr == NULL) || (AddrPtr->iga_grefcnt == 0)) {
  2583. Status = IP_BAD_REQ;
  2584. break;
  2585. }
  2586. // Don't let the all-hosts mcast address go away.
  2587. if (IP_ADDR_EQUAL(Addr, ALL_HOST_MCAST)) {
  2588. break;
  2589. }
  2590. // Perform IADDLIST
  2591. Status = IGMPAddInclList(&Handle, NTE, &PrevPtr, &AddrPtr,
  2592. NumInclSources, InclSourceList);
  2593. if (Status != IP_SUCCESS) {
  2594. break;
  2595. }
  2596. // Decrement the refcount
  2597. ASSERT(AddrPtr->iga_grefcnt > 0);
  2598. AddrPtr->iga_grefcnt--;
  2599. if ((AddrPtr->iga_grefcnt == 0)
  2600. && (NTE->nte_if->IgmpVersion == IGMPV3)) {
  2601. // Leaves are only retransmitted in IGMPv3
  2602. MarkGroup(AddrPtr);
  2603. }
  2604. // For each existing source entry:
  2605. // If entry is not in {xdellist}, xrefcnt=refcnt, irefcnt=0,
  2606. // Add source to BLOCK message
  2607. // If entry is in {xdellist},
  2608. // Decrement xrefcnt and remove from {xdellist}
  2609. // If xrefcnt=irefcnt=0, delete entry
  2610. PrevSrc = STRUCT_OF(IGMPSrcAddr, &AddrPtr->iga_srclist, isa_next);
  2611. for (Src = AddrPtr->iga_srclist; Src; PrevSrc=Src,Src = Src->isa_next) {
  2612. for (i=0; i<NumExclSources; i++) {
  2613. if (IP_ADDR_EQUAL(Src->isa_addr, ExclSourceList[i])) {
  2614. (Src->isa_xrefcnt)--;
  2615. ExclSourceList[i] = ExclSourceList[--NumExclSources];
  2616. break;
  2617. }
  2618. }
  2619. if ((i == NumExclSources)
  2620. && !IS_SOURCE_ALLOWED(AddrPtr, Src)
  2621. && (NTE->nte_if->IgmpVersion == IGMPV3)) {
  2622. // Add source to BLOCK message
  2623. MarkSource(AddrPtr, Src);
  2624. }
  2625. if (IS_SOURCE_DELETABLE(Src)) {
  2626. DeleteIGMPSrcAddr(PrevSrc, &Src);
  2627. Src = PrevSrc;
  2628. }
  2629. }
  2630. // Break if {xdellist} is not empty
  2631. ASSERT(NumExclSources == 0);
  2632. if (IgmpVersion == IGMPV3) {
  2633. // If refcnt is 0
  2634. // Send TO_IN(null)
  2635. // Else
  2636. // Send ALLOW/BLOCK messages if non-empty
  2637. if (AddrPtr->iga_grefcnt == 0) {
  2638. ToInRec = GetToInRecord(AddrPtr, &ToInRecSize);
  2639. } else {
  2640. AllowRec = GetAllowRecord(AddrPtr, &AllowRecSize);
  2641. BlockRec = GetBlockRecord(AddrPtr, &BlockRecSize);
  2642. }
  2643. // set triggered group retransmission timer
  2644. if (ToInRec || AllowRec || BlockRec) {
  2645. AddrPtr->iga_trtimer = IGMPRandomTicks(UNSOLICITED_REPORT_INTERVAL);
  2646. }
  2647. }
  2648. // Note: IGMPv2 leaves are not retransmitted, hence no timer set.
  2649. GroupNowAllowed = IS_GROUP_ALLOWED(AddrPtr);
  2650. if (!GroupNowAllowed)
  2651. CancelGroupResponseTimer(AddrPtr);
  2652. // Delete the group entry if it's no longer needed
  2653. if (IS_GROUP_DELETABLE(AddrPtr))
  2654. DeleteIGMPAddr(NTE, PrevPtr, &AddrPtr);
  2655. } while (FALSE);
  2656. CTEFreeLock(&NTE->nte_lock, Handle);
  2657. if (Status != IP_SUCCESS) {
  2658. return Status;
  2659. }
  2660. // Update link-layer filter
  2661. if (!GroupNowAllowed) {
  2662. (*IF->if_deladdr) (IF->if_lcontext, LLIP_ADDR_MCAST, Addr, 0);
  2663. }
  2664. if (IgmpVersion == IGMPV3) {
  2665. IGMPv3RecordQueueEntry *Head = NULL, *rqe;
  2666. rqe = STRUCT_OF(IGMPv3RecordQueueEntry, &Head, i3qe_next);
  2667. QueueRecord(&rqe, &ToInRec, ToInRecSize);
  2668. QueueRecord(&rqe, &AllowRec, AllowRecSize);
  2669. QueueRecord(&rqe, &BlockRec, BlockRecSize);
  2670. SendIGMPv3Reports(Head, SrcAddr, BodyMTU);
  2671. } else if (!GroupNowAllowed) {
  2672. IGMPReportQueueEntry *Head = NULL, *rqe;
  2673. rqe = STRUCT_OF(IGMPReportQueueEntry, &Head, iqe_next);
  2674. QueueOldReport(&rqe, IGMP_DELETE, IgmpVersion, Addr);
  2675. SendOldReports(Head, SrcAddr);
  2676. }
  2677. return Status;
  2678. }
  2679. //* LeaveAllIGMPAddr - remove all group references on an interface
  2680. IP_STATUS
  2681. LeaveAllIGMPAddr(
  2682. IN NetTableEntry *NTE,
  2683. IN IPAddr SrcAddr)
  2684. {
  2685. IGMPAddr **HashPtr, *Prev, *Next, *Curr;
  2686. IGMPSrcAddr *PrevSrc, *CurrSrc;
  2687. int i, Grefcnt;
  2688. IP_STATUS Status;
  2689. CTELockHandle Handle;
  2690. Interface *IF;
  2691. uint IgmpVersion = 0, BodyMTU, OldMode;
  2692. IPAddr Addr;
  2693. IGMPv3RecordQueueEntry *I3Head = NULL, *i3qe;
  2694. IGMPReportQueueEntry *OldHead = NULL, *iqe;
  2695. IGMPv3GroupRecord *Rec;
  2696. uint RecSize;
  2697. i3qe = STRUCT_OF(IGMPv3RecordQueueEntry, &I3Head, i3qe_next);
  2698. iqe = STRUCT_OF(IGMPReportQueueEntry, &OldHead, iqe_next);
  2699. // We've been called to delete all of the addresses,
  2700. // regardless of their reference count. This should only
  2701. // happen when the NTE is going away.
  2702. Status = IP_SUCCESS;
  2703. CTEGetLock(&NTE->nte_lock, &Handle);
  2704. do {
  2705. HashPtr = NTE->nte_igmplist;
  2706. if (HashPtr == NULL) {
  2707. break;
  2708. }
  2709. IF = NTE->nte_if;
  2710. BodyMTU = RECORD_MTU(NTE);
  2711. IgmpVersion = IF->IgmpVersion;
  2712. for (i = 0; (i < IGMP_TABLE_SIZE) && (NTE->nte_igmplist != NULL); i++) {
  2713. Curr = STRUCT_OF(IGMPAddr, &HashPtr[i], iga_next);
  2714. Next = HashPtr[i];
  2715. for (Prev=Curr,Curr=Next;
  2716. Curr && (NTE->nte_igmplist != NULL);
  2717. Prev=Curr,Curr=Next) {
  2718. Next = Curr->iga_next;
  2719. Grefcnt = Curr->iga_grefcnt;
  2720. Addr = Curr->iga_addr;
  2721. // Leave all sources
  2722. PrevSrc = STRUCT_OF(IGMPSrcAddr, &Curr->iga_srclist, isa_next);
  2723. for(CurrSrc=PrevSrc->isa_next;
  2724. CurrSrc;
  2725. PrevSrc=CurrSrc,CurrSrc=CurrSrc->isa_next) {
  2726. if (Grefcnt && IS_SOURCE_ALLOWED(Curr, CurrSrc)
  2727. && (IF->IgmpVersion == IGMPV3)) {
  2728. // Add source to BLOCK message
  2729. MarkSource(Curr, CurrSrc);
  2730. }
  2731. // Force leave
  2732. CurrSrc->isa_irefcnt = 0;
  2733. CurrSrc->isa_xrefcnt = Curr->iga_grefcnt;
  2734. //
  2735. // We may be able to delete the source now,
  2736. // but not if it's marked for inclusion in a block
  2737. // message to be sent below.
  2738. //
  2739. if (IS_SOURCE_DELETABLE(CurrSrc)) {
  2740. DeleteIGMPSrcAddr(PrevSrc, &CurrSrc);
  2741. CurrSrc = PrevSrc;
  2742. }
  2743. }
  2744. // Force group leave
  2745. if (Grefcnt > 0) {
  2746. Curr->iga_grefcnt = 0;
  2747. // Leaves are only retransmitted in IGMPv3, where
  2748. // state will actually be deleted once retransmissions
  2749. // are complete.
  2750. if (NTE->nte_if->IgmpVersion == IGMPV3)
  2751. MarkGroup(Curr);
  2752. CancelGroupResponseTimer(Curr);
  2753. //
  2754. // We may be able to delete the group now,
  2755. // but not if it's marked for inclusion in an IGMPv3
  2756. // leave to be sent below.
  2757. //
  2758. if (IS_GROUP_DELETABLE(Curr))
  2759. DeleteIGMPAddr(NTE, Prev, &Curr);
  2760. }
  2761. // Queue triggered messages
  2762. if (!IP_ADDR_EQUAL(Addr, ALL_HOST_MCAST)) {
  2763. if (IgmpVersion < IGMPV3) {
  2764. QueueOldReport(&iqe, IGMP_DELETE, IgmpVersion,Addr);
  2765. } else if (Grefcnt > 0) {
  2766. // queue TO_IN
  2767. Rec = GetToInRecord(Curr, &RecSize);
  2768. QueueRecord(&i3qe, &Rec, RecSize);
  2769. } else {
  2770. // queue BLOCK
  2771. Rec = GetBlockRecord(Curr, &RecSize);
  2772. QueueRecord(&i3qe, &Rec, RecSize);
  2773. }
  2774. }
  2775. // If we haven't deleted the group yet, delete it now
  2776. if (Curr != NULL) {
  2777. // Delete any leftover sources
  2778. PrevSrc = STRUCT_OF(IGMPSrcAddr, &Curr->iga_srclist,
  2779. isa_next);
  2780. while (Curr->iga_srclist != NULL) {
  2781. CurrSrc = Curr->iga_srclist;
  2782. CurrSrc->isa_irefcnt = CurrSrc->isa_xrefcnt = 0;
  2783. CurrSrc->isa_xmitleft = CurrSrc->isa_csmarked = 0;
  2784. DeleteIGMPSrcAddr(PrevSrc, &CurrSrc);
  2785. }
  2786. Curr->iga_xmitleft = 0;
  2787. DeleteIGMPAddr(NTE, Prev, &Curr);
  2788. }
  2789. Curr = Prev;
  2790. CTEFreeLock(&NTE->nte_lock, Handle);
  2791. {
  2792. // Update link-layer filter
  2793. (*IF->if_deladdr) (IF->if_lcontext, LLIP_ADDR_MCAST,
  2794. Addr, 0);
  2795. }
  2796. CTEGetLock(&NTE->nte_lock, &Handle);
  2797. }
  2798. }
  2799. ASSERT(NTE->nte_igmplist == NULL);
  2800. ASSERT(NTE->nte_igmpcount == 0);
  2801. } while (FALSE);
  2802. CTEFreeLock(&NTE->nte_lock, Handle);
  2803. if (IgmpVersion == IGMPV3)
  2804. SendIGMPv3Reports(I3Head, SrcAddr, BodyMTU);
  2805. else
  2806. SendOldReports(OldHead, SrcAddr);
  2807. return Status;
  2808. }
  2809. //* IGMPAddrChange - Change the IGMP address list on an NTE.
  2810. //
  2811. // Called to add or delete an IGMP address. We're given the relevant NTE,
  2812. // the address, and the action to be performed. We validate the NTE, the
  2813. // address, and the IGMP level, and then attempt to perform the action.
  2814. //
  2815. // There are a bunch of strange race conditions that can occur during
  2816. // adding/deleting addresses, related to trying to add the same address
  2817. // twice and having it fail, or adding and deleting the same address
  2818. // simultaneously. Most of these happen because we have to free the lock
  2819. // to call the interface, and the call to the interface can fail. To
  2820. // prevent this we serialize all access to this routine. Only one thread
  2821. // of execution can go through here at a time, all others are blocked.
  2822. //
  2823. // Input: NTE - NTE with list to be altered.
  2824. // Addr - Address affected.
  2825. // ChangeType - Type of change - IGMP_ADD, IGMP_DELETE,
  2826. // IGMP_DELETE_ALL.
  2827. // ExclSourceList - list of exclusion sources (volatile)
  2828. //
  2829. // Returns: IP_STATUS of attempt to perform action.
  2830. //
  2831. IP_STATUS
  2832. IGMPAddrChange(
  2833. IN NetTableEntry *NTE,
  2834. IN IPAddr Addr,
  2835. IN uint ChangeType,
  2836. IN uint NumExclSources,
  2837. IN OUT IPAddr *ExclSourceList,
  2838. IN uint NumInclSources,
  2839. IN IPAddr *InclSourceList)
  2840. {
  2841. CTELockHandle Handle;
  2842. IGMPAddr *AddrPtr, *PrevPtr;
  2843. IGMPSrcAddr *SrcAddrPtr;
  2844. IP_STATUS Status;
  2845. Interface *IF;
  2846. uint AddrAdded;
  2847. IGMPBlockStruct Block;
  2848. IGMPBlockStruct *BlockPtr;
  2849. uint IgmpVersion;
  2850. IPAddr SrcAddr = 0;
  2851. // First make sure we're at level 2 of IGMP support.
  2852. if (IGMPLevel != 2)
  2853. return IP_BAD_REQ;
  2854. if (NTE->nte_flags & NTE_VALID) {
  2855. //
  2856. // If this is an unnumbered interface
  2857. //
  2858. if ((NTE->nte_if->if_flags & IF_FLAGS_NOIPADDR) &&
  2859. IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
  2860. SrcAddr = g_ValidAddr;
  2861. if (IP_ADDR_EQUAL(SrcAddr, NULL_IP_ADDR)) {
  2862. return IP_BAD_REQ;
  2863. }
  2864. } else {
  2865. SrcAddr = NTE->nte_addr;
  2866. }
  2867. }
  2868. CTEInitBlockStruc(&Block.ibs_block);
  2869. // Make sure we're the only ones in this routine. If someone else is
  2870. // already here, block.
  2871. CTEGetLock(&IGMPLock, &Handle);
  2872. if (IGMPBlockFlag) {
  2873. // Someone else is already here. Walk down the block list, and
  2874. // put ourselves on the end. Then free the lock and block on our
  2875. // IGMPBlock structure.
  2876. BlockPtr = STRUCT_OF(IGMPBlockStruct, &IGMPBlockList, ibs_next);
  2877. while (BlockPtr->ibs_next != NULL)
  2878. BlockPtr = BlockPtr->ibs_next;
  2879. Block.ibs_next = NULL;
  2880. BlockPtr->ibs_next = &Block;
  2881. CTEFreeLock(&IGMPLock, Handle);
  2882. CTEBlock(&Block.ibs_block);
  2883. } else {
  2884. // Noone else here, set the flag so noone else gets in and free the
  2885. // lock.
  2886. IGMPBlockFlag = 1;
  2887. CTEFreeLock(&IGMPLock, Handle);
  2888. }
  2889. // Now we're in the routine, and we won't be reentered here by another
  2890. // thread of execution. Make sure everything's valid, and figure out
  2891. // what to do.
  2892. Status = IP_SUCCESS;
  2893. // Now figure out the action to be performed.
  2894. switch (ChangeType) {
  2895. case IGMP_ADD:
  2896. Status = JoinIGMPAddr(NTE, Addr, NumExclSources, ExclSourceList,
  2897. NumInclSources, InclSourceList,
  2898. SrcAddr);
  2899. break;
  2900. case IGMP_DELETE:
  2901. Status = LeaveIGMPAddr(NTE, Addr, NumExclSources, ExclSourceList,
  2902. NumInclSources, InclSourceList,
  2903. SrcAddr);
  2904. break;
  2905. case IGMP_DELETE_ALL:
  2906. Status = LeaveAllIGMPAddr(NTE, SrcAddr);
  2907. break;
  2908. default:
  2909. DEBUGCHK;
  2910. break;
  2911. }
  2912. // We finished the request, and Status contains the completion status.
  2913. // If there are any pending blocks for this routine, signal the next
  2914. // one now. Otherwise clear the block flag.
  2915. CTEGetLock(&IGMPLock, &Handle);
  2916. if ((BlockPtr = IGMPBlockList) != NULL) {
  2917. // Someone is blocking. Pull him from the list and signal him.
  2918. IGMPBlockList = BlockPtr->ibs_next;
  2919. CTEFreeLock(&IGMPLock, Handle);
  2920. CTESignal(&BlockPtr->ibs_block, IP_SUCCESS);
  2921. } else {
  2922. // No one blocking, just clear the flag.
  2923. IGMPBlockFlag = 0;
  2924. CTEFreeLock(&IGMPLock, Handle);
  2925. }
  2926. return Status;
  2927. }
  2928. //* GroupResponseTimeout - Called when group-response timer expires
  2929. // Assumes caller holds lock on NTE
  2930. // Caller is responsible for deleting AddrPtr if no longer needed
  2931. void
  2932. GroupResponseTimeout(
  2933. IN OUT IGMPv3RecordQueueEntry **pI3qe,
  2934. IN OUT IGMPReportQueueEntry **pIqe,
  2935. IN NetTableEntry *NTE,
  2936. IN IGMPAddr *AddrPtr)
  2937. {
  2938. uint IgmpVersion, BodyMTU, StateRecSize = 0;
  2939. IGMPv3GroupRecord *StateRec = NULL;
  2940. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_TX,
  2941. (DTEXT("GroupResponseTimeout\n")));
  2942. IgmpVersion = NTE->nte_if->IgmpVersion;
  2943. BodyMTU = RECORD_MTU(NTE);
  2944. if (IgmpVersion < IGMPV3) {
  2945. QueueOldReport(pIqe, IGMP_ADD, IgmpVersion, AddrPtr->iga_addr);
  2946. return;
  2947. }
  2948. if (AddrPtr->iga_resptype == GROUP_SOURCE_RESP) {
  2949. StateRec = GetGSIsInRecord(AddrPtr, &StateRecSize);
  2950. } else {
  2951. // Group-specific response
  2952. if (AddrPtr->iga_grefcnt == 0) {
  2953. StateRec = GetIsInRecord(AddrPtr, &StateRecSize);
  2954. } else {
  2955. StateRec = GetIsExRecord(AddrPtr, &StateRecSize, BodyMTU);
  2956. }
  2957. }
  2958. QueueRecord(pI3qe, &StateRec, StateRecSize);
  2959. CancelGroupResponseTimer(AddrPtr);
  2960. }
  2961. //* RetransmissionTimeout - called when retransmission timer expires
  2962. //
  2963. // Caller is responsible for deleting Grp afterwards if no longer needed
  2964. void
  2965. RetransmissionTimeout(
  2966. IN OUT IGMPv3RecordQueueEntry **pI3qe,
  2967. IN OUT IGMPReportQueueEntry **pIqe,
  2968. IN NetTableEntry *NTE,
  2969. IN IGMPAddr *Grp)
  2970. {
  2971. IGMPv3GroupRecord *Rec = NULL;
  2972. uint RecSize = 0;
  2973. uint IgmpVersion, BodyMTU;
  2974. DEBUGMSG(DBG_TRACE && DBG_IGMP && DBG_TX,
  2975. (DTEXT("RetransmissionTimeout\n")));
  2976. IgmpVersion = NTE->nte_if->IgmpVersion;
  2977. BodyMTU = RECORD_MTU(NTE);
  2978. if (IgmpVersion < IGMPV3) {
  2979. // We decrement the counter here since the same function
  2980. // is used to respond to queries.
  2981. IgmpDecXmitLeft(Grp);
  2982. QueueOldReport(pIqe, IGMP_ADD, IgmpVersion, Grp->iga_addr);
  2983. } else {
  2984. if (Grp->iga_changetype == MODE_CHANGE) {
  2985. if (Grp->iga_grefcnt == 0) {
  2986. Rec = GetToInRecord(Grp, &RecSize);
  2987. } else {
  2988. Rec = GetToExRecord(Grp, &RecSize, BodyMTU);
  2989. }
  2990. QueueRecord(pI3qe, &Rec, RecSize);
  2991. } else {
  2992. Rec = GetAllowRecord(Grp, &RecSize);
  2993. QueueRecord(pI3qe, &Rec, RecSize);
  2994. Rec = GetBlockRecord(Grp, &RecSize);
  2995. QueueRecord(pI3qe, &Rec, RecSize);
  2996. }
  2997. }
  2998. if (Grp->iga_xmitleft > 0) {
  2999. Grp->iga_trtimer = IGMPRandomTicks(UNSOLICITED_REPORT_INTERVAL);
  3000. }
  3001. }
  3002. //* IGMPTimer - Handle an IGMP timer event.
  3003. //
  3004. // This function is called every 500 ms. by IP. If we're at level 2 of
  3005. // IGMP functionality we run down the NTE looking for running timers. If
  3006. // we find one, we see if it has expired and if so we send an
  3007. // IGMP report.
  3008. //
  3009. // Input: NTE - Pointer to NTE to check.
  3010. //
  3011. // Returns: Nothing.
  3012. //
  3013. void
  3014. IGMPTimer(
  3015. IN NetTableEntry * NTE)
  3016. {
  3017. CTELockHandle Handle;
  3018. IGMPAddr *AddrPtr, *PrevPtr;
  3019. uint IgmpVersion = 0, BodyMTU, i;
  3020. IPAddr SrcAddr;
  3021. IGMPAddr **HashPtr;
  3022. IGMPv3GroupRecord *StateRec;
  3023. uint StateRecSize;
  3024. IGMPv3RecordQueueEntry *I3Head = NULL, *i3qe;
  3025. IGMPReportQueueEntry *OldHead = NULL, *iqe;
  3026. i3qe = STRUCT_OF(IGMPv3RecordQueueEntry, &I3Head, i3qe_next);
  3027. iqe = STRUCT_OF(IGMPReportQueueEntry, &OldHead, iqe_next);
  3028. if (IGMPLevel != 2) {
  3029. return;
  3030. }
  3031. // We are doing IGMP. Run down the addresses active on this NTE.
  3032. CTEGetLock(&NTE->nte_lock, &Handle);
  3033. if (NTE->nte_flags & NTE_VALID) {
  3034. //
  3035. // If we haven't heard any query from an older version
  3036. // router during timeout period, revert to newer version.
  3037. // No need to check whether NTE is valid or not
  3038. //
  3039. if ((NTE->nte_if->IgmpVer2Timeout != 0)
  3040. && (--(NTE->nte_if->IgmpVer2Timeout) == 0)) {
  3041. NTE->nte_if->IgmpVersion = IGMPV3;
  3042. }
  3043. if ((NTE->nte_if->IgmpVer1Timeout != 0)
  3044. && (--(NTE->nte_if->IgmpVer1Timeout) == 0)) {
  3045. NTE->nte_if->IgmpVersion = IGMPV3;
  3046. }
  3047. if (NTE->nte_if->IgmpVer2Timeout != 0)
  3048. NTE->nte_if->IgmpVersion = IGMPV2;
  3049. if (NTE->nte_if->IgmpVer1Timeout != 0)
  3050. NTE->nte_if->IgmpVersion = IGMPV1;
  3051. if ((NTE->nte_if->if_flags & IF_FLAGS_NOIPADDR) &&
  3052. IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
  3053. SrcAddr = g_ValidAddr;
  3054. if (IP_ADDR_EQUAL(SrcAddr, NULL_IP_ADDR)) {
  3055. CTEFreeLock(&NTE->nte_lock, Handle);
  3056. return;
  3057. }
  3058. } else {
  3059. SrcAddr = NTE->nte_addr;
  3060. }
  3061. BodyMTU = RECORD_MTU(NTE);
  3062. IgmpVersion = NTE->nte_if->IgmpVersion;
  3063. HashPtr = NTE->nte_igmplist;
  3064. for (i=0; (i<IGMP_TABLE_SIZE) && (NTE->nte_igmplist!=NULL); i++) {
  3065. PrevPtr = STRUCT_OF(IGMPAddr, &HashPtr[i], iga_next);
  3066. AddrPtr = PrevPtr->iga_next;
  3067. while (AddrPtr != NULL) {
  3068. // Hande group response timer
  3069. if (AddrPtr->iga_resptimer != 0) {
  3070. AddrPtr->iga_resptimer--;
  3071. if ((AddrPtr->iga_resptimer == 0)
  3072. && (NTE->nte_flags & NTE_VALID)) {
  3073. GroupResponseTimeout(&i3qe, &iqe, NTE, AddrPtr);
  3074. }
  3075. }
  3076. // Handle triggered retransmission timer
  3077. if (AddrPtr->iga_trtimer != 0) {
  3078. AddrPtr->iga_trtimer--;
  3079. if ((AddrPtr->iga_trtimer == 0)
  3080. && (NTE->nte_flags & NTE_VALID)) {
  3081. RetransmissionTimeout(&i3qe, &iqe, NTE, AddrPtr);
  3082. }
  3083. }
  3084. // Delete group if no longer needed
  3085. if (IS_GROUP_DELETABLE(AddrPtr)) {
  3086. DeleteIGMPAddr(NTE, PrevPtr, &AddrPtr);
  3087. AddrPtr = PrevPtr;
  3088. }
  3089. if (NTE->nte_igmplist == NULL) {
  3090. // PrevPtr is gone
  3091. break;
  3092. }
  3093. //
  3094. // Go on to the next one.
  3095. //
  3096. PrevPtr = AddrPtr;
  3097. AddrPtr = AddrPtr->iga_next;
  3098. }
  3099. }
  3100. // Check general query timer
  3101. if ((NTE->nte_if->IgmpGeneralTimer != 0)
  3102. && (--(NTE->nte_if->IgmpGeneralTimer) == 0)) {
  3103. QueueIGMPv3GeneralResponse(&i3qe, NTE);
  3104. }
  3105. } //nte_valid
  3106. CTEFreeLock(&NTE->nte_lock, Handle);
  3107. if (IgmpVersion == IGMPV3)
  3108. SendIGMPv3Reports(I3Head, SrcAddr, BodyMTU);
  3109. else
  3110. SendOldReports(OldHead, SrcAddr);
  3111. }
  3112. //* IsMCastSourceAllowed - check if incoming packet passes interface filter
  3113. //
  3114. // Returns: DEST_MCAST if allowed, DEST_LOCAL if not.
  3115. uchar
  3116. IsMCastSourceAllowed(
  3117. IN IPAddr Dest,
  3118. IN IPAddr Source,
  3119. IN uchar Protocol,
  3120. IN NetTableEntry *NTE)
  3121. {
  3122. CTELockHandle Handle;
  3123. uchar Result = DEST_LOCAL;
  3124. IGMPAddr *AddrPtr = NULL;
  3125. IGMPSrcAddr *SrcPtr = NULL;
  3126. if (IGMPLevel != 2) {
  3127. return DEST_LOCAL;
  3128. }
  3129. // IGMP Queries must be immune to source filters or else
  3130. // we might not be able to respond to group-specific queries
  3131. // from the querier and hence lose data.
  3132. if (Protocol == PROT_IGMP) {
  3133. return DEST_MCAST;
  3134. }
  3135. CTEGetLock(&NTE->nte_lock, &Handle);
  3136. {
  3137. AddrPtr = FindIGMPAddr(NTE, Dest, NULL);
  3138. if (AddrPtr != NULL) {
  3139. SrcPtr = FindIGMPSrcAddr(AddrPtr, Source, NULL);
  3140. if (SrcPtr) {
  3141. if (IS_SOURCE_ALLOWED(AddrPtr, SrcPtr))
  3142. Result = DEST_MCAST;
  3143. } else {
  3144. if (IS_GROUP_ALLOWED(AddrPtr))
  3145. Result = DEST_MCAST;
  3146. }
  3147. }
  3148. }
  3149. CTEFreeLock(&NTE->nte_lock, Handle);
  3150. return Result;
  3151. }
  3152. //* InitIGMPForNTE - Called to do per-NTE initialization.
  3153. //
  3154. // Called when an NTE becomes valid. If we're at level 2, we put the
  3155. // all-host mcast on the list and add the address to the interface.
  3156. //
  3157. // Input: NTE - NTE on which to act.
  3158. //
  3159. // Returns: Nothing.
  3160. //
  3161. void
  3162. InitIGMPForNTE(
  3163. IN NetTableEntry * NTE)
  3164. {
  3165. if (IGMPLevel == 2) {
  3166. IGMPAddrChange(NTE, ALL_HOST_MCAST, IGMP_ADD, 0, NULL, 0, NULL);
  3167. }
  3168. if (Seed == 0) {
  3169. // No random seed yet.
  3170. Seed = (int)NTE->nte_addr;
  3171. // Make sure the inital value is odd, and less than 9 decimal digits.
  3172. RandomValue = ((Seed + (int)CTESystemUpTime()) % 100000000) | 1;
  3173. }
  3174. }
  3175. //* StopIGMPForNTE - Called to do per-NTE shutdown.
  3176. //
  3177. // Called when we're shutting down an NTE, and want to stop IGMP on it,
  3178. //
  3179. // Input: NTE - NTE on which to act.
  3180. //
  3181. // Returns: Nothing.
  3182. //
  3183. void
  3184. StopIGMPForNTE(
  3185. IN NetTableEntry * NTE)
  3186. {
  3187. if (IGMPLevel == 2) {
  3188. IGMPAddrChange(NTE, NULL_IP_ADDR, IGMP_DELETE_ALL,
  3189. 0, NULL, 0, NULL);
  3190. }
  3191. }
  3192. #pragma BEGIN_INIT
  3193. //** IGMPInit - Initialize IGMP.
  3194. //
  3195. // This bit of code initializes IGMP generally. There is also some amount
  3196. // of work done on a per-NTE basis that we do when each one is initialized.
  3197. //
  3198. // Input: Nothing.
  3199. ///
  3200. // Returns: TRUE if we init, FALSE if we don't.
  3201. //
  3202. uint
  3203. IGMPInit(void)
  3204. {
  3205. DEBUGMSG(DBG_INFO && DBG_IGMP,
  3206. (DTEXT("Initializing IGMP\n")));
  3207. if (IGMPLevel != 2)
  3208. return TRUE;
  3209. CTEInitLock(&IGMPLock);
  3210. IGMPBlockList = NULL;
  3211. IGMPBlockFlag = 0;
  3212. Seed = 0;
  3213. // We fake things a little bit. We register our receive handler, but
  3214. // since we steal buffers from ICMP we register the ICMP send complete
  3215. // handler.
  3216. IGMPProtInfo = IPRegisterProtocol(PROT_IGMP, IGMPRcv, IGMPSendComplete,
  3217. NULL, NULL, NULL, NULL);
  3218. if (IGMPProtInfo != NULL)
  3219. return TRUE;
  3220. else
  3221. return FALSE;
  3222. }
  3223. #pragma END_INIT