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.

6064 lines
155 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. mbound.c
  5. Abstract:
  6. This module implements routines associated with administratively-
  7. scoped boundaries (i.e. group-prefix boundaries). An IPv4 Local
  8. Scope boundary implicitly exists (no state needed) whenever any
  9. other boundary exists. The IPv4 Local Scope implicitly exists
  10. whenever any other scope exists.
  11. Author:
  12. dthaler@microsoft.com 4-20-98
  13. Revision History:
  14. --*/
  15. #include "allinc.h"
  16. #include "mbound.h"
  17. #include <math.h> // for floor()
  18. #pragma hdrstop
  19. #ifdef DEBUG
  20. #define INLINE
  21. #else
  22. #define INLINE __inline
  23. #endif
  24. #define MZAP_DEFAULT_BIT 0x80
  25. #define MAX_SCOPES 10
  26. SCOPE_ENTRY g_scopeEntry[MAX_SCOPES];
  27. SCOPE_ENTRY g_LocalScope;
  28. #define BOUNDARY_HASH_TABLE_SIZE 57
  29. #define BOUNDARY_HASH(X) ((X) % BOUNDARY_HASH_TABLE_SIZE)
  30. BOUNDARY_BUCKET g_bbScopeTable[BOUNDARY_HASH_TABLE_SIZE];
  31. #define ROWSTATUS_ACTIVE 1
  32. #define MIN_SCOPE_ADDR 0xef000000
  33. #define MAX_SCOPE_ADDR (0xefff0000 - 1)
  34. #define IPV4_LOCAL_SCOPE_LANG MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US)
  35. #define IPV4_LOCAL_SCOPE_NAME SN_L"IPv4 Local Scope"
  36. #define IPV4_LOCAL_SCOPE_ADDR htonl(0xefff0000)
  37. #define IPV4_LOCAL_SCOPE_MASK htonl(0xffff0000)
  38. #define IN_IPV4_LOCAL_SCOPE(x) \
  39. (((x) & IPV4_LOCAL_SCOPE_MASK) == IPV4_LOCAL_SCOPE_ADDR)
  40. LIST_ENTRY g_MasterInterfaceList;
  41. LIST_ENTRY g_MasterScopeList;
  42. #define MALLOC(dwSize) HeapAlloc(IPRouterHeap, 0, dwSize)
  43. #define FREE(x) HeapFree(IPRouterHeap, 0, x)
  44. #define MIN(x,y) (((x)<(y))?(x):(y))
  45. // Forward static declarations
  46. DWORD
  47. AssertBoundaryEntry(
  48. BOUNDARY_IF *pBoundaryIf,
  49. SCOPE_ENTRY *pScope,
  50. PBOUNDARY_ENTRY *ppBoundary
  51. );
  52. VOID
  53. MzapInitScope(
  54. PSCOPE_ENTRY pScope
  55. );
  56. DWORD
  57. MzapInitBIf(
  58. PBOUNDARY_IF pBIf
  59. );
  60. VOID
  61. MzapUninitBIf(
  62. PBOUNDARY_IF pBIf
  63. );
  64. DWORD
  65. MzapActivateBIf(
  66. PBOUNDARY_IF pBIf
  67. );
  68. //
  69. // Functions to manipulate scopes
  70. //
  71. PSCOPE_ENTRY
  72. NewScope()
  73. {
  74. DWORD dwScopeIndex;
  75. // Find an unused scope index
  76. for (dwScopeIndex=0; dwScopeIndex<MAX_SCOPES; dwScopeIndex++)
  77. {
  78. if ( !g_scopeEntry[dwScopeIndex].ipGroupAddress )
  79. {
  80. return &g_scopeEntry[ dwScopeIndex ];
  81. }
  82. }
  83. return NULL;
  84. }
  85. PSCOPE_ENTRY
  86. FindScope(
  87. IN IPV4_ADDRESS ipGroupAddress,
  88. IN IPV4_ADDRESS ipGroupMask
  89. )
  90. /*++
  91. Called by:
  92. AssertScope(), RmGetBoundary()
  93. Locks:
  94. Assumes caller holds write lock on BOUNDARY_TABLE.
  95. --*/
  96. {
  97. PLIST_ENTRY pleNode;
  98. for (pleNode = g_MasterScopeList.Flink;
  99. pleNode isnot &g_MasterScopeList;
  100. pleNode = pleNode->Flink)
  101. {
  102. SCOPE_ENTRY *pScope = CONTAINING_RECORD(pleNode, SCOPE_ENTRY,
  103. leScopeLink);
  104. if (pScope->ipGroupAddress == ipGroupAddress
  105. && pScope->ipGroupMask == ipGroupMask)
  106. return pScope;
  107. }
  108. return NULL;
  109. }
  110. PBYTE
  111. GetLangName(
  112. IN LANGID idLanguage
  113. )
  114. {
  115. char b1[8], b2[8];
  116. static char buff[80];
  117. LCID lcid = MAKELCID(idLanguage, SORT_DEFAULT);
  118. GetLocaleInfo(lcid, LOCALE_SISO639LANGNAME, b1, sizeof(b1));
  119. GetLocaleInfo(lcid, LOCALE_SISO3166CTRYNAME, b2, sizeof(b2));
  120. if (_stricmp(b1, b2))
  121. sprintf(buff, "%s-%s", b1, b2);
  122. else
  123. strcpy(buff, b1);
  124. return buff;
  125. }
  126. PSCOPE_NAME_ENTRY
  127. GetScopeNameByLangID(
  128. IN PSCOPE_ENTRY pScope,
  129. IN LANGID idLanguage
  130. )
  131. /*++
  132. Called by:
  133. AssertScopeName()
  134. --*/
  135. {
  136. PLIST_ENTRY pleNode;
  137. PSCOPE_NAME_ENTRY pName;
  138. for (pleNode = pScope->leNameList.Flink;
  139. pleNode isnot &pScope->leNameList;
  140. pleNode = pleNode->Flink)
  141. {
  142. pName = CONTAINING_RECORD(pleNode, SCOPE_NAME_ENTRY, leNameLink);
  143. if (idLanguage == pName->idLanguage)
  144. return pName;
  145. }
  146. return NULL;
  147. }
  148. PSCOPE_NAME_ENTRY
  149. GetScopeNameByLangName(
  150. IN PSCOPE_ENTRY pScope,
  151. IN PBYTE pLangName
  152. )
  153. /*++
  154. Called by:
  155. CheckForScopeNameMismatch()
  156. --*/
  157. {
  158. PLIST_ENTRY pleNode;
  159. PSCOPE_NAME_ENTRY pName;
  160. for (pleNode = pScope->leNameList.Flink;
  161. pleNode isnot &pScope->leNameList;
  162. pleNode = pleNode->Flink)
  163. {
  164. pName = CONTAINING_RECORD(pleNode, SCOPE_NAME_ENTRY, leNameLink);
  165. if (!strcmp(pLangName, GetLangName(pName->idLanguage)))
  166. return pName;
  167. }
  168. return NULL;
  169. }
  170. VOID
  171. MakePrefixStringW(
  172. OUT PWCHAR pwcPrefixStr,
  173. IN IPV4_ADDRESS ipAddr,
  174. IN IPV4_ADDRESS ipMask
  175. )
  176. {
  177. swprintf( pwcPrefixStr,
  178. L"%d.%d.%d.%d/%d",
  179. PRINT_IPADDR(ipAddr),
  180. MaskToMaskLen(ipMask) );
  181. }
  182. // Global buffers used to create messages
  183. WCHAR g_AddrBuf1[20];
  184. WCHAR g_AddrBuf2[20];
  185. WCHAR g_AddrBuf3[20];
  186. WCHAR g_AddrBuf4[20];
  187. VOID
  188. MakeAddressStringW(
  189. OUT PWCHAR pwcAddressStr,
  190. IN IPV4_ADDRESS ipAddr
  191. )
  192. {
  193. swprintf( pwcAddressStr,
  194. L"%d.%d.%d.%d",
  195. PRINT_IPADDR(ipAddr) );
  196. }
  197. SCOPE_NAME
  198. GetDefaultName(
  199. IN PSCOPE_ENTRY pScope
  200. )
  201. /*++
  202. Called by:
  203. RmGetNextScope()
  204. Various other functions for use in Trace() calls
  205. --*/
  206. {
  207. PLIST_ENTRY pleNode;
  208. PSCOPE_NAME_ENTRY pName;
  209. static SCOPE_NAME_BUFFER snScopeNameBuffer;
  210. SCOPE_NAME pFirst = NULL;
  211. for (pleNode = pScope->leNameList.Flink;
  212. pleNode isnot &pScope->leNameList;
  213. pleNode = pleNode->Flink)
  214. {
  215. pName = CONTAINING_RECORD(pleNode, SCOPE_NAME_ENTRY, leNameLink);
  216. if (pName->bDefault)
  217. return pName->snScopeName;
  218. if (!pFirst)
  219. pFirst = pName->snScopeName;
  220. }
  221. // If any names were specified, just pick the first one.
  222. if (pFirst)
  223. return pFirst;
  224. MakePrefixStringW( snScopeNameBuffer,
  225. pScope->ipGroupAddress,
  226. pScope->ipGroupMask );
  227. return snScopeNameBuffer;
  228. }
  229. VOID
  230. DeleteScopeName(
  231. IN PLIST_ENTRY pleNode
  232. )
  233. {
  234. PSCOPE_NAME_ENTRY pName = CONTAINING_RECORD( pleNode,
  235. SCOPE_NAME_ENTRY,
  236. leNameLink );
  237. RemoveEntryList(pleNode);
  238. if (pName->snScopeName)
  239. FREE(pName->snScopeName);
  240. FREE( pName );
  241. }
  242. DWORD
  243. AssertScopeName(
  244. IN PSCOPE_ENTRY pScope,
  245. IN LANGID idLanguage,
  246. IN SCOPE_NAME snScopeName // unicode string to duplicate
  247. )
  248. /*++
  249. Arguments:
  250. pScope - scope entry to modify
  251. idLanguage - language ID of new name
  252. snScopeName - new name to use
  253. Called by:
  254. MzapInitLocalScope(), AddScope(), ParseScopeInfo(), SetScopeInfo(),
  255. SNMPSetScope()
  256. --*/
  257. {
  258. SCOPE_NAME_BUFFER snScopeNameBuffer;
  259. PSCOPE_NAME_ENTRY pName;
  260. pName = GetScopeNameByLangID(pScope, idLanguage);
  261. //
  262. // See if the name is already correct.
  263. //
  264. if (pName && snScopeName && !sn_strcmp( snScopeName, pName->snScopeName ))
  265. {
  266. return NO_ERROR;
  267. }
  268. //
  269. // Create a scope name if we weren't given one
  270. //
  271. if ( snScopeName is NULL
  272. || snScopeName[0] is '\0' )
  273. {
  274. MakePrefixStringW( snScopeNameBuffer,
  275. pScope->ipGroupAddress,
  276. pScope->ipGroupMask );
  277. snScopeName = snScopeNameBuffer;
  278. }
  279. // Add a name entry if needed
  280. if (!pName)
  281. {
  282. pName = (PSCOPE_NAME_ENTRY)MALLOC( sizeof(SCOPE_NAME_ENTRY) );
  283. if (!pName)
  284. {
  285. return ERROR_NOT_ENOUGH_MEMORY;
  286. }
  287. pName->bDefault = FALSE;
  288. pName->snScopeName = NULL;
  289. pName->idLanguage = idLanguage;
  290. InsertTailList( &pScope->leNameList, &pName->leNameLink );
  291. pScope->ulNumNames++;
  292. }
  293. //
  294. // Free the old name and save the new one
  295. //
  296. if (pName->snScopeName)
  297. {
  298. FREE( pName->snScopeName );
  299. }
  300. pName->snScopeName = (SCOPE_NAME)MALLOC( (sn_strlen(snScopeName)+1)
  301. * SNCHARSIZE );
  302. if (pName->snScopeName == NULL)
  303. {
  304. DWORD dwErr = GetLastError();
  305. Trace3(
  306. ANY,
  307. "Error %d allocating %d bytes for scope name %s",
  308. dwErr, sn_strlen(snScopeName)+1, snScopeName
  309. );
  310. return dwErr;
  311. }
  312. sn_strcpy(pName->snScopeName, snScopeName);
  313. Trace4(MCAST, "Updated scope name for \"%s\": %ls (%d.%d.%d.%d/%d)",
  314. GetLangName(idLanguage),
  315. snScopeName,
  316. PRINT_IPADDR(pScope->ipGroupAddress),
  317. MaskToMaskLen(pScope->ipGroupMask) );
  318. return NO_ERROR;
  319. }
  320. VOID
  321. MzapInitLocalScope()
  322. /*++
  323. Called by:
  324. ActivateMZAP()
  325. --*/
  326. {
  327. PSCOPE_ENTRY pScope = &g_LocalScope;
  328. pScope->ipGroupAddress = IPV4_LOCAL_SCOPE_ADDR;
  329. pScope->ipGroupMask = IPV4_LOCAL_SCOPE_MASK;
  330. InitializeListHead( &pScope->leNameList );
  331. pScope->ulNumNames = 0;
  332. MzapInitScope(pScope);
  333. AssertScopeName( pScope, IPV4_LOCAL_SCOPE_LANG, IPV4_LOCAL_SCOPE_NAME );
  334. }
  335. DWORD
  336. AddScope(
  337. IN IPV4_ADDRESS ipGroupAddress,
  338. IN IPV4_ADDRESS ipGroupMask,
  339. OUT PSCOPE_ENTRY *pScopeEntry
  340. )
  341. /*++
  342. Routine Description:
  343. Add a named scope.
  344. Arguments:
  345. IN ipGroupAddress - first address in the scope to add
  346. IN ipGroupMask - mask associated with the address
  347. OUT pScope - scope entry added
  348. Called by:
  349. AssertScope()
  350. Locks:
  351. Assumes caller holds write lock on BOUNDARY_TABLE
  352. Returns:
  353. NO_ERROR
  354. ERROR_NOT_ENOUGH_MEMORY
  355. ERROR_INVALID_PARAMETER
  356. --*/
  357. {
  358. SCOPE_ENTRY *pScope;
  359. PLIST_ENTRY pleNode;
  360. // See if any bits are set in the address but not the mask
  361. if (ipGroupAddress & ~ipGroupMask)
  362. return ERROR_INVALID_PARAMETER;
  363. // Make sure the address is a valid one
  364. if (ntohl(ipGroupAddress) < MIN_SCOPE_ADDR
  365. || ntohl(ipGroupAddress) > MAX_SCOPE_ADDR)
  366. return ERROR_INVALID_PARAMETER;
  367. // Make sure we have space for this entry
  368. if ((pScope = NewScope()) == NULL)
  369. return ERROR_NOT_ENOUGH_MEMORY;
  370. pScope->ipGroupAddress = ipGroupAddress;
  371. pScope->ipGroupMask = ipGroupMask;
  372. InitializeListHead( &pScope->leNameList );
  373. pScope->ulNumNames = 0;
  374. #if 0
  375. {
  376. SCOPE_NAME_BUFFER snScopeNameBuffer;
  377. // Create a scope name if we weren't given one
  378. if ( snScopeName is NULL
  379. || snScopeName[0] is '\0' )
  380. {
  381. MakePrefixStringW( snScopeNameBuffer,
  382. pScope->ipGroupAddress,
  383. pScope->ipGroupMask );
  384. snScopeName = snScopeNameBuffer;
  385. }
  386. AssertScopeName( pScope, idLanguage, snScopeName );
  387. }
  388. #endif
  389. MzapInitScope(pScope);
  390. //
  391. // Add it to the master scope list
  392. //
  393. // Search for entry after the new one
  394. for (pleNode = g_MasterScopeList.Flink;
  395. pleNode isnot &g_MasterScopeList;
  396. pleNode = pleNode->Flink)
  397. {
  398. SCOPE_ENTRY *pPrevScope = CONTAINING_RECORD(pleNode, SCOPE_ENTRY,
  399. leScopeLink);
  400. IPV4_ADDRESS ipAddress = pPrevScope->ipGroupAddress;
  401. IPV4_ADDRESS ipMask = pPrevScope->ipGroupMask;
  402. if (ipAddress > pScope->ipGroupAddress
  403. || (ipAddress==pScope->ipGroupAddress && ipMask>pScope->ipGroupMask))
  404. break;
  405. }
  406. InsertTailList( pleNode, &pScope->leScopeLink );
  407. *pScopeEntry = pScope;
  408. #if 0
  409. Trace4(MCAST, "AddScope: added %s %ls (%d.%d.%d.%d/%d)",
  410. GetLangName( idLanguage ),
  411. snScopeName,
  412. PRINT_IPADDR(ipGroupAddress),
  413. MaskToMaskLen(ipGroupMask) );
  414. #endif
  415. Trace2(MCAST, "AddScope: added (%d.%d.%d.%d/%d)",
  416. PRINT_IPADDR(ipGroupAddress),
  417. MaskToMaskLen(ipGroupMask) );
  418. return NO_ERROR;
  419. }
  420. DWORD
  421. AssertScope(
  422. IN IPV4_ADDRESS ipGroupAddress,
  423. IN IPV4_ADDRESS ipGroupMask,
  424. OUT PSCOPE_ENTRY *ppScopeEntry
  425. )
  426. /*++
  427. Arguments:
  428. ipGroupAddress - address part of the scope prefix
  429. ipGroupMask - mask part of the scope prefix
  430. ppScopeEntry - scope entry to return to caller
  431. Locks:
  432. Assumes caller holds write lock on BOUNDARY_TABLE.
  433. Called by:
  434. SetScopeInfo()
  435. SNMPAddBoundaryToInterface()
  436. Returns:
  437. NO_ERROR - success
  438. whatever AddScope() returns
  439. --*/
  440. {
  441. DWORD dwResult = NO_ERROR;
  442. *ppScopeEntry = FindScope(ipGroupAddress, ipGroupMask);
  443. if (! *ppScopeEntry)
  444. {
  445. dwResult = AddScope(ipGroupAddress, ipGroupMask, ppScopeEntry);
  446. }
  447. return dwResult;
  448. }
  449. DWORD
  450. DeleteScope(
  451. IN PSCOPE_ENTRY pScope
  452. )
  453. /*++
  454. Routine Description:
  455. Remove all information about a given boundary.
  456. Called by:
  457. SetScopeInfo(), SNMPDeleteBoundaryFromInterface()
  458. Locks:
  459. Assumes caller holds write lock on BOUNDARY_TABLE
  460. Returns:
  461. NO_ERROR
  462. --*/
  463. {
  464. Trace2( MCAST, "ENTERED DeleteScope: %d.%d.%d.%d/%d",
  465. PRINT_IPADDR(pScope->ipGroupAddress),
  466. MaskToMaskLen(pScope->ipGroupMask) );
  467. if (pScope->ipGroupAddress == 0) {
  468. Trace0( MCAST, "LEFT DeleteScope" );
  469. return NO_ERROR; // already deleted
  470. }
  471. if (pScope->ulNumInterfaces > 0)
  472. {
  473. //
  474. // Walk all interfaces looking for references. It doesn't matter
  475. // whether this is inefficient, since it occurs extremely rarely,
  476. // if ever, and we don't care whether it takes a couple of seconds
  477. // to do.
  478. //
  479. DWORD dwBucketIdx;
  480. PLIST_ENTRY pleNode, pleNext;
  481. for (dwBucketIdx = 0;
  482. dwBucketIdx < BOUNDARY_HASH_TABLE_SIZE
  483. && pScope->ulNumInterfaces > 0;
  484. dwBucketIdx++)
  485. {
  486. for (pleNode = g_bbScopeTable[dwBucketIdx].leInterfaceList.Flink;
  487. pleNode isnot & g_bbScopeTable[dwBucketIdx].leInterfaceList;
  488. pleNode = pleNext)
  489. {
  490. BOUNDARY_ENTRY *pBoundary = CONTAINING_RECORD(pleNode,
  491. BOUNDARY_ENTRY, leBoundaryLink);
  492. // Save pointer to next node, since we may delete the current one
  493. pleNext = pleNode->Flink;
  494. if (pBoundary->pScope == pScope) {
  495. // Delete boundary
  496. RemoveEntryList(&(pBoundary->leBoundaryLink));
  497. pScope->ulNumInterfaces--;
  498. FREE(pBoundary);
  499. }
  500. }
  501. }
  502. }
  503. // Do the actual scope deletion
  504. RemoveEntryList(&(pScope->leScopeLink));
  505. pScope->ipGroupAddress = 0;
  506. pScope->ipGroupMask = 0xFFFFFFFF;
  507. while (! IsListEmpty(&pScope->leNameList) )
  508. {
  509. DeleteScopeName(pScope->leNameList.Flink);
  510. pScope->ulNumNames--;
  511. }
  512. Trace0( MCAST, "LEFT DeleteScope" );
  513. return NO_ERROR;
  514. }
  515. //
  516. // Routines to manipulate BOUNDARY_IF structures
  517. //
  518. BOUNDARY_IF *
  519. FindBIfEntry(
  520. IN DWORD dwIfIndex
  521. )
  522. /*++
  523. Locks:
  524. Assumes caller holds at least a read lock on BOUNDARY_TABLE
  525. Called by:
  526. AssertBIfEntry(), RmHasBoundary(), BindBoundaryInterface()
  527. Returns:
  528. pointer to BOUNDARY_IF entry, if found
  529. NULL, if not found
  530. --*/
  531. {
  532. PLIST_ENTRY pleNode;
  533. BOUNDARY_IF *pIf;
  534. DWORD dwBucketIdx = BOUNDARY_HASH(dwIfIndex);
  535. for (pleNode = g_bbScopeTable[dwBucketIdx].leInterfaceList.Flink;
  536. pleNode isnot & g_bbScopeTable[dwBucketIdx].leInterfaceList;
  537. pleNode = pleNode->Flink)
  538. {
  539. pIf = CONTAINING_RECORD(pleNode, BOUNDARY_IF, leBoundaryIfLink);
  540. if (pIf->dwIfIndex == dwIfIndex)
  541. return pIf;
  542. }
  543. return NULL;
  544. }
  545. BOUNDARY_IF *
  546. FindBIfEntryBySocket(
  547. IN SOCKET sMzapSocket
  548. )
  549. {
  550. register PLIST_ENTRY pleNode;
  551. register DWORD dwBucketIdx;
  552. BOUNDARY_IF *pIf;
  553. for (dwBucketIdx = 0;
  554. dwBucketIdx < BOUNDARY_HASH_TABLE_SIZE;
  555. dwBucketIdx++)
  556. {
  557. for (pleNode = g_bbScopeTable[dwBucketIdx].leInterfaceList.Flink;
  558. pleNode isnot & g_bbScopeTable[dwBucketIdx].leInterfaceList;
  559. pleNode = pleNode->Flink)
  560. {
  561. pIf = CONTAINING_RECORD(pleNode, BOUNDARY_IF, leBoundaryIfLink);
  562. if (pIf->sMzapSocket == sMzapSocket)
  563. return pIf;
  564. }
  565. }
  566. return NULL;
  567. }
  568. DWORD
  569. AddBIfEntry(
  570. IN DWORD dwIfIndex,
  571. OUT PBOUNDARY_IF *ppBoundaryIf,
  572. IN BOOL bIsOperational
  573. )
  574. /*++
  575. Locks:
  576. Assumes caller holds a write lock on BOUNDARY_TABLE
  577. Called by:
  578. AssertBIfEntry()
  579. Returns:
  580. NO_ERROR on success
  581. ERROR_NOT_ENOUGH_MEMORY
  582. --*/
  583. {
  584. PLIST_ENTRY pleNode;
  585. DWORD dwBucketIdx, dwErr = NO_ERROR;
  586. BOUNDARY_IF *pBoundaryIf;
  587. Trace1(MCAST, "AddBIfEntry %x", dwIfIndex);
  588. dwBucketIdx = BOUNDARY_HASH(dwIfIndex);
  589. pBoundaryIf = MALLOC( sizeof(BOUNDARY_IF) );
  590. if (!pBoundaryIf)
  591. return ERROR_NOT_ENOUGH_MEMORY;
  592. pBoundaryIf->dwIfIndex = dwIfIndex;
  593. InitializeListHead(&pBoundaryIf->leBoundaryList);
  594. MzapInitBIf(pBoundaryIf);
  595. if (bIsOperational)
  596. {
  597. dwErr = MzapActivateBIf(pBoundaryIf);
  598. }
  599. // find entry in bucket's list to insert before
  600. for (pleNode = g_bbScopeTable[dwBucketIdx].leInterfaceList.Flink;
  601. pleNode isnot &g_bbScopeTable[dwBucketIdx].leInterfaceList;
  602. pleNode = pleNode->Flink) {
  603. BOUNDARY_IF *pPrevIf = CONTAINING_RECORD(pleNode, BOUNDARY_IF,
  604. leBoundaryIfLink);
  605. if (pPrevIf->dwIfIndex > dwIfIndex)
  606. break;
  607. }
  608. InsertTailList( pleNode, &(pBoundaryIf->leBoundaryIfLink));
  609. // find entry in master list to insert before
  610. for (pleNode = g_MasterInterfaceList.Flink;
  611. pleNode isnot &g_MasterInterfaceList;
  612. pleNode = pleNode->Flink) {
  613. BOUNDARY_IF *pPrevIf = CONTAINING_RECORD(pleNode, BOUNDARY_IF,
  614. leBoundaryIfLink);
  615. if (pPrevIf->dwIfIndex > dwIfIndex)
  616. break;
  617. }
  618. InsertTailList( pleNode, &(pBoundaryIf->leBoundaryIfMasterLink));
  619. *ppBoundaryIf = pBoundaryIf;
  620. return dwErr;
  621. }
  622. DWORD
  623. AssertBIfEntry(
  624. IN DWORD dwIfIndex,
  625. OUT PBOUNDARY_IF *ppBoundaryIf,
  626. IN BOOL bIsOperational
  627. )
  628. /*++
  629. Locks:
  630. Assumes caller holds a write lock on BOUNDARY_TABLE
  631. Called by:
  632. SetBoundaryInfo(), SNMPAddBoundaryToInterface()
  633. --*/
  634. {
  635. if ((*ppBoundaryIf = FindBIfEntry(dwIfIndex)) != NULL)
  636. return NO_ERROR;
  637. return AddBIfEntry(dwIfIndex, ppBoundaryIf, bIsOperational);
  638. }
  639. //
  640. // Routines to manipulate BOUNDARY_ENTRY structures
  641. //
  642. BOUNDARY_ENTRY *
  643. FindBoundaryEntry(
  644. BOUNDARY_IF *pBoundaryIf,
  645. SCOPE_ENTRY *pScope
  646. )
  647. /*++
  648. Locks:
  649. Assumes caller already holds at least a read lock on BOUNDARY_TABLE
  650. Called by:
  651. AssertBoundaryEntry()
  652. Returns:
  653. pointer to BOUNDARY_ENTRY, if found
  654. NULL, if not found
  655. --*/
  656. {
  657. PLIST_ENTRY pleNode;
  658. for (pleNode = pBoundaryIf->leBoundaryList.Flink;
  659. pleNode isnot &(pBoundaryIf->leBoundaryList);
  660. pleNode = pleNode->Flink)
  661. {
  662. BOUNDARY_ENTRY *pBoundary = CONTAINING_RECORD(pleNode, BOUNDARY_ENTRY,
  663. leBoundaryLink);
  664. if (pScope == &g_LocalScope || pScope == pBoundary->pScope)
  665. return pBoundary;
  666. }
  667. return NULL;
  668. }
  669. DWORD
  670. AddBoundaryEntry(
  671. BOUNDARY_IF *pBoundaryIf,
  672. SCOPE_ENTRY *pScope,
  673. PBOUNDARY_ENTRY *ppBoundary
  674. )
  675. /*++
  676. Called by:
  677. AssertBoundaryEntry()
  678. Locks:
  679. Assumes caller holds a write lock on BOUNDARY_TABLE
  680. Returns:
  681. NO_ERROR on success
  682. ERROR_NOT_ENOUGH_MEMORY
  683. --*/
  684. {
  685. PLIST_ENTRY pleNode;
  686. Trace3(MCAST, "AddBoundaryEntry: If %x Scope %d.%d.%d.%d/%d",
  687. pBoundaryIf->dwIfIndex,
  688. PRINT_IPADDR(pScope->ipGroupAddress),
  689. MaskToMaskLen(pScope->ipGroupMask) );
  690. if ((*ppBoundary = MALLOC( sizeof(BOUNDARY_ENTRY) )) == NULL)
  691. return ERROR_NOT_ENOUGH_MEMORY;
  692. (*ppBoundary)->pScope = pScope;
  693. // Search for entry after the new one
  694. for (pleNode = pBoundaryIf->leBoundaryList.Flink;
  695. pleNode isnot &pBoundaryIf->leBoundaryList;
  696. pleNode = pleNode->Flink) {
  697. BOUNDARY_ENTRY *pPrevRange = CONTAINING_RECORD(pleNode, BOUNDARY_ENTRY,
  698. leBoundaryLink);
  699. IPV4_ADDRESS ipAddress = pPrevRange->pScope->ipGroupAddress;
  700. IPV4_ADDRESS ipMask = pPrevRange->pScope->ipGroupMask;
  701. if (ipAddress > pScope->ipGroupAddress
  702. || (ipAddress==pScope->ipGroupAddress && ipMask>pScope->ipGroupMask))
  703. break;
  704. }
  705. InsertTailList( pleNode, &((*ppBoundary)->leBoundaryLink));
  706. pScope->ulNumInterfaces++;
  707. return NO_ERROR;
  708. }
  709. DWORD
  710. AssertBoundaryEntry(
  711. BOUNDARY_IF *pBoundaryIf,
  712. SCOPE_ENTRY *pScope,
  713. PBOUNDARY_ENTRY *ppBoundary
  714. )
  715. /*++
  716. Called by:
  717. SetBoundaryInfo()
  718. Locks:
  719. Assumes caller holds a write lock on BOUNDARY_TABLE
  720. Returns:
  721. NO_ERROR on success
  722. ERROR_NOT_ENOUGH_MEMORY
  723. --*/
  724. {
  725. if ((*ppBoundary = FindBoundaryEntry(pBoundaryIf, pScope)) != NULL)
  726. return NO_ERROR;
  727. return AddBoundaryEntry(pBoundaryIf, pScope, ppBoundary);
  728. }
  729. //
  730. // Functions to manipulate boundaries
  731. //
  732. VOID
  733. DeleteBoundaryFromInterface(pBoundary, pBoundaryIf)
  734. BOUNDARY_ENTRY *pBoundary;
  735. BOUNDARY_IF *pBoundaryIf;
  736. /*++
  737. Called by:
  738. SetBoundaryInfo(), SNMPDeleteBoundaryFromInterface()
  739. --*/
  740. {
  741. Trace3(MCAST, "DeleteBoundaryFromInterface: If %x Scope %d.%d.%d.%d/%d",
  742. pBoundaryIf->dwIfIndex,
  743. PRINT_IPADDR(pBoundary->pScope->ipGroupAddress),
  744. MaskToMaskLen(pBoundary->pScope->ipGroupMask) );
  745. RemoveEntryList(&(pBoundary->leBoundaryLink));
  746. pBoundary->pScope->ulNumInterfaces--;
  747. FREE(pBoundary);
  748. //
  749. // If there are no boundaries left, delete the pBoundaryIf.
  750. //
  751. if (IsListEmpty( &pBoundaryIf->leBoundaryList ))
  752. {
  753. // Remove the BoundaryIf
  754. MzapUninitBIf( pBoundaryIf );
  755. RemoveEntryList( &(pBoundaryIf->leBoundaryIfLink));
  756. RemoveEntryList( &(pBoundaryIf->leBoundaryIfMasterLink));
  757. FREE(pBoundaryIf);
  758. }
  759. }
  760. //
  761. // Routines to process range information, which is what MGM deals with.
  762. // It's much more efficient to pass range deltas to MGM than to pass
  763. // prefixes, or original info, since overlapping boundaries might exist.
  764. //
  765. DWORD
  766. AssertRange(
  767. IN OUT PLIST_ENTRY pHead,
  768. IN IPV4_ADDRESS ipFirst,
  769. IN IPV4_ADDRESS ipLast
  770. )
  771. /*++
  772. Called by:
  773. ConvertIfTableToRanges()
  774. Locks:
  775. none
  776. --*/
  777. {
  778. PLIST_ENTRY pleLast;
  779. RANGE_ENTRY *pRange;
  780. Trace2(MCAST, "AssertRange: (%d.%d.%d.%d - %d.%d.%d.%d)",
  781. PRINT_IPADDR(ipFirst),
  782. PRINT_IPADDR(ipLast));
  783. //
  784. // Since we're calling this in <ipFirst,ipLast> order, the new
  785. // range may only overlap with the last range, if any.
  786. //
  787. pleLast = pHead->Blink;
  788. if (pleLast isnot pHead)
  789. {
  790. RANGE_ENTRY *pPrevRange = CONTAINING_RECORD(pleLast, RANGE_ENTRY,
  791. leRangeLink);
  792. // See if it aggregates
  793. if (ntohl(ipFirst) <= ntohl(pPrevRange->ipLast) + 1)
  794. {
  795. if (ntohl(ipLast) > ntohl(pPrevRange->ipLast))
  796. pPrevRange->ipLast = ipLast;
  797. return NO_ERROR;
  798. }
  799. }
  800. //
  801. // Ok, no overlap, so add a new range
  802. //
  803. pRange = MALLOC( sizeof(RANGE_ENTRY) );
  804. if (pRange == NULL)
  805. {
  806. return ERROR_NOT_ENOUGH_MEMORY;
  807. }
  808. pRange->ipFirst = ipFirst;
  809. pRange->ipLast = ipLast;
  810. InsertTailList(pHead, &pRange->leRangeLink);
  811. return NO_ERROR;
  812. }
  813. VOID
  814. ConvertIfTableToRanges(
  815. IN DWORD dwIfIndex,
  816. OUT PLIST_ENTRY pHead
  817. )
  818. /*++
  819. Routine Description:
  820. Go through the list of boundaries on a given interface, and
  821. compose an ordered list of non-overlapping ranges.
  822. Called by:
  823. ConvertTableToRanges()
  824. SetBoundaryInfo(), SNMPAddBoundaryToInterface(),
  825. SNMPDeleteBoundaryFromInterface()
  826. Locks:
  827. Assumes caller holds read lock on BOUNDARY_TABLE
  828. --*/
  829. {
  830. PLIST_ENTRY pleNode;
  831. IPV4_ADDRESS ipLastAddress;
  832. BOUNDARY_IF *pBoundaryIf;
  833. BOUNDARY_ENTRY *pBoundary;
  834. Trace1( MCAST, "ENTERED ConvertIfTableToRanges: If=%x", dwIfIndex );
  835. InitializeListHead(pHead);
  836. pBoundaryIf = FindBIfEntry(dwIfIndex);
  837. if (pBoundaryIf) {
  838. for (pleNode = pBoundaryIf->leBoundaryList.Flink;
  839. pleNode isnot &pBoundaryIf->leBoundaryList;
  840. pleNode = pleNode->Flink) {
  841. pBoundary = CONTAINING_RECORD(pleNode, BOUNDARY_ENTRY,
  842. leBoundaryLink);
  843. ipLastAddress = pBoundary->pScope->ipGroupAddress |
  844. ~pBoundary->pScope->ipGroupMask;
  845. AssertRange(pHead, pBoundary->pScope->ipGroupAddress,
  846. ipLastAddress);
  847. }
  848. // Finally, we also have one for the IPv4 Local Scope
  849. if ( !IsListEmpty( &pBoundaryIf->leBoundaryList ) ) {
  850. AssertRange(pHead, IPV4_LOCAL_SCOPE_ADDR,
  851. IPV4_LOCAL_SCOPE_ADDR | ~IPV4_LOCAL_SCOPE_MASK);
  852. }
  853. }
  854. Trace0( MCAST, "LEFT ConvertIfTableToRanges" );
  855. }
  856. DWORD
  857. ConvertTableToRanges(
  858. OUT PLIST_ENTRY pIfHead
  859. )
  860. /*++
  861. Routine description:
  862. Calculate the list of blocked ranges on all interfaces.
  863. Locks:
  864. BOUNDARY_TABLE for reading
  865. --*/
  866. {
  867. DWORD i, dwErr = NO_ERROR;
  868. PLIST_ENTRY pleNode;
  869. BOUNDARY_IF *pBoundaryIf, *pRangeIf;
  870. InitializeListHead(pIfHead);
  871. ENTER_READER(BOUNDARY_TABLE);
  872. {
  873. // For each interface with boundaries...
  874. for (i=0; i<BOUNDARY_HASH_TABLE_SIZE; i++) {
  875. for (pleNode = g_bbScopeTable[i].leInterfaceList.Flink;
  876. pleNode isnot &g_bbScopeTable[i].leInterfaceList;
  877. pleNode = pleNode->Flink) {
  878. pBoundaryIf = CONTAINING_RECORD(pleNode, BOUNDARY_IF,
  879. leBoundaryIfLink);
  880. // Add a node to the if range list
  881. pRangeIf = MALLOC( sizeof(BOUNDARY_IF) );
  882. if (pRangeIf is NULL)
  883. {
  884. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  885. break;
  886. }
  887. pRangeIf->dwIfIndex = pBoundaryIf->dwIfIndex;
  888. InsertTailList(pIfHead, &pRangeIf->leBoundaryIfLink);
  889. // Compose the range list for this interface
  890. ConvertIfTableToRanges(pBoundaryIf->dwIfIndex,
  891. &pRangeIf->leBoundaryList);
  892. }
  893. }
  894. }
  895. EXIT_LOCK(BOUNDARY_TABLE);
  896. return dwErr;
  897. }
  898. VOID
  899. GetRange(
  900. IN PLIST_ENTRY pleNode,
  901. IN PLIST_ENTRY pHead,
  902. OUT PRANGE_ENTRY *ppRange,
  903. OUT IPV4_ADDRESS *phipFirst,
  904. OUT IPV4_ADDRESS *phipLast
  905. )
  906. {
  907. if (pleNode isnot pHead)
  908. {
  909. (*ppRange) = CONTAINING_RECORD(pleNode, RANGE_ENTRY, leRangeLink);
  910. *phipFirst = ntohl((*ppRange)->ipFirst);
  911. *phipLast = ntohl((*ppRange)->ipLast);
  912. }
  913. else
  914. {
  915. (*ppRange) = NULL;
  916. *phipFirst = *phipLast = 0xFFFFFFFF;
  917. }
  918. }
  919. VOID
  920. GetRangeIf(
  921. IN PLIST_ENTRY pleNode,
  922. IN PLIST_ENTRY pHead,
  923. OUT PBOUNDARY_IF *ppRangeIf,
  924. OUT ULONG *pulIfIndex
  925. )
  926. {
  927. if (pleNode isnot pHead)
  928. {
  929. (*ppRangeIf) = CONTAINING_RECORD(pleNode, BOUNDARY_IF, leBoundaryIfLink);
  930. *pulIfIndex = (*ppRangeIf)->dwIfIndex;
  931. }
  932. else
  933. {
  934. (*ppRangeIf) = NULL;
  935. *pulIfIndex = 0xFFFFFFFF;
  936. }
  937. }
  938. VOID
  939. FreeRangeList(
  940. IN PLIST_ENTRY pHead
  941. )
  942. /*++
  943. Routine description:
  944. Free up space from a range list
  945. Called by:
  946. ProcessIfRangeDeltas()
  947. Locks:
  948. none
  949. --*/
  950. {
  951. RANGE_ENTRY *pRange;
  952. PLIST_ENTRY pleNode;
  953. for (pleNode = pHead->Flink;
  954. pleNode isnot pHead;
  955. pleNode = pHead->Flink)
  956. {
  957. pRange = CONTAINING_RECORD(pleNode, RANGE_ENTRY, leRangeLink);
  958. RemoveEntryList(&pRange->leRangeLink);
  959. FREE(pRange);
  960. }
  961. }
  962. VOID
  963. FreeIfRangeLists(
  964. IN PLIST_ENTRY pHead
  965. )
  966. /*++
  967. Routine description:
  968. Free all entries in the list, as well as the list of ranges off each entry.
  969. Called by:
  970. ProcessRangeDeltas()
  971. Locks:
  972. none
  973. --*/
  974. {
  975. BOUNDARY_IF *pRangeIf;
  976. PLIST_ENTRY pleNode;
  977. for (pleNode = pHead->Flink;
  978. pleNode isnot pHead;
  979. pleNode = pHead->Flink)
  980. {
  981. pRangeIf = CONTAINING_RECORD(pleNode, BOUNDARY_IF, leBoundaryIfLink);
  982. RemoveEntryList(&pRangeIf->leBoundaryIfLink);
  983. FreeRangeList(&pRangeIf->leBoundaryList);
  984. FREE(pRangeIf);
  985. }
  986. }
  987. //
  988. // Check if the interface
  989. // is the RAS Server Interface in which case, the
  990. // callback should be invoked for all clients connected
  991. // and the NEXT HOP address should be set to the client
  992. // address. Otherwise zero should be fine as NHOP
  993. //
  994. VOID
  995. BlockGroups(
  996. IN IPV4_ADDRESS ipFirst,
  997. IN IPV4_ADDRESS ipLast,
  998. IN DWORD dwIfIndex
  999. )
  1000. {
  1001. IPV4_ADDRESS ipNextHop;
  1002. PICB picb;
  1003. PLIST_ENTRY pleNode;
  1004. ENTER_READER(ICB_LIST);
  1005. do {
  1006. // Look up the type of this interface
  1007. picb = InterfaceLookupByIfIndex(dwIfIndex);
  1008. if (picb==NULL)
  1009. break;
  1010. // If interface is not an NBMA interface, just block on the interface
  1011. // Currently, the only NBMA-like interface is the "internal" interface
  1012. if (picb->ritType isnot ROUTER_IF_TYPE_INTERNAL)
  1013. {
  1014. Trace3( MCAST,
  1015. "Blocking [%d.%d.%d.%d-%d.%d.%d.%d] on if %x",
  1016. PRINT_IPADDR(ipFirst),
  1017. PRINT_IPADDR(ipLast),
  1018. dwIfIndex );
  1019. g_pfnMgmBlockGroups(ipFirst, ipLast, dwIfIndex, 0);
  1020. break;
  1021. }
  1022. // For NBMA interfaces, need to block on each next hop
  1023. // to enumerate all next hops on the internal interface,
  1024. // we have to walk the PICB list looking for entries with
  1025. // an ifIndex of -1.
  1026. for (pleNode = ICBList.Flink;
  1027. pleNode isnot &ICBList;
  1028. pleNode = pleNode->Flink)
  1029. {
  1030. picb = CONTAINING_RECORD(pleNode, ICB, leIfLink);
  1031. if (picb->ritType isnot ROUTER_IF_TYPE_CLIENT)
  1032. continue;
  1033. Trace4( MCAST,
  1034. "Blocking [%d.%d.%d.%d-%d.%d.%d.%d] on if %x nh %d.%d.%d.%d",
  1035. PRINT_IPADDR(ipFirst),
  1036. PRINT_IPADDR(ipLast),
  1037. dwIfIndex,
  1038. PRINT_IPADDR(picb->dwRemoteAddress) );
  1039. g_pfnMgmBlockGroups( ipFirst,
  1040. ipLast,
  1041. dwIfIndex,
  1042. picb->dwRemoteAddress );
  1043. }
  1044. } while(0);
  1045. EXIT_LOCK(ICB_LIST);
  1046. }
  1047. //
  1048. // Check if the interface
  1049. // is the RAS Server Interface in which case, the
  1050. // callback should be invoked for all clients connected
  1051. // and the NEXT HOP address should be set to the client
  1052. // address. Otherwise zero should be fine as NHOP
  1053. //
  1054. VOID
  1055. UnblockGroups(
  1056. IN IPV4_ADDRESS ipFirst,
  1057. IN IPV4_ADDRESS ipLast,
  1058. IN DWORD dwIfIndex
  1059. )
  1060. {
  1061. IPV4_ADDRESS ipNextHop;
  1062. PICB picb;
  1063. PLIST_ENTRY pleNode;
  1064. ENTER_READER(ICB_LIST);
  1065. do {
  1066. // Look up the type of this interface
  1067. picb = InterfaceLookupByIfIndex(dwIfIndex);
  1068. if (picb == NULL )
  1069. break;
  1070. // If interface is not an NBMA interface, just block on the interface
  1071. // Currently, the only NBMA-like interface is the "internal" interface
  1072. if (picb->ritType isnot ROUTER_IF_TYPE_INTERNAL)
  1073. {
  1074. Trace3( MCAST,
  1075. "Unblocking [%d.%d.%d.%d-%d.%d.%d.%d] on if %x",
  1076. PRINT_IPADDR(ipFirst),
  1077. PRINT_IPADDR(ipLast),
  1078. dwIfIndex );
  1079. g_pfnMgmUnBlockGroups(ipFirst, ipLast, dwIfIndex, 0);
  1080. break;
  1081. }
  1082. // For NBMA interfaces, need to block on each next hop
  1083. // to enumerate all next hops on the internal interface,
  1084. // we have to walk the PICB list looking for entries with
  1085. // an ifIndex of -1.
  1086. for (pleNode = ICBList.Flink;
  1087. pleNode isnot &ICBList;
  1088. pleNode = pleNode->Flink)
  1089. {
  1090. picb = CONTAINING_RECORD(pleNode, ICB, leIfLink);
  1091. if (picb->ritType isnot ROUTER_IF_TYPE_CLIENT)
  1092. continue;
  1093. Trace4( MCAST,
  1094. "Unblocking [%d.%d.%d.%d-%d.%d.%d.%d] on if %x nh %d.%d.%d.%d",
  1095. PRINT_IPADDR(ipFirst),
  1096. PRINT_IPADDR(ipLast),
  1097. dwIfIndex,
  1098. PRINT_IPADDR(picb->dwRemoteAddress) );
  1099. g_pfnMgmUnBlockGroups( ipFirst,
  1100. ipLast,
  1101. dwIfIndex,
  1102. picb->dwRemoteAddress );
  1103. }
  1104. } while(0);
  1105. EXIT_LOCK(ICB_LIST);
  1106. }
  1107. VOID
  1108. ProcessIfRangeDeltas(
  1109. IN DWORD dwIfIndex,
  1110. IN PLIST_ENTRY pOldHead,
  1111. IN PLIST_ENTRY pNewHead
  1112. )
  1113. /*++
  1114. Routine Description:
  1115. Go through the previous and current lists of ranges, and inform
  1116. MGM of any differences found.
  1117. Called by:
  1118. SetBoundaryInfo(), SNMPAddBoundaryToInterface(),
  1119. SNMPDeleteBoundaryFromInterface()
  1120. Locks:
  1121. none
  1122. --*/
  1123. {
  1124. PLIST_ENTRY pleOld = pOldHead->Flink,
  1125. pleNew = pNewHead->Flink;
  1126. RANGE_ENTRY *pOld, *pNew;
  1127. IPV4_ADDRESS hipOldFirst, hipOldLast, hipNewFirst, hipNewLast;
  1128. IPV4_ADDRESS hipLast;
  1129. // Get ranges in host order fields
  1130. GetRange(pleOld, pOldHead, &pOld, &hipOldFirst, &hipOldLast);
  1131. GetRange(pleNew, pNewHead, &pNew, &hipNewFirst, &hipNewLast);
  1132. // Loop until we hit the end of both lists
  1133. while (pOld || pNew)
  1134. {
  1135. // See if there's a new range to block
  1136. if (pNew && hipNewFirst < hipOldFirst)
  1137. {
  1138. hipLast = MIN(hipNewLast, hipOldFirst-1);
  1139. BlockGroups(pNew->ipFirst, htonl(hipLast), dwIfIndex);
  1140. hipNewFirst = hipOldFirst;
  1141. pNew->ipFirst = htonl(hipNewFirst);
  1142. if (hipNewFirst > hipNewLast)
  1143. {
  1144. // advance new
  1145. pleNew = pleNew->Flink;
  1146. GetRange(pleNew, pNewHead, &pNew, &hipNewFirst, &hipNewLast);
  1147. }
  1148. }
  1149. // See if there's an old range to unblock
  1150. if (pOld && hipOldFirst < hipNewFirst)
  1151. {
  1152. hipLast = MIN(hipOldLast, hipNewFirst-1);
  1153. UnblockGroups(pOld->ipFirst, htonl(hipLast), dwIfIndex);
  1154. hipOldFirst = hipNewFirst;
  1155. pOld->ipFirst = htonl(hipOldFirst);
  1156. if (hipOldFirst > hipOldLast)
  1157. {
  1158. // advance old
  1159. pleOld = pleOld->Flink;
  1160. GetRange(pleOld, pOldHead, &pOld, &hipOldFirst, &hipOldLast);
  1161. }
  1162. }
  1163. // See if there's an unchanged range to skip
  1164. if (pOld && pNew && hipOldFirst == hipNewFirst)
  1165. {
  1166. hipLast = MIN(hipOldLast, hipNewLast);
  1167. hipOldFirst = hipLast+1;
  1168. pOld->ipFirst = htonl(hipOldFirst);
  1169. if (hipOldFirst > hipOldLast)
  1170. {
  1171. // advance old
  1172. pleOld = pleOld->Flink;
  1173. GetRange(pleOld, pOldHead, &pOld, &hipOldFirst, &hipOldLast);
  1174. }
  1175. hipNewFirst = hipLast+1;
  1176. pNew->ipFirst = htonl(hipNewFirst);
  1177. if (hipNewFirst > hipNewLast)
  1178. {
  1179. // advance new
  1180. pleNew = pleNew->Flink;
  1181. GetRange(pleNew, pNewHead, &pNew, &hipNewFirst, &hipNewLast);
  1182. }
  1183. }
  1184. }
  1185. FreeRangeList(pOldHead);
  1186. FreeRangeList(pNewHead);
  1187. }
  1188. VOID
  1189. ProcessRangeDeltas(
  1190. IN PLIST_ENTRY pOldIfHead,
  1191. IN PLIST_ENTRY pNewIfHead
  1192. )
  1193. {
  1194. PLIST_ENTRY pleOldIf = pOldIfHead->Flink,
  1195. pleNewIf = pNewIfHead->Flink;
  1196. BOUNDARY_IF *pOldIf, *pNewIf;
  1197. ULONG ulOldIfIndex, ulNewIfIndex;
  1198. LIST_ENTRY emptyList;
  1199. GetRangeIf(pleOldIf, pOldIfHead, &pOldIf, &ulOldIfIndex);
  1200. GetRangeIf(pleNewIf, pNewIfHead, &pNewIf, &ulNewIfIndex);
  1201. InitializeListHead(&emptyList);
  1202. // Loop until we hit the end of both lists
  1203. while (pOldIf || pNewIf)
  1204. {
  1205. // See if there's a new interface without old boundaries
  1206. if (pNewIf && ulNewIfIndex < ulOldIfIndex)
  1207. {
  1208. // process it
  1209. ProcessIfRangeDeltas(ulNewIfIndex, &emptyList,
  1210. &pNewIf->leBoundaryList);
  1211. // advance new
  1212. pleNewIf = pleNewIf->Flink;
  1213. GetRangeIf(pleNewIf, pNewIfHead, &pNewIf, &ulNewIfIndex);
  1214. }
  1215. // See if there's an old interface without new boundaries
  1216. if (pOldIf && ulOldIfIndex < ulNewIfIndex)
  1217. {
  1218. // process it
  1219. ProcessIfRangeDeltas(ulOldIfIndex, &pOldIf->leBoundaryList,
  1220. &emptyList);
  1221. // advance old
  1222. pleOldIf = pleOldIf->Flink;
  1223. GetRangeIf(pleOldIf, pOldIfHead, &pOldIf, &ulOldIfIndex);
  1224. }
  1225. // See if there's an ifindex to change
  1226. if (pOldIf && pNewIf && ulOldIfIndex == ulNewIfIndex)
  1227. {
  1228. // process it
  1229. ProcessIfRangeDeltas(ulOldIfIndex, &pOldIf->leBoundaryList,
  1230. &pNewIf->leBoundaryList);
  1231. // advance old
  1232. pleOldIf = pleOldIf->Flink;
  1233. GetRangeIf(pleOldIf, pOldIfHead, &pOldIf, &ulOldIfIndex);
  1234. // advance new
  1235. pleNewIf = pleNewIf->Flink;
  1236. GetRangeIf(pleNewIf, pNewIfHead, &pNewIf, &ulNewIfIndex);
  1237. }
  1238. }
  1239. FreeIfRangeLists(pOldIfHead);
  1240. FreeIfRangeLists(pNewIfHead);
  1241. }
  1242. VOID
  1243. ParseScopeInfo(
  1244. IN PBYTE pBuffer,
  1245. IN ULONG ulNumScopes,
  1246. OUT PSCOPE_ENTRY *ppScopes
  1247. )
  1248. /*++
  1249. Description:
  1250. Routines to parse registry info into a pre-allocated array.
  1251. Space for names will be dynamically allocated by this function,
  1252. and it is the caller's responsibility to free them.
  1253. Called by:
  1254. SetScopeInfo()
  1255. --*/
  1256. {
  1257. DWORD i, j, dwLen, dwNumNames, dwLanguage, dwFlags;
  1258. SCOPE_NAME_BUFFER pScopeName;
  1259. PSCOPE_ENTRY pScopes;
  1260. *ppScopes = pScopes = MALLOC( ulNumScopes * sizeof(SCOPE_ENTRY) );
  1261. for (i=0; i<ulNumScopes; i++)
  1262. {
  1263. // Copy group address, and mask
  1264. dwLen = 2 * sizeof(IPV4_ADDRESS);
  1265. CopyMemory(&pScopes[i].ipGroupAddress, pBuffer, dwLen);
  1266. pBuffer += dwLen;
  1267. // Get flags
  1268. CopyMemory(&dwFlags, pBuffer, sizeof(DWORD));
  1269. pBuffer += sizeof(DWORD);
  1270. pScopes[i].bDivisible = dwFlags;
  1271. CopyMemory(&dwNumNames, pBuffer, sizeof(DWORD));
  1272. pBuffer += sizeof(DWORD);
  1273. pScopes[i].ulNumInterfaces = 0; // this value is ignored
  1274. pScopes[i].ulNumNames = 0;
  1275. InitializeListHead( &pScopes[i].leNameList );
  1276. for (j=0; j<dwNumNames; j++)
  1277. {
  1278. // Set language name
  1279. CopyMemory(&dwLanguage, pBuffer, sizeof(dwLanguage));
  1280. pBuffer += sizeof(dwLanguage);
  1281. // Get scope name length
  1282. CopyMemory(&dwLen, pBuffer, sizeof(DWORD));
  1283. pBuffer += sizeof(DWORD);
  1284. if (dwLen > MAX_SCOPE_NAME_LEN)
  1285. {
  1286. Trace2(MCAST,
  1287. "ERROR %d-char scope name in registry, truncated to %d",
  1288. dwLen, MAX_SCOPE_NAME_LEN);
  1289. dwLen = MAX_SCOPE_NAME_LEN;
  1290. }
  1291. // Set scope name
  1292. wcsncpy(pScopeName, (SCOPE_NAME)pBuffer, dwLen);
  1293. pScopeName[ dwLen ] = '\0';
  1294. pBuffer += dwLen * SNCHARSIZE;
  1295. AssertScopeName( &pScopes[i], (LANGID)dwLanguage, pScopeName );
  1296. }
  1297. }
  1298. }
  1299. VOID
  1300. FreeScopeInfo(
  1301. PSCOPE_ENTRY pScopes,
  1302. DWORD dwNumScopes
  1303. )
  1304. {
  1305. PLIST_ENTRY pleNode;
  1306. DWORD i;
  1307. for (i=0; i<dwNumScopes; i++)
  1308. {
  1309. while (!IsListEmpty(&pScopes[i].leNameList))
  1310. {
  1311. DeleteScopeName( pScopes[i].leNameList.Flink );
  1312. }
  1313. }
  1314. FREE(pScopes);
  1315. }
  1316. DWORD
  1317. SetScopeInfo(
  1318. PRTR_INFO_BLOCK_HEADER pInfoHdr
  1319. )
  1320. /*++
  1321. Routine Description:
  1322. Sets the scope info associated with the router.
  1323. First we add the scopes present in the scope info. Then we
  1324. enumerate the scopes and delete those that we don't find in the
  1325. scope info.
  1326. Locks:
  1327. BOUNDARY_TABLE for writing
  1328. Called by:
  1329. InitRouter() in init.c
  1330. SetGlobalInfo() in iprtrmgr.c
  1331. --*/
  1332. {
  1333. DWORD dwResult = NO_ERROR;
  1334. DWORD dwNumScopes, i, j;
  1335. PRTR_TOC_ENTRY pToc;
  1336. SCOPE_ENTRY *pScopes;
  1337. BOOL bFound;
  1338. SCOPE_ENTRY *pScope;
  1339. BYTE *pBuffer;
  1340. LIST_ENTRY leOldIfRanges, leNewIfRanges;
  1341. PSCOPE_NAME_ENTRY pName;
  1342. PLIST_ENTRY pleNode;
  1343. Trace0( MCAST, "ENTERED SetScopeInfo" );
  1344. pToc = GetPointerToTocEntry(IP_MCAST_BOUNDARY_INFO, pInfoHdr);
  1345. if (pToc is NULL) {
  1346. // No TOC means no change
  1347. Trace0( MCAST, "LEFT SetScopeInfo" );
  1348. return NO_ERROR;
  1349. }
  1350. //
  1351. // This call wouldn't be needed if we saved this info in the
  1352. // BOUNDARY_IF structure, but since it should rarely, if ever,
  1353. // change, we won't worry about it for now.
  1354. //
  1355. dwResult = ConvertTableToRanges(&leOldIfRanges);
  1356. if (dwResult isnot NO_ERROR) {
  1357. return dwResult;
  1358. }
  1359. if (pToc->InfoSize is 0)
  1360. {
  1361. StopMZAP();
  1362. // delete all scopes
  1363. ENTER_WRITER(BOUNDARY_TABLE);
  1364. {
  1365. for (i=0; i<MAX_SCOPES; i++)
  1366. DeleteScope(&g_scopeEntry[i]);
  1367. }
  1368. EXIT_LOCK(BOUNDARY_TABLE);
  1369. // Inform MGM of deltas
  1370. dwResult = ConvertTableToRanges(&leNewIfRanges);
  1371. if (dwResult isnot NO_ERROR)
  1372. {
  1373. return dwResult;
  1374. }
  1375. ProcessRangeDeltas(&leOldIfRanges, &leNewIfRanges);
  1376. Trace0( MCAST, "LEFT SetScopeInfo" );
  1377. return NO_ERROR;
  1378. }
  1379. pBuffer = (PBYTE)GetInfoFromTocEntry(pInfoHdr, pToc);
  1380. if (pBuffer is NULL)
  1381. {
  1382. return ERROR_INSUFFICIENT_BUFFER;
  1383. }
  1384. // Scope count is stored in first DWORD
  1385. dwNumScopes = *((PDWORD) pBuffer);
  1386. pBuffer += sizeof(DWORD);
  1387. ParseScopeInfo(pBuffer, dwNumScopes, &pScopes);
  1388. ENTER_WRITER(BOUNDARY_TABLE);
  1389. {
  1390. //
  1391. // Add all the new scopes
  1392. //
  1393. for (i=0; i<dwNumScopes; i++)
  1394. {
  1395. dwResult = AssertScope( pScopes[i].ipGroupAddress,
  1396. pScopes[i].ipGroupMask,
  1397. &pScope );
  1398. if (!pScope)
  1399. {
  1400. Trace2( MCAST,
  1401. "Bad scope prefix %d.%d.%d.%d/%d.%d.%d.%d",
  1402. PRINT_IPADDR(pScopes[i].ipGroupAddress),
  1403. PRINT_IPADDR(pScopes[i].ipGroupMask) );
  1404. continue;
  1405. }
  1406. pScope->bDivisible = pScopes[i].bDivisible;
  1407. for (pleNode = pScopes[i].leNameList.Flink;
  1408. pleNode isnot &pScopes[i].leNameList;
  1409. pleNode = pleNode->Flink)
  1410. {
  1411. pName = CONTAINING_RECORD(pleNode, SCOPE_NAME_ENTRY, leNameLink);
  1412. AssertScopeName( pScope, pName->idLanguage, pName->snScopeName );
  1413. }
  1414. }
  1415. //
  1416. // Now enumerate the scopes, deleting the scopes that are not in the
  1417. // new list.
  1418. //
  1419. for (i=0; i<MAX_SCOPES; i++)
  1420. {
  1421. pScope = &g_scopeEntry[i];
  1422. if (pScope->ipGroupAddress == 0)
  1423. continue; // not active
  1424. bFound = FALSE;
  1425. for (j=0; j<dwNumScopes; j++)
  1426. {
  1427. if (pScopes[j].ipGroupAddress == pScope->ipGroupAddress
  1428. && pScopes[j].ipGroupMask == pScope->ipGroupMask )
  1429. {
  1430. bFound = TRUE;
  1431. break;
  1432. }
  1433. }
  1434. if (!bFound)
  1435. DeleteScope(pScope);
  1436. }
  1437. }
  1438. EXIT_LOCK(BOUNDARY_TABLE);
  1439. // Free scopes and names
  1440. FreeScopeInfo(pScopes, dwNumScopes);
  1441. dwResult = ConvertTableToRanges(&leNewIfRanges);
  1442. if (dwResult isnot NO_ERROR) {
  1443. return dwResult;
  1444. }
  1445. ProcessRangeDeltas(&leOldIfRanges, &leNewIfRanges);
  1446. Trace0( MCAST, "LEFT SetScopeInfo" );
  1447. return NO_ERROR;
  1448. }
  1449. DWORD
  1450. GetScopeInfo(
  1451. IN OUT PRTR_TOC_ENTRY pToc,
  1452. IN OUT PDWORD pdwTocIndex,
  1453. IN OUT PBYTE pBuffer,
  1454. IN PRTR_INFO_BLOCK_HEADER pInfoHdr,
  1455. IN OUT PDWORD pdwBufferSize
  1456. )
  1457. /*++
  1458. Routine Description:
  1459. Called to get a copy of the scope information to write into the
  1460. registry.
  1461. Locks:
  1462. BOUNDARY_TABLE for reading
  1463. Arguments:
  1464. pToc Space to fill in the TOC entry (may be NULL)
  1465. pdwTocIndex Pointer to TOC index to be incremented if TOC written
  1466. pBuffer Pointer to buffer into which info is to be written
  1467. pInfoHdr Pointer to info block header for offset computation
  1468. pdwBufferSize [IN] Size of the buffer pointed to by pBuffer
  1469. [OUT] Size of data copied out, or size of buffer needed
  1470. Called by:
  1471. GetGlobalConfiguration() in info.c
  1472. Return Value:
  1473. NO_ERROR Buffer of size *pdwBufferSize was copied out
  1474. ERROR_INSUFFICIENT_BUFFER The buffer was too small to copy out the info
  1475. The size of buffer needed is in *pdwBufferSize
  1476. --*/
  1477. {
  1478. DWORD i, dwSizeReqd, dwNumScopes, dwLen, dwNumNames,
  1479. dwLanguage, dwFlags;
  1480. PLIST_ENTRY pleNode, pleNode2;
  1481. PSCOPE_ENTRY pScope;
  1482. PSCOPE_NAME_ENTRY pName;
  1483. dwSizeReqd = sizeof(DWORD);
  1484. dwNumScopes = 0;
  1485. ENTER_READER(BOUNDARY_TABLE);
  1486. {
  1487. //
  1488. // Calculate size required
  1489. //
  1490. for (pleNode = g_MasterScopeList.Flink;
  1491. pleNode isnot &g_MasterScopeList;
  1492. pleNode = pleNode->Flink)
  1493. {
  1494. pScope = CONTAINING_RECORD(pleNode, SCOPE_ENTRY, leScopeLink);
  1495. if ( !pScope->ipGroupAddress )
  1496. continue; // not active
  1497. dwSizeReqd += 2*sizeof(IPV4_ADDRESS) + 2*sizeof(DWORD);
  1498. for (pleNode2 = pScope->leNameList.Flink;
  1499. pleNode2 isnot &pScope->leNameList;
  1500. pleNode2 = pleNode2->Flink)
  1501. {
  1502. pName = CONTAINING_RECORD( pleNode2,
  1503. SCOPE_NAME_ENTRY,
  1504. leNameLink );
  1505. dwSizeReqd += (DWORD)(2 * sizeof(DWORD)
  1506. + sn_strlen(pName->snScopeName) * SNCHARSIZE);
  1507. }
  1508. dwNumScopes++;
  1509. }
  1510. if (dwNumScopes) {
  1511. dwSizeReqd += sizeof(DWORD); // space for scope count
  1512. }
  1513. //
  1514. // Increment TOC index by number of TOC entries needed
  1515. //
  1516. if (pdwTocIndex && dwSizeReqd>0)
  1517. (*pdwTocIndex)++;
  1518. if (dwSizeReqd > *pdwBufferSize)
  1519. {
  1520. *pdwBufferSize = dwSizeReqd;
  1521. EXIT_LOCK(BOUNDARY_TABLE);
  1522. return ERROR_INSUFFICIENT_BUFFER;
  1523. }
  1524. *pdwBufferSize = dwSizeReqd;
  1525. if (pToc)
  1526. {
  1527. //pToc->InfoVersion = IP_MCAST_BOUNDARY_INFO;
  1528. pToc->InfoType = IP_MCAST_BOUNDARY_INFO;
  1529. pToc->Count = 1; // single variable-sized opaque block
  1530. pToc->InfoSize = dwSizeReqd;
  1531. pToc->Offset = (ULONG)(pBuffer - (PBYTE) pInfoHdr);
  1532. }
  1533. if (pBuffer)
  1534. {
  1535. //
  1536. // Add scope count
  1537. //
  1538. CopyMemory(pBuffer, &dwNumScopes, sizeof(DWORD));
  1539. pBuffer += sizeof(DWORD);
  1540. //
  1541. // Go through and get each scope
  1542. //
  1543. for (pleNode = g_MasterScopeList.Flink;
  1544. pleNode isnot &g_MasterScopeList;
  1545. pleNode = pleNode->Flink)
  1546. {
  1547. pScope = CONTAINING_RECORD(pleNode, SCOPE_ENTRY, leScopeLink);
  1548. if ( !pScope->ipGroupAddress )
  1549. continue; // not active
  1550. // Copy scope address, and mask
  1551. dwLen = 2 * sizeof(IPV4_ADDRESS);
  1552. CopyMemory(pBuffer, &pScope->ipGroupAddress, dwLen);
  1553. pBuffer += dwLen;
  1554. // Copy flags
  1555. dwFlags = pScope->bDivisible;
  1556. CopyMemory(pBuffer, &dwFlags, sizeof(dwFlags));
  1557. pBuffer += sizeof(dwFlags);
  1558. // Copy # of names
  1559. CopyMemory(pBuffer, &pScope->ulNumNames, sizeof(DWORD));
  1560. pBuffer += sizeof(DWORD);
  1561. for (pleNode2 = pScope->leNameList.Flink;
  1562. pleNode2 isnot &pScope->leNameList;
  1563. pleNode2 = pleNode2->Flink)
  1564. {
  1565. pName = CONTAINING_RECORD( pleNode2,
  1566. SCOPE_NAME_ENTRY,
  1567. leNameLink );
  1568. // Save language
  1569. dwLanguage = pName->idLanguage;
  1570. CopyMemory(pBuffer, &dwLanguage, sizeof(dwLanguage));
  1571. pBuffer += sizeof(dwLanguage);
  1572. // Copy scope name (save length in words)
  1573. dwLen = sn_strlen(pName->snScopeName);
  1574. CopyMemory(pBuffer, &dwLen, sizeof(DWORD));
  1575. pBuffer += sizeof(DWORD);
  1576. dwLen *= SNCHARSIZE;
  1577. CopyMemory(pBuffer, pName->snScopeName, dwLen);
  1578. pBuffer += dwLen;
  1579. }
  1580. }
  1581. }
  1582. }
  1583. EXIT_LOCK(BOUNDARY_TABLE);
  1584. return NO_ERROR;
  1585. }
  1586. DWORD
  1587. SetBoundaryInfo(
  1588. PICB picb,
  1589. PRTR_INFO_BLOCK_HEADER pInfoHdr
  1590. )
  1591. /*++
  1592. Routine Description:
  1593. Sets the boundary info associated with an interface.
  1594. First we add the boundaries present in the boundary info. Then we
  1595. enumerate the boundaries and delete those that we don't find in the
  1596. boundary info.
  1597. Arguments:
  1598. picb The ICB of the interface
  1599. Called by:
  1600. AddInterface() in iprtrmgr.c
  1601. SetInterfaceInfo() in iprtrmgr.c
  1602. Locks:
  1603. BOUNDARY_TABLE for writing
  1604. --*/
  1605. {
  1606. DWORD dwResult = NO_ERROR,
  1607. dwNumBoundaries, i, j;
  1608. PRTR_TOC_ENTRY pToc;
  1609. PMIB_BOUNDARYROW pBoundaries;
  1610. BOOL bFound;
  1611. BOUNDARY_ENTRY *pBoundary;
  1612. SCOPE_ENTRY *pScope;
  1613. LIST_ENTRY leOldRanges,
  1614. leNewRanges,
  1615. *pleNode,
  1616. *pleNext;
  1617. BOUNDARY_IF *pBoundaryIf;
  1618. Trace1( MCAST, "ENTERED SetBoundaryInfo for If %x", picb->dwIfIndex );
  1619. pToc = GetPointerToTocEntry(IP_MCAST_BOUNDARY_INFO, pInfoHdr);
  1620. if (pToc is NULL)
  1621. {
  1622. // No TOC means no change
  1623. Trace0( MCAST, "LEFT SetBoundaryInfo" );
  1624. return NO_ERROR;
  1625. }
  1626. dwNumBoundaries = pToc->Count;
  1627. ENTER_WRITER(BOUNDARY_TABLE);
  1628. {
  1629. //
  1630. // This call wouldn't be needed if we saved this info in the
  1631. // BOUNDARY_IF structure, but since it should rarely, if ever,
  1632. // change, we won't worry about it for now.
  1633. //
  1634. ConvertIfTableToRanges(picb->dwIfIndex, &leOldRanges);
  1635. if (pToc->InfoSize is 0)
  1636. {
  1637. // Delete all boundaries on this interface
  1638. pBoundaryIf = FindBIfEntry(picb->dwIfIndex);
  1639. if (pBoundaryIf)
  1640. {
  1641. for (pleNode = pBoundaryIf->leBoundaryList.Flink;
  1642. pleNode isnot &pBoundaryIf->leBoundaryList;
  1643. pleNode = pBoundaryIf->leBoundaryList.Flink)
  1644. {
  1645. pBoundary = CONTAINING_RECORD(pleNode, BOUNDARY_ENTRY,
  1646. leBoundaryLink);
  1647. DeleteBoundaryFromInterface(pBoundary, pBoundaryIf);
  1648. }
  1649. }
  1650. }
  1651. else
  1652. {
  1653. pBoundaries = (PMIB_BOUNDARYROW)GetInfoFromTocEntry(pInfoHdr, pToc);
  1654. dwResult = AssertBIfEntry(picb->dwIfIndex, &pBoundaryIf,
  1655. (picb->dwOperationalState is IF_OPER_STATUS_OPERATIONAL));
  1656. // Add all the new boundaries
  1657. for (i=0; i<dwNumBoundaries; i++)
  1658. {
  1659. dwResult = AssertScope( pBoundaries[i].dwGroupAddress,
  1660. pBoundaries[i].dwGroupMask,
  1661. &pScope );
  1662. if (pScope)
  1663. {
  1664. dwResult = AssertBoundaryEntry( pBoundaryIf,
  1665. pScope,
  1666. &pBoundary);
  1667. }
  1668. }
  1669. //
  1670. // Now enumerate the boundaries, deleting the boundaries that are
  1671. // not in the new list.
  1672. //
  1673. for (pleNode = pBoundaryIf->leBoundaryList.Flink;
  1674. pleNode isnot &pBoundaryIf->leBoundaryList;
  1675. pleNode = pleNext)
  1676. {
  1677. pleNext = pleNode->Flink;
  1678. pBoundary = CONTAINING_RECORD(pleNode, BOUNDARY_ENTRY,
  1679. leBoundaryLink);
  1680. pScope = pBoundary->pScope;
  1681. bFound = FALSE;
  1682. for (j=0; j<dwNumBoundaries; j++)
  1683. {
  1684. if (pBoundaries[j].dwGroupAddress == pScope->ipGroupAddress
  1685. && pBoundaries[j].dwGroupMask == pScope->ipGroupMask )
  1686. {
  1687. bFound = TRUE;
  1688. break;
  1689. }
  1690. }
  1691. if (!bFound)
  1692. DeleteBoundaryFromInterface(pBoundary, pBoundaryIf);
  1693. }
  1694. }
  1695. ConvertIfTableToRanges(picb->dwIfIndex, &leNewRanges);
  1696. }
  1697. EXIT_LOCK(BOUNDARY_TABLE);
  1698. // Inform MGM of deltas
  1699. ProcessIfRangeDeltas(picb->dwIfIndex, &leOldRanges, &leNewRanges);
  1700. StartMZAP();
  1701. Trace0( MCAST, "LEFT SetBoundaryInfo" );
  1702. return NO_ERROR;
  1703. }
  1704. DWORD
  1705. GetMcastLimitInfo(
  1706. IN PICB picb,
  1707. OUT PRTR_TOC_ENTRY pToc,
  1708. IN OUT PDWORD pdwTocIndex,
  1709. OUT PBYTE pBuffer,
  1710. IN PRTR_INFO_BLOCK_HEADER pInfoHdr,
  1711. IN OUT PDWORD pdwBufferSize
  1712. )
  1713. /*++
  1714. Routine Description:
  1715. Called to get a copy of the limit information to write into the
  1716. registry.
  1717. Arguments:
  1718. picb Interface entry
  1719. pToc Space to fill in the TOC entry (may be NULL)
  1720. pdwTocIndex Pointer to TOC index to be incremented if TOC written
  1721. pBuffer Pointer to buffer into which info is to be written
  1722. pInfoHdr Pointer to info block header for offset computation
  1723. pdwBufferSize [IN] Size of the buffer pointed to by pBuffer
  1724. [OUT] Size of data copied out, or size of buffer needed
  1725. Called by:
  1726. GetInterfaceConfiguration() in info.c
  1727. Return Value:
  1728. NO_ERROR Buffer of size *pdwBufferSize was copied out
  1729. ERROR_INSUFFICIENT_BUFFER The buffer was too small to copy out the info
  1730. The size of buffer needed is in *pdwBufferSize
  1731. --*/
  1732. {
  1733. DWORD i, dwLen, dwSizeReqd, dwNumBoundaries;
  1734. PLIST_ENTRY pleNode;
  1735. PMIB_MCAST_LIMIT_ROW pLimit;
  1736. dwSizeReqd = 0;
  1737. dwNumBoundaries = 0;
  1738. if (picb->dwMcastTtl < 2 and picb->dwMcastRateLimit is 0)
  1739. {
  1740. // No block needed, since values are default
  1741. *pdwBufferSize = 0;
  1742. return NO_ERROR;
  1743. }
  1744. if (pdwTocIndex)
  1745. (*pdwTocIndex)++;
  1746. if (*pdwBufferSize < sizeof (MIB_MCAST_LIMIT_ROW))
  1747. {
  1748. *pdwBufferSize = sizeof(MIB_MCAST_LIMIT_ROW);
  1749. return ERROR_INSUFFICIENT_BUFFER;
  1750. }
  1751. if (pToc)
  1752. {
  1753. //pToc->InfoVersion = IP_MCAST_BOUNDARY_INFO;
  1754. pToc->InfoSize = sizeof(MIB_MCAST_LIMIT_ROW);
  1755. pToc->InfoType = IP_MCAST_LIMIT_INFO;
  1756. pToc->Count = 1;
  1757. pToc->Offset = (DWORD)(pBuffer - (PBYTE) pInfoHdr);
  1758. }
  1759. *pdwBufferSize = sizeof(MIB_MCAST_LIMIT_ROW);
  1760. pLimit = (PMIB_MCAST_LIMIT_ROW)pBuffer;
  1761. pLimit->dwTtl = picb->dwMcastTtl;
  1762. pLimit->dwRateLimit = picb->dwMcastRateLimit;
  1763. return NO_ERROR;
  1764. }
  1765. DWORD
  1766. GetBoundaryInfo(
  1767. IN PICB picb,
  1768. OUT PRTR_TOC_ENTRY pToc,
  1769. IN OUT PDWORD pdwTocIndex,
  1770. OUT PBYTE pBuffer,
  1771. IN PRTR_INFO_BLOCK_HEADER pInfoHdr,
  1772. IN OUT PDWORD pdwBufferSize
  1773. )
  1774. /*++
  1775. Routine Description:
  1776. Called to get a copy of the boundary information to write into the
  1777. registry.
  1778. Locks:
  1779. BOUNDARY_TABLE for reading
  1780. Arguments:
  1781. picb Interface entry
  1782. pToc Space to fill in the TOC entry (may be NULL)
  1783. pdwTocIndex Pointer to TOC index to be incremented if TOC written
  1784. pBuffer Pointer to buffer into which info is to be written
  1785. pInfoHdr Pointer to info block header for offset computation
  1786. pdwBufferSize [IN] Size of the buffer pointed to by pBuffer
  1787. [OUT] Size of data copied out, or size of buffer needed
  1788. Called by:
  1789. GetInterfaceConfiguration() in info.c
  1790. Return Value:
  1791. NO_ERROR Buffer of size *pdwBufferSize was copied out
  1792. ERROR_INSUFFICIENT_BUFFER The buffer was too small to copy out the info
  1793. The size of buffer needed is in *pdwBufferSize
  1794. --*/
  1795. {
  1796. DWORD i, dwLen, dwSizeReqd, dwNumBoundaries;
  1797. PLIST_ENTRY pleNode;
  1798. BOUNDARY_ENTRY *pBoundary;
  1799. MIB_BOUNDARYROW BoundaryRow;
  1800. BOUNDARY_IF *pIf;
  1801. dwSizeReqd = 0;
  1802. dwNumBoundaries = 0;
  1803. ENTER_READER(BOUNDARY_TABLE);
  1804. {
  1805. pIf = FindBIfEntry(picb->dwIfIndex);
  1806. if (!pIf)
  1807. {
  1808. *pdwBufferSize = 0;
  1809. EXIT_LOCK(BOUNDARY_TABLE);
  1810. return NO_ERROR;
  1811. }
  1812. //
  1813. // Calculate size required. We could have stored the count
  1814. // in the boundary entry, but we expect a pretty small number
  1815. // of boundaries (1 or 2) so use brute force for now.
  1816. //
  1817. for (pleNode = pIf->leBoundaryList.Flink;
  1818. pleNode isnot &pIf->leBoundaryList;
  1819. pleNode = pleNode->Flink)
  1820. {
  1821. dwNumBoundaries++;
  1822. }
  1823. dwSizeReqd += dwNumBoundaries * sizeof(MIB_BOUNDARYROW);
  1824. //
  1825. // Increment TOC index by number of TOC entries needed
  1826. //
  1827. if (pdwTocIndex && dwSizeReqd>0)
  1828. (*pdwTocIndex)++;
  1829. if (dwSizeReqd > *pdwBufferSize)
  1830. {
  1831. *pdwBufferSize = dwSizeReqd;
  1832. EXIT_LOCK(BOUNDARY_TABLE);
  1833. return ERROR_INSUFFICIENT_BUFFER;
  1834. }
  1835. *pdwBufferSize = dwSizeReqd;
  1836. if (pToc)
  1837. {
  1838. //pToc->InfoVersion = sizeof(MIB_BOUNDARYROW);
  1839. pToc->InfoSize = sizeof(MIB_BOUNDARYROW);
  1840. pToc->InfoType = IP_MCAST_BOUNDARY_INFO;
  1841. pToc->Count = dwNumBoundaries;
  1842. pToc->Offset = (DWORD)(pBuffer - (PBYTE) pInfoHdr);
  1843. }
  1844. // Go through and copy each boundary
  1845. for (pleNode = pIf->leBoundaryList.Flink;
  1846. pleNode isnot &pIf->leBoundaryList;
  1847. pleNode = pleNode->Flink)
  1848. {
  1849. pBoundary = CONTAINING_RECORD(pleNode, BOUNDARY_ENTRY,
  1850. leBoundaryLink);
  1851. BoundaryRow.dwGroupAddress = pBoundary->pScope->ipGroupAddress;
  1852. BoundaryRow.dwGroupMask = pBoundary->pScope->ipGroupMask;
  1853. CopyMemory(pBuffer, &BoundaryRow, sizeof(MIB_BOUNDARYROW));
  1854. pBuffer += sizeof(MIB_BOUNDARYROW);
  1855. }
  1856. }
  1857. EXIT_LOCK(BOUNDARY_TABLE);
  1858. return NO_ERROR;
  1859. }
  1860. //
  1861. // Functions used by SNMP
  1862. //
  1863. DWORD
  1864. SNMPDeleteScope(
  1865. IN IPV4_ADDRESS ipGroupAddress,
  1866. IN IPV4_ADDRESS ipGroupMask
  1867. )
  1868. /*++
  1869. Called by:
  1870. Locks:
  1871. BOUNDARY_TABLE for writing.
  1872. ICB_LIST and then PROTOCOL_CB_LIST for writing (for saving to registry).
  1873. Returns:
  1874. ERROR_INVALID_PARAMETER if trying to delete the local scope
  1875. whatever DeleteScope() returns
  1876. whatever ProcessSaveGlobalConfigInfo() returns
  1877. --*/
  1878. {
  1879. DWORD dwErr = NO_ERROR;
  1880. PSCOPE_ENTRY pScope;
  1881. BOOL bChanged = FALSE;
  1882. if ( IN_IPV4_LOCAL_SCOPE(ipGroupAddress) )
  1883. {
  1884. return ERROR_INVALID_PARAMETER;
  1885. }
  1886. ENTER_WRITER(BOUNDARY_TABLE);
  1887. {
  1888. pScope = FindScope( ipGroupAddress, ipGroupMask );
  1889. if (pScope)
  1890. {
  1891. dwErr = DeleteScope( pScope );
  1892. bChanged = TRUE;
  1893. }
  1894. }
  1895. EXIT_LOCK(BOUNDARY_TABLE);
  1896. // Resave the scopes to the registry
  1897. if (dwErr is NO_ERROR && bChanged)
  1898. {
  1899. // ProcessSaveGlobalConfigInfo() requires us to have both the
  1900. // ICB_LIST and the PROTOCOL_CB_LIST locked.
  1901. ENTER_WRITER(ICB_LIST);
  1902. ENTER_WRITER(PROTOCOL_CB_LIST);
  1903. dwErr = ProcessSaveGlobalConfigInfo();
  1904. EXIT_LOCK(PROTOCOL_CB_LIST);
  1905. EXIT_LOCK(ICB_LIST);
  1906. }
  1907. return dwErr;
  1908. }
  1909. DWORD
  1910. SNMPSetScope(
  1911. IN IPV4_ADDRESS ipGroupAddress,
  1912. IN IPV4_ADDRESS ipGroupMask,
  1913. IN SCOPE_NAME snScopeName
  1914. )
  1915. /*++
  1916. Called by:
  1917. AccessMcastScope() in access.c
  1918. Locks:
  1919. Locks BOUNDARY_TABLE for writing
  1920. Locks ICB_LIST then PROTOCOL_CB_LIST for writing (for saving to registry)
  1921. Returns:
  1922. whatever ProcessSaveGlobalConfigInfo() returns
  1923. --*/
  1924. {
  1925. DWORD dwErr;
  1926. PSCOPE_ENTRY pScope;
  1927. LANGID idLanguage = MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT);
  1928. ENTER_WRITER(BOUNDARY_TABLE);
  1929. {
  1930. pScope = FindScope( ipGroupAddress, ipGroupMask );
  1931. if ( ! pScope )
  1932. {
  1933. dwErr = ERROR_INVALID_PARAMETER;
  1934. }
  1935. else
  1936. {
  1937. dwErr = AssertScopeName( pScope, idLanguage, snScopeName );
  1938. }
  1939. }
  1940. EXIT_LOCK(BOUNDARY_TABLE);
  1941. // Save the scope to the registry
  1942. if (dwErr is NO_ERROR)
  1943. {
  1944. // ProcessSaveGlobalConfigInfo() requires us to have both the
  1945. // ICB_LIST and the PROTOCOL_CB_LIST locked.
  1946. ENTER_WRITER(ICB_LIST);
  1947. ENTER_WRITER(PROTOCOL_CB_LIST);
  1948. dwErr = ProcessSaveGlobalConfigInfo();
  1949. EXIT_LOCK(PROTOCOL_CB_LIST);
  1950. EXIT_LOCK(ICB_LIST);
  1951. }
  1952. return dwErr;
  1953. }
  1954. DWORD
  1955. SNMPAddScope(
  1956. IN IPV4_ADDRESS ipGroupAddress,
  1957. IN IPV4_ADDRESS ipGroupMask,
  1958. IN SCOPE_NAME snScopeName,
  1959. OUT PSCOPE_ENTRY *ppScope
  1960. )
  1961. /*++
  1962. Called by:
  1963. AccessMcastScope() in access.c
  1964. Locks:
  1965. Locks BOUNDARY_TABLE for writing
  1966. Locks ICB_LIST then PROTOCOL_CB_LIST for writing (for saving to registry)
  1967. Returns:
  1968. ERROR_INVALID_PARAMATER if already exists
  1969. whatever AddScope() returns
  1970. whatever ProcessSaveGlobalConfigInfo() returns
  1971. --*/
  1972. {
  1973. DWORD dwErr;
  1974. PSCOPE_ENTRY pScope;
  1975. LANGID idLanguage = MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT);
  1976. ENTER_WRITER(BOUNDARY_TABLE);
  1977. {
  1978. pScope = FindScope( ipGroupAddress, ipGroupMask );
  1979. if ( pScope )
  1980. {
  1981. dwErr = ERROR_INVALID_PARAMETER;
  1982. }
  1983. else
  1984. {
  1985. dwErr = AddScope( ipGroupAddress,
  1986. ipGroupMask,
  1987. ppScope );
  1988. if (dwErr is NO_ERROR)
  1989. dwErr = AssertScopeName( *ppScope, idLanguage, snScopeName );
  1990. }
  1991. }
  1992. EXIT_LOCK(BOUNDARY_TABLE);
  1993. // Save the scope to the registry
  1994. if (dwErr is NO_ERROR)
  1995. {
  1996. // ProcessSaveGlobalConfigInfo() requires us to have both the
  1997. // ICB_LIST and the PROTOCOL_CB_LIST locked.
  1998. ENTER_WRITER(ICB_LIST);
  1999. ENTER_WRITER(PROTOCOL_CB_LIST);
  2000. dwErr = ProcessSaveGlobalConfigInfo();
  2001. EXIT_LOCK(PROTOCOL_CB_LIST);
  2002. EXIT_LOCK(ICB_LIST);
  2003. }
  2004. return dwErr;
  2005. }
  2006. DWORD
  2007. SNMPAssertScope(
  2008. IN IPV4_ADDRESS ipGroupAddress,
  2009. IN IPV4_ADDRESS ipGroupMask,
  2010. IN PBYTE pScopeName, // string to duplicate
  2011. OUT PSCOPE_ENTRY *ppScopeEntry,
  2012. OUT PBOOL pbSaveGlobal
  2013. )
  2014. /*++
  2015. Locks:
  2016. Assumes caller holds write lock on BOUNDARY_TABLE.
  2017. Called by:
  2018. SNMPAddBoundaryToInterface()
  2019. Returns:
  2020. NO_ERROR - success
  2021. whatever AddScope() returns
  2022. --*/
  2023. {
  2024. DWORD dwErr = NO_ERROR;
  2025. SCOPE_NAME_BUFFER snScopeNameBuffer;
  2026. LANGID idLanguage;
  2027. if (pScopeName)
  2028. {
  2029. idLanguage = MAKELANGID( LANG_NEUTRAL, SUBLANG_SYS_DEFAULT );
  2030. MultiByteToWideChar( CP_UTF8,
  2031. 0,
  2032. pScopeName,
  2033. strlen(pScopeName),
  2034. snScopeNameBuffer,
  2035. MAX_SCOPE_NAME_LEN+1 );
  2036. }
  2037. *ppScopeEntry = FindScope(ipGroupAddress, ipGroupMask);
  2038. if (! *ppScopeEntry)
  2039. {
  2040. dwErr = AddScope( ipGroupAddress,
  2041. ipGroupMask,
  2042. ppScopeEntry);
  2043. if (pScopeName and (dwErr is NO_ERROR))
  2044. {
  2045. dwErr = AssertScopeName( *ppScopeEntry,
  2046. idLanguage,
  2047. snScopeNameBuffer );
  2048. }
  2049. *pbSaveGlobal = TRUE;
  2050. }
  2051. return dwErr;
  2052. }
  2053. DWORD
  2054. SNMPAddBoundaryToInterface(
  2055. IN DWORD dwIfIndex,
  2056. IN IPV4_ADDRESS ipGroupAddress,
  2057. IN IPV4_ADDRESS ipGroupMask
  2058. )
  2059. /*++
  2060. Routine Description:
  2061. Create a boundary if necessary, and add it to a given interface
  2062. and to the registry.
  2063. Called by:
  2064. AccessMcastBoundary() in access.c
  2065. Locks:
  2066. BOUNDARY_TABLE for writing
  2067. ICB_LIST and then PROTOCOL_CB_LIST for writing
  2068. Returns:
  2069. NO_ERROR
  2070. whatever AssertScope() returns
  2071. whatever AssertBifEntry() returns
  2072. whatever ProcessSaveInterfaceConfigInfo()
  2073. --*/
  2074. {
  2075. DWORD dwResult;
  2076. LIST_ENTRY leOldRanges,
  2077. leNewRanges;
  2078. BOOL bSaveGlobal = FALSE,
  2079. bIsOperational = TRUE;
  2080. BOUNDARY_ENTRY *pBoundary;
  2081. BOUNDARY_IF *pBIf;
  2082. SCOPE_ENTRY *pScope;
  2083. //
  2084. // bIsOperational should really be set to TRUE only if
  2085. // picb->dwOperationalState is IF_OPER_STATUS_OPERATIONAL
  2086. //
  2087. // Add the boundary
  2088. ENTER_WRITER(BOUNDARY_TABLE);
  2089. {
  2090. Trace0( MCAST, "SNMPAddBoundaryToInterface: converting old ranges" );
  2091. ConvertIfTableToRanges(dwIfIndex, &leOldRanges);
  2092. dwResult = SNMPAssertScope(ipGroupAddress, ipGroupMask, NULL, &pScope,
  2093. &bSaveGlobal);
  2094. if (dwResult == NO_ERROR)
  2095. {
  2096. dwResult = AssertBIfEntry(dwIfIndex, &pBIf, bIsOperational);
  2097. if (dwResult is NO_ERROR)
  2098. {
  2099. AssertBoundaryEntry(pBIf, pScope, &pBoundary);
  2100. }
  2101. }
  2102. if (dwResult isnot NO_ERROR)
  2103. {
  2104. EXIT_LOCK(BOUNDARY_TABLE);
  2105. return dwResult;
  2106. }
  2107. Trace0( MCAST, "SNMPAddBoundaryToInterface: converting new ranges" );
  2108. ConvertIfTableToRanges(dwIfIndex, &leNewRanges);
  2109. }
  2110. EXIT_LOCK(BOUNDARY_TABLE);
  2111. // Inform MGM of deltas
  2112. ProcessIfRangeDeltas(dwIfIndex, &leOldRanges, &leNewRanges);
  2113. // Save the boundary to the registry
  2114. {
  2115. // ProcessSaveInterfaceConfigInfo() requires us to have both the
  2116. // ICB_LIST and the PROTOCOL_CB_LIST locked.
  2117. ENTER_WRITER(ICB_LIST);
  2118. ENTER_WRITER(PROTOCOL_CB_LIST);
  2119. if (bSaveGlobal)
  2120. dwResult = ProcessSaveGlobalConfigInfo();
  2121. dwResult = ProcessSaveInterfaceConfigInfo(dwIfIndex);
  2122. EXIT_LOCK(PROTOCOL_CB_LIST);
  2123. EXIT_LOCK(ICB_LIST);
  2124. }
  2125. return dwResult;
  2126. }
  2127. DWORD
  2128. SNMPDeleteBoundaryFromInterface(
  2129. IN DWORD dwIfIndex,
  2130. IN IPV4_ADDRESS ipGroupAddress,
  2131. IN IPV4_ADDRESS ipGroupMask
  2132. )
  2133. /*++
  2134. Routine Description:
  2135. Remove a boundary from a given interface, and delete the scope
  2136. entry if it's unnamed and no interfaces remain.
  2137. Called by:
  2138. AccessMcastBoundary() in access.c
  2139. Locks:
  2140. BOUNDARY_TABLE for writing
  2141. Returns:
  2142. NO_ERROR
  2143. --*/
  2144. {
  2145. LIST_ENTRY leOldRanges,
  2146. leNewRanges,
  2147. *pleNode,
  2148. *pleNext;
  2149. DWORD dwResult = NO_ERROR;
  2150. BOOL bSaveGlobal = FALSE;
  2151. BOUNDARY_IF *pBIf;
  2152. BOUNDARY_ENTRY *pBoundary;
  2153. SCOPE_ENTRY *pScope;
  2154. ENTER_WRITER(BOUNDARY_TABLE);
  2155. {
  2156. Trace0( MCAST,
  2157. "SNMPDeleteBoundaryFromInterface: converting old ranges" );
  2158. ConvertIfTableToRanges(dwIfIndex, &leOldRanges);
  2159. //
  2160. // We have to do a little more work than just calling
  2161. // DeleteBoundaryFromInterface(), since we first have to
  2162. // look up which boundary matches.
  2163. //
  2164. pBIf = FindBIfEntry(dwIfIndex);
  2165. if (pBIf is NULL)
  2166. {
  2167. // nothing to do
  2168. FreeRangeList(&leOldRanges);
  2169. EXIT_LOCK(BOUNDARY_TABLE);
  2170. return NO_ERROR;
  2171. }
  2172. for (pleNode = pBIf->leBoundaryList.Flink;
  2173. pleNode isnot &pBIf->leBoundaryList;
  2174. pleNode = pleNext)
  2175. {
  2176. // Save ptr to next node, since we may delete this one
  2177. pleNext = pleNode->Flink;
  2178. pBoundary = CONTAINING_RECORD(pleNode, BOUNDARY_ENTRY,
  2179. leBoundaryLink);
  2180. pScope = pBoundary->pScope;
  2181. if (pScope->ipGroupAddress == ipGroupAddress
  2182. && pScope->ipGroupMask == ipGroupMask)
  2183. {
  2184. // Delete boundary from interface
  2185. DeleteBoundaryFromInterface(pBoundary, pBIf);
  2186. if (!pScope->ulNumInterfaces && IsListEmpty(&pScope->leNameList))
  2187. {
  2188. DeleteScope(pScope);
  2189. bSaveGlobal = TRUE;
  2190. }
  2191. }
  2192. }
  2193. Trace0( MCAST,
  2194. "SNMPDeleteBoundaryFromInterface: converting new ranges" );
  2195. ConvertIfTableToRanges(dwIfIndex, &leNewRanges);
  2196. }
  2197. EXIT_LOCK(BOUNDARY_TABLE);
  2198. // Inform MGM of deltas
  2199. ProcessIfRangeDeltas(dwIfIndex, &leOldRanges, &leNewRanges);
  2200. // Resave boundaries to registry
  2201. {
  2202. // ProcessSaveInterfaceConfigInfo() requires us to have both the
  2203. // ICB_LIST and the PROTOCOL_CB_LIST locked.
  2204. ENTER_WRITER(ICB_LIST);
  2205. ENTER_WRITER(PROTOCOL_CB_LIST);
  2206. if (bSaveGlobal)
  2207. dwResult = ProcessSaveGlobalConfigInfo();
  2208. dwResult = ProcessSaveInterfaceConfigInfo(dwIfIndex);
  2209. EXIT_LOCK(PROTOCOL_CB_LIST);
  2210. EXIT_LOCK(ICB_LIST);
  2211. }
  2212. return dwResult;
  2213. }
  2214. //
  2215. // Functions which can be called from MGM and Routing Protocols
  2216. //
  2217. BOOL
  2218. WINAPI
  2219. RmHasBoundary(
  2220. IN DWORD dwIfIndex,
  2221. IN IPV4_ADDRESS ipGroupAddress
  2222. )
  2223. /*++
  2224. Routine Description:
  2225. Test to see whether a boundary for the given group exists on the
  2226. indicated interface.
  2227. Called by:
  2228. (MGM, Routing Protocols)
  2229. Locks:
  2230. BOUNDARY_TABLE for reading
  2231. Returns:
  2232. TRUE, if a boundary exists
  2233. FALSE, if not
  2234. --*/
  2235. {
  2236. BOUNDARY_IF *pIf;
  2237. BOUNDARY_ENTRY *pBoundary;
  2238. PLIST_ENTRY pleNode;
  2239. BOOL bFound = FALSE;
  2240. ENTER_READER(BOUNDARY_TABLE);
  2241. {
  2242. pIf = FindBIfEntry(dwIfIndex);
  2243. if (pIf)
  2244. {
  2245. // An address in the IPv4 Local Scope has a boundary if
  2246. // ANY boundary exists.
  2247. if ( !IsListEmpty( &pIf->leBoundaryList )
  2248. && IN_IPV4_LOCAL_SCOPE(ipGroupAddress) )
  2249. bFound = TRUE;
  2250. for (pleNode = pIf->leBoundaryList.Flink;
  2251. !bFound && pleNode isnot &pIf->leBoundaryList;
  2252. pleNode = pleNode->Flink)
  2253. {
  2254. pBoundary = CONTAINING_RECORD(pleNode, BOUNDARY_ENTRY,
  2255. leBoundaryLink);
  2256. if ((ipGroupAddress & pBoundary->pScope->ipGroupMask)
  2257. == pBoundary->pScope->ipGroupAddress)
  2258. bFound = TRUE;
  2259. }
  2260. }
  2261. }
  2262. EXIT_LOCK(BOUNDARY_TABLE);
  2263. return bFound;
  2264. }
  2265. //----------------------------------------------------------------------------
  2266. // Boundary enumeration API.
  2267. //
  2268. //----------------------------------------------------------------------------
  2269. DWORD
  2270. RmGetBoundary(
  2271. IN PMIB_IPMCAST_BOUNDARY pimm,
  2272. IN OUT PDWORD pdwBufferSize,
  2273. IN OUT PBYTE pbBuffer
  2274. )
  2275. /*++
  2276. Called by:
  2277. AccessMcastBoundary() in access.c
  2278. Returns:
  2279. SNMP error code
  2280. --*/
  2281. {
  2282. DWORD dwErr = NO_ERROR;
  2283. BOUNDARY_IF *pBIf;
  2284. BOUNDARY_ENTRY *pBoundary;
  2285. SCOPE_ENTRY *pScope;
  2286. PMIB_IPMCAST_BOUNDARY *pOut;
  2287. Trace1( ENTER, "ENTERED RmGetBoundary: %d", *pdwBufferSize );
  2288. if (*pdwBufferSize < sizeof(MIB_IPMCAST_BOUNDARY)) {
  2289. *pdwBufferSize = sizeof(MIB_IPMCAST_BOUNDARY);
  2290. return ERROR_INSUFFICIENT_BUFFER;
  2291. }
  2292. do {
  2293. ENTER_READER(BOUNDARY_TABLE);
  2294. if ((pBIf = FindBIfEntry(pimm->dwIfIndex)) == NULL)
  2295. {
  2296. dwErr = ERROR_NOT_FOUND;
  2297. break;
  2298. }
  2299. if ( IN_IPV4_LOCAL_SCOPE(pimm->dwGroupAddress) )
  2300. {
  2301. dwErr = ERROR_NOT_FOUND;
  2302. break;
  2303. }
  2304. else
  2305. {
  2306. pScope = FindScope(pimm->dwGroupAddress, pimm->dwGroupMask);
  2307. if (pScope == NULL)
  2308. {
  2309. dwErr = ERROR_NOT_FOUND;
  2310. break;
  2311. }
  2312. if ((pBoundary = FindBoundaryEntry(pBIf, pScope)) == NULL)
  2313. {
  2314. dwErr = ERROR_NOT_FOUND;
  2315. break;
  2316. }
  2317. }
  2318. // Ok, we found it.
  2319. pimm->dwStatus = ROWSTATUS_ACTIVE;
  2320. CopyMemory(pbBuffer, pimm, sizeof(MIB_IPMCAST_BOUNDARY));
  2321. } while(0);
  2322. EXIT_LOCK(BOUNDARY_TABLE);
  2323. Trace1( ENTER, "LEAVING RmGetBoundary %x\n", dwErr );
  2324. return dwErr;
  2325. }
  2326. //----------------------------------------------------------------------------
  2327. // SCOPE enumeration API.
  2328. //
  2329. //----------------------------------------------------------------------------
  2330. DWORD
  2331. AddNextScope(
  2332. IN IPV4_ADDRESS ipAddr,
  2333. IN IPV4_ADDRESS ipMask,
  2334. IN SCOPE_NAME snScopeName,
  2335. IN PMIB_IPMCAST_SCOPE pimmStart,
  2336. IN OUT PDWORD pdwNumEntries,
  2337. IN OUT PDWORD pdwBufferSize,
  2338. IN OUT PBYTE *ppbBuffer)
  2339. /*++
  2340. Arguments:
  2341. pdwBufferSize: [IN] size of buffer
  2342. [OUT] extra space left, if NO_ERROR is returned
  2343. total size needed, if ERROR_INSUFFICIENT_BUFFER
  2344. --*/
  2345. {
  2346. //
  2347. // See whether this scope fits the requested criteria
  2348. //
  2349. if (ntohl(ipAddr) > ntohl(pimmStart->dwGroupAddress)
  2350. || ( ipAddr == pimmStart->dwGroupAddress
  2351. && ntohl(ipMask) >= ntohl(pimmStart->dwGroupMask)))
  2352. {
  2353. MIB_IPMCAST_SCOPE imm;
  2354. //
  2355. // Make sure enough space is left in the buffer
  2356. //
  2357. if (*pdwBufferSize < sizeof(MIB_IPMCAST_SCOPE))
  2358. {
  2359. if (*pdwNumEntries == 0)
  2360. *pdwBufferSize = sizeof(MIB_IPMCAST_SCOPE);
  2361. return ERROR_INSUFFICIENT_BUFFER;
  2362. }
  2363. //
  2364. // Copy scope into buffer
  2365. //
  2366. imm.dwGroupAddress = ipAddr;
  2367. imm.dwGroupMask = ipMask;
  2368. sn_strcpy(imm.snNameBuffer, snScopeName);
  2369. imm.dwStatus = ROWSTATUS_ACTIVE;
  2370. CopyMemory(*ppbBuffer, &imm, sizeof(MIB_IPMCAST_SCOPE));
  2371. (*ppbBuffer) += sizeof(MIB_IPMCAST_SCOPE);
  2372. (*pdwBufferSize) -= sizeof(MIB_IPMCAST_SCOPE);
  2373. (*pdwNumEntries)++;
  2374. }
  2375. return NO_ERROR;
  2376. }
  2377. DWORD
  2378. RmGetNextScope(
  2379. IN PMIB_IPMCAST_SCOPE pimmStart,
  2380. IN OUT PDWORD pdwBufferSize,
  2381. IN OUT PBYTE pbBuffer,
  2382. IN OUT PDWORD pdwNumEntries
  2383. )
  2384. /*++
  2385. Locks:
  2386. BOUNDARY_TABLE for reading
  2387. Called by:
  2388. RmGetFirstScope(),
  2389. AccessMcastScope() in access.c
  2390. --*/
  2391. {
  2392. DWORD dwErr = NO_ERROR;
  2393. DWORD dwNumEntries=0, dwBufferSize = *pdwBufferSize;
  2394. SCOPE_ENTRY *pScope, local;
  2395. DWORD dwInd;
  2396. BOOL bHaveScopes = FALSE;
  2397. PLIST_ENTRY pleNode;
  2398. Trace1( MCAST, "ENTERED RmGetNextScope: %d", dwBufferSize);
  2399. // Bump index by 1
  2400. pimmStart->dwGroupMask = htonl( ntohl(pimmStart->dwGroupMask) + 1);
  2401. if (!pimmStart->dwGroupMask)
  2402. {
  2403. pimmStart->dwGroupAddress = htonl( ntohl(pimmStart->dwGroupAddress) + 1);
  2404. }
  2405. ENTER_READER(BOUNDARY_TABLE);
  2406. {
  2407. // Walk master scope list
  2408. for (pleNode = g_MasterScopeList.Flink;
  2409. dwNumEntries < *pdwNumEntries && pleNode isnot &g_MasterScopeList;
  2410. pleNode = pleNode->Flink) {
  2411. pScope = CONTAINING_RECORD(pleNode, SCOPE_ENTRY, leScopeLink);
  2412. if ( !pScope->ipGroupAddress )
  2413. continue;
  2414. bHaveScopes = TRUE;
  2415. dwErr = AddNextScope(pScope->ipGroupAddress,
  2416. pScope->ipGroupMask,
  2417. GetDefaultName( pScope ),
  2418. pimmStart,
  2419. &dwNumEntries,
  2420. &dwBufferSize,
  2421. &pbBuffer);
  2422. if (dwErr == ERROR_INSUFFICIENT_BUFFER)
  2423. {
  2424. *pdwBufferSize = dwBufferSize;
  2425. return dwErr;
  2426. }
  2427. }
  2428. //
  2429. // Finally, if we have scopes, then we can also count
  2430. // one for the IPv4 Local Scope.
  2431. //
  2432. if ( dwNumEntries > 0 && dwNumEntries < *pdwNumEntries && bHaveScopes )
  2433. {
  2434. dwErr = AddNextScope( IPV4_LOCAL_SCOPE_ADDR,
  2435. IPV4_LOCAL_SCOPE_MASK,
  2436. IPV4_LOCAL_SCOPE_NAME,
  2437. pimmStart,
  2438. &dwNumEntries,
  2439. &dwBufferSize,
  2440. &pbBuffer );
  2441. }
  2442. if (!dwNumEntries && dwErr==NO_ERROR)
  2443. dwErr = ERROR_NO_MORE_ITEMS;
  2444. }
  2445. EXIT_LOCK(BOUNDARY_TABLE);
  2446. *pdwBufferSize -= dwBufferSize;
  2447. *pdwNumEntries = dwNumEntries;
  2448. Trace1( MCAST, "LEAVING RmGetNextScope %x", dwErr );
  2449. return dwErr;
  2450. }
  2451. DWORD
  2452. RmGetScope(
  2453. IN PMIB_IPMCAST_SCOPE pimm,
  2454. IN OUT PDWORD pdwBufferSize,
  2455. IN OUT PBYTE pbBuffer
  2456. )
  2457. /*++
  2458. Called by:
  2459. AccessMcastScope() in access.c
  2460. Returns:
  2461. SNMP error code
  2462. --*/
  2463. {
  2464. DWORD dwErr = NO_ERROR;
  2465. SCOPE_ENTRY *pScope;
  2466. PMIB_IPMCAST_SCOPE *pOut;
  2467. Trace1( ENTER, "ENTERED RmGetScope: %d", *pdwBufferSize );
  2468. if (*pdwBufferSize < sizeof(MIB_IPMCAST_SCOPE)) {
  2469. *pdwBufferSize = sizeof(MIB_IPMCAST_SCOPE);
  2470. return ERROR_INSUFFICIENT_BUFFER;
  2471. }
  2472. pimm->dwStatus = ROWSTATUS_ACTIVE;
  2473. ENTER_READER(BOUNDARY_TABLE);
  2474. do {
  2475. if ( pimm->dwGroupAddress == IPV4_LOCAL_SCOPE_ADDR
  2476. && pimm->dwGroupMask == IPV4_LOCAL_SCOPE_MASK )
  2477. {
  2478. sn_strcpy( pimm->snNameBuffer, IPV4_LOCAL_SCOPE_NAME );
  2479. CopyMemory(pbBuffer, pimm, sizeof(MIB_IPMCAST_SCOPE));
  2480. }
  2481. else
  2482. {
  2483. pScope = FindScope(pimm->dwGroupAddress, pimm->dwGroupMask);
  2484. if (pScope == NULL)
  2485. {
  2486. dwErr = ERROR_NOT_FOUND;
  2487. break;
  2488. }
  2489. // Ok, we found it.
  2490. CopyMemory(pbBuffer, pimm, sizeof(MIB_IPMCAST_SCOPE));
  2491. }
  2492. } while(0);
  2493. EXIT_LOCK(BOUNDARY_TABLE);
  2494. Trace1( ENTER, "LEAVING RmGetScope %x\n", dwErr );
  2495. return dwErr;
  2496. }
  2497. DWORD
  2498. RmGetFirstScope(
  2499. IN OUT PDWORD pdwBufferSize,
  2500. IN OUT PBYTE pbBuffer,
  2501. IN OUT PDWORD pdwNumEntries
  2502. )
  2503. /*++
  2504. Routine description:
  2505. Get the first scope in lexicographic order. Since Addr=0
  2506. is not used, a GetFirst is equivalent to a GetNext with Addr=0.
  2507. Called by:
  2508. AccessMcastScope() in access.c
  2509. --*/
  2510. {
  2511. MIB_IPMCAST_SCOPE imm;
  2512. imm.dwGroupAddress = imm.dwGroupMask = 0;
  2513. return RmGetNextScope(&imm, pdwBufferSize, pbBuffer, pdwNumEntries);
  2514. }
  2515. //----------------------------------------------------------------------------
  2516. // BOUNDARY enumeration API.
  2517. //
  2518. //----------------------------------------------------------------------------
  2519. DWORD
  2520. AddNextBoundary(
  2521. IN DWORD dwIfIndex,
  2522. IN IPV4_ADDRESS ipAddr,
  2523. IN IPV4_ADDRESS ipMask,
  2524. IN PMIB_IPMCAST_BOUNDARY pimmStart,
  2525. IN OUT PDWORD pdwNumEntries,
  2526. IN OUT PDWORD pdwBufferSize,
  2527. IN OUT PBYTE *ppbBuffer)
  2528. /*++
  2529. Arguments:
  2530. pdwBufferSize: [IN] size of buffer
  2531. [OUT] extra space left, if NO_ERROR is returned
  2532. total size needed, if ERROR_INSUFFICIENT_BUFFER
  2533. --*/
  2534. {
  2535. //
  2536. // See whether this boundary fits the requested criteria
  2537. //
  2538. if (ntohl(ipAddr) > ntohl(pimmStart->dwGroupAddress)
  2539. || ( ipAddr == pimmStart->dwGroupAddress
  2540. && ntohl(ipMask) >= ntohl(pimmStart->dwGroupMask)))
  2541. {
  2542. MIB_IPMCAST_BOUNDARY imm;
  2543. //
  2544. // Make sure enough space is left in the buffer
  2545. //
  2546. if (*pdwBufferSize < sizeof(MIB_IPMCAST_BOUNDARY))
  2547. {
  2548. if (*pdwNumEntries == 0)
  2549. *pdwBufferSize = sizeof(MIB_IPMCAST_BOUNDARY);
  2550. return ERROR_INSUFFICIENT_BUFFER;
  2551. }
  2552. //
  2553. // Copy boundary into buffer
  2554. //
  2555. imm.dwIfIndex = dwIfIndex;
  2556. imm.dwGroupAddress = ipAddr;
  2557. imm.dwGroupMask = ipMask;
  2558. imm.dwStatus = ROWSTATUS_ACTIVE;
  2559. CopyMemory(*ppbBuffer, &imm, sizeof(MIB_IPMCAST_BOUNDARY));
  2560. (*ppbBuffer) += sizeof(MIB_IPMCAST_BOUNDARY);
  2561. (*pdwBufferSize) -= sizeof(MIB_IPMCAST_BOUNDARY);
  2562. (*pdwNumEntries)++;
  2563. }
  2564. return NO_ERROR;
  2565. }
  2566. DWORD
  2567. RmGetNextBoundary(
  2568. IN PMIB_IPMCAST_BOUNDARY pimmStart,
  2569. IN OUT PDWORD pdwBufferSize,
  2570. IN OUT PBYTE pbBuffer,
  2571. IN OUT PDWORD pdwNumEntries
  2572. )
  2573. /*++
  2574. Locks:
  2575. BOUNDARY_TABLE for reading
  2576. Called by:
  2577. RmGetFirstBoundary(),
  2578. AccessMcastBoundary() in access.c
  2579. --*/
  2580. {
  2581. DWORD dwErr = NO_ERROR;
  2582. PLIST_ENTRY pleIf, pleBound;
  2583. DWORD dwNumEntries=0, dwBufferSize = *pdwBufferSize;
  2584. BOUNDARY_ENTRY *pBound, local;
  2585. Trace1( MCAST, "ENTERED RmGetNextBoundary: %d", dwBufferSize);
  2586. // Bump index by 1
  2587. pimmStart->dwGroupMask = htonl( ntohl(pimmStart->dwGroupMask) + 1);
  2588. if (!pimmStart->dwGroupMask)
  2589. {
  2590. pimmStart->dwGroupAddress = htonl( ntohl(pimmStart->dwGroupAddress) + 1);
  2591. if (!pimmStart->dwGroupAddress)
  2592. pimmStart->dwIfIndex++;
  2593. }
  2594. ENTER_READER(BOUNDARY_TABLE);
  2595. {
  2596. // Walk master BOUNDARY_IF list
  2597. for (pleIf = g_MasterInterfaceList.Flink;
  2598. dwErr == NO_ERROR && dwNumEntries < *pdwNumEntries
  2599. && pleIf isnot &g_MasterInterfaceList;
  2600. pleIf = pleIf->Flink)
  2601. {
  2602. BOUNDARY_IF *pBIf = CONTAINING_RECORD(pleIf, BOUNDARY_IF,
  2603. leBoundaryIfMasterLink);
  2604. if (pBIf->dwIfIndex >= pimmStart->dwIfIndex)
  2605. {
  2606. // Walk BOUNDARY list
  2607. for (pleBound = pBIf->leBoundaryList.Flink;
  2608. dwErr == NO_ERROR && dwNumEntries < *pdwNumEntries
  2609. && pleBound isnot &pBIf->leBoundaryList;
  2610. pleBound = pleBound->Flink)
  2611. {
  2612. pBound = CONTAINING_RECORD(pleBound,
  2613. BOUNDARY_ENTRY, leBoundaryLink);
  2614. dwErr = AddNextBoundary(pBIf->dwIfIndex,
  2615. pBound->pScope->ipGroupAddress,
  2616. pBound->pScope->ipGroupMask,
  2617. pimmStart,
  2618. &dwNumEntries,
  2619. &dwBufferSize,
  2620. &pbBuffer);
  2621. }
  2622. //
  2623. // Finally, if we have boundaries, then we can also count
  2624. // one for the IPv4 Local Scope.
  2625. //
  2626. if (dwErr == NO_ERROR && dwNumEntries < *pdwNumEntries
  2627. && !IsListEmpty( &pBIf->leBoundaryList ) )
  2628. {
  2629. dwErr = AddNextBoundary(pBIf->dwIfIndex,
  2630. IPV4_LOCAL_SCOPE_ADDR,
  2631. IPV4_LOCAL_SCOPE_MASK,
  2632. pimmStart,
  2633. &dwNumEntries,
  2634. &dwBufferSize,
  2635. &pbBuffer);
  2636. }
  2637. if (dwErr == ERROR_INSUFFICIENT_BUFFER)
  2638. {
  2639. *pdwBufferSize = dwBufferSize;
  2640. return dwErr;
  2641. }
  2642. }
  2643. }
  2644. if (!dwNumEntries && dwErr==NO_ERROR)
  2645. dwErr = ERROR_NO_MORE_ITEMS;
  2646. }
  2647. EXIT_LOCK(BOUNDARY_TABLE);
  2648. *pdwBufferSize -= dwBufferSize;
  2649. *pdwNumEntries = dwNumEntries;
  2650. Trace1( MCAST, "LEAVING RmGetNextBoundary %x\n", dwErr );
  2651. return dwErr;
  2652. }
  2653. DWORD
  2654. RmGetFirstBoundary(
  2655. IN OUT PDWORD pdwBufferSize,
  2656. IN OUT PBYTE pbBuffer,
  2657. IN OUT PDWORD pdwNumEntries
  2658. )
  2659. /*++
  2660. Routine description:
  2661. Get the first boundary in lexicographic order. Since IfIndex=0
  2662. is not used, a GetFirst is equivalent to a GetNext with IfIndex=0.
  2663. Called by:
  2664. AccessMcastBoundary() in access.c
  2665. --*/
  2666. {
  2667. MIB_IPMCAST_BOUNDARY imm;
  2668. imm.dwIfIndex = imm.dwGroupAddress = imm.dwGroupMask = 0;
  2669. return RmGetNextBoundary(&imm, pdwBufferSize, pbBuffer, pdwNumEntries);
  2670. }
  2671. void
  2672. InitializeBoundaryTable()
  2673. /*++
  2674. Locks:
  2675. BOUNDARY_TABLE for writing
  2676. --*/
  2677. {
  2678. register int i;
  2679. ENTER_WRITER(BOUNDARY_TABLE);
  2680. {
  2681. for (i=0; i<BOUNDARY_HASH_TABLE_SIZE; i++)
  2682. InitializeListHead(&g_bbScopeTable[i].leInterfaceList);
  2683. InitializeListHead(&g_MasterInterfaceList);
  2684. InitializeListHead(&g_MasterScopeList);
  2685. ZeroMemory( g_scopeEntry, MAX_SCOPES * sizeof(SCOPE_ENTRY) );
  2686. }
  2687. EXIT_LOCK(BOUNDARY_TABLE);
  2688. }
  2689. //////////////////////////////////////////////////////////////////////////////
  2690. // START OF MZAP ROUTINES
  2691. //////////////////////////////////////////////////////////////////////////////
  2692. // Notes on MZAP write lock dependencies:
  2693. // ZAM_CACHE - no dependencies
  2694. // MZAP_TIMER - no dependencies
  2695. // ZBR_LIST - lock BOUNDARY_ENTRY and MZAP_TIMER before ZBR_LIST
  2696. // ZLE_LIST - lock MZAP_TIMER before ZLE_LIST
  2697. #define TOP_OF_SCOPE(pScope) \
  2698. ((pScope)->ipGroupAddress | ~(pScope)->ipGroupMask)
  2699. // Convert number of seconds to number of 100ns intervals
  2700. #define TM_SECONDS(x) ((x)*10000000)
  2701. //
  2702. // Define this if/when authentication of MZAP messages is provided
  2703. //
  2704. #undef SECURE_MZAP
  2705. //
  2706. // Address used as Message Origin for locally-originated messages
  2707. //
  2708. IPV4_ADDRESS g_ipMyAddress = INADDR_ANY;
  2709. IPV4_ADDRESS g_ipMyLocalZoneID = INADDR_ANY;
  2710. SOCKET g_mzapLocalSocket = INVALID_SOCKET;
  2711. LIST_ENTRY g_zbrTimerList;
  2712. LIST_ENTRY g_zleTimerList;
  2713. BOOL g_bMzapStarted = FALSE;
  2714. HANDLE g_hMzapSocketEvent = NULL;
  2715. // For now, originate all ZAMs and ZCMs at the same time.
  2716. LARGE_INTEGER g_liZamExpiryTime;
  2717. DWORD
  2718. UpdateMzapTimer();
  2719. #include <packon.h>
  2720. typedef struct _IPV4_MZAP_HEADER {
  2721. BYTE byVersion;
  2722. BYTE byBPType;
  2723. BYTE byAddressFamily;
  2724. BYTE byNameCount;
  2725. IPV4_ADDRESS ipMessageOrigin;
  2726. IPV4_ADDRESS ipScopeZoneID;
  2727. IPV4_ADDRESS ipScopeStart;
  2728. IPV4_ADDRESS ipScopeEnd;
  2729. BYTE pScopeNameBlock[0];
  2730. } IPV4_MZAP_HEADER, *PIPV4_MZAP_HEADER;
  2731. typedef struct _IPV4_ZAM_HEADER {
  2732. BYTE bZT;
  2733. BYTE bZTL;
  2734. WORD wHoldTime;
  2735. IPV4_ADDRESS ipAddress[1];
  2736. } IPV4_ZAM_HEADER, *PIPV4_ZAM_HEADER;
  2737. typedef struct _IPV4_ZCM_HEADER {
  2738. BYTE bZNUM;
  2739. BYTE bReserved;
  2740. WORD wHoldTime;
  2741. IPV4_ADDRESS ipZBR[0];
  2742. } IPV4_ZCM_HEADER, *PIPV4_ZCM_HEADER;
  2743. #include <packoff.h>
  2744. //////////////////////////////////////////////////////////////////////////////
  2745. // Functions for ZBR neighbor list and Zone ID maintenance
  2746. //////////////////////////////////////////////////////////////////////////////
  2747. ZBR_ENTRY *
  2748. FindZBR(
  2749. IN PSCOPE_ENTRY pScope,
  2750. IN IPV4_ADDRESS ipAddress
  2751. )
  2752. /*++
  2753. Description:
  2754. Finds a given ZBR in a list.
  2755. Arguments:
  2756. IN pscope - scope to find a ZBR associated with
  2757. IN ipAddress - address of ZBR to find
  2758. Returns:
  2759. Pointer to ZBR entry, or NULL if not found
  2760. Called by:
  2761. AssertZBR()
  2762. Locks:
  2763. Assumes caller holds read lock on BOUNDARY_ENTRY and ZBR_LIST
  2764. --*/
  2765. {
  2766. PZBR_ENTRY pZbr;
  2767. PLIST_ENTRY pleNode;
  2768. for (pleNode = pScope->leZBRList.Flink;
  2769. pleNode isnot &pScope->leZBRList;
  2770. pleNode = pleNode->Flink)
  2771. {
  2772. pZbr = CONTAINING_RECORD(pleNode, ZBR_ENTRY, leZBRLink);
  2773. if (pZbr->ipAddress == ipAddress)
  2774. {
  2775. return pZbr;
  2776. }
  2777. }
  2778. return NULL;
  2779. }
  2780. IPV4_ADDRESS
  2781. MyScopeZoneID(
  2782. IN PSCOPE_ENTRY pScope
  2783. )
  2784. /*++
  2785. Description:
  2786. Get the Zone ID which we're inside for a given scope
  2787. Arguments:
  2788. IN pScope - scope to get the zone ID for
  2789. Returns:
  2790. scope zone address
  2791. Called by:
  2792. AddMZAPHeader(), HandleZAM()
  2793. Locks:
  2794. Assumes caller holds read lock on BOUNDARY_TABLE
  2795. so that pScope won't go away.
  2796. --*/
  2797. {
  2798. PLIST_ENTRY pleNode;
  2799. IPV4_ADDRESS ipScopeZoneID = g_ipMyAddress;
  2800. // If first ZBR has a lower IP address than us, use that.
  2801. pleNode = pScope->leZBRList.Flink;
  2802. if (pleNode isnot &pScope->leZBRList)
  2803. {
  2804. ZBR_ENTRY *pZbr = CONTAINING_RECORD(pleNode, ZBR_ENTRY, leZBRLink);
  2805. if (ntohl(pZbr->ipAddress) < ntohl(ipScopeZoneID))
  2806. ipScopeZoneID = pZbr->ipAddress;
  2807. }
  2808. return ipScopeZoneID;
  2809. }
  2810. VOID
  2811. SetZbrExpiryTime(
  2812. PZBR_ENTRY pZbr,
  2813. LARGE_INTEGER liExpiryTime
  2814. )
  2815. {
  2816. PLIST_ENTRY pleNode;
  2817. pZbr->liExpiryTime = liExpiryTime;
  2818. for (pleNode = g_zbrTimerList.Flink;
  2819. pleNode isnot &g_zbrTimerList;
  2820. pleNode = pleNode->Flink)
  2821. {
  2822. ZBR_ENTRY *pPrev = CONTAINING_RECORD(pleNode, ZBR_ENTRY, leTimerLink);
  2823. if (RtlLargeIntegerGreaterThan(pPrev->liExpiryTime, liExpiryTime))
  2824. break;
  2825. }
  2826. InsertTailList( pleNode, &pZbr->leTimerLink );
  2827. }
  2828. ZBR_ENTRY *
  2829. AddZBR(
  2830. IN PSCOPE_ENTRY pScope,
  2831. IN IPV4_ADDRESS ipAddress,
  2832. IN LARGE_INTEGER liExpiryTime
  2833. )
  2834. /*++
  2835. Description:
  2836. Adds ZBR to scope's list. Initializes timer, and updates Zone ID.
  2837. Arguments:
  2838. IN pScope - scope to add a boundary router of
  2839. IN ipAddress - address of the boundary router to add
  2840. IN liExpiryTime - time at which to expire the boundary router entry
  2841. Returns:
  2842. Pointer to new boundary router entry, or NULL on memory alloc error
  2843. Called by:
  2844. AssertZBR()
  2845. Locks:
  2846. Assumes caller holds write lock on BOUNDARY_ENTRY, MZAP_TIMER, and ZBR_LIST
  2847. --*/
  2848. {
  2849. PZBR_ENTRY pZbr;
  2850. PLIST_ENTRY pleNode;
  2851. // Initialize new ZBR entry
  2852. pZbr = MALLOC( sizeof(ZBR_ENTRY) );
  2853. if (!pZbr)
  2854. {
  2855. return NULL;
  2856. }
  2857. pZbr->ipAddress = ipAddress;
  2858. // Add ZBR to list in order of lowest IP address
  2859. for (pleNode = pScope->leZBRList.Flink;
  2860. pleNode isnot &pScope->leZBRList;
  2861. pleNode = pleNode->Flink)
  2862. {
  2863. ZBR_ENTRY *pPrev = CONTAINING_RECORD(pleNode, ZBR_ENTRY, leZBRLink);
  2864. if (ntohl(pPrev->ipAddress) > ntohl(ipAddress))
  2865. {
  2866. break;
  2867. }
  2868. }
  2869. InsertTailList( pleNode, &pZbr->leZBRLink );
  2870. // We don't need to update Zone ID since it's recalculated
  2871. // whenever we need it.
  2872. // Add ZBR to timer list in order of expiry time
  2873. SetZbrExpiryTime( pZbr, liExpiryTime );
  2874. UpdateMzapTimer();
  2875. return pZbr;
  2876. }
  2877. ZBR_ENTRY *
  2878. AssertZBR(
  2879. IN PSCOPE_ENTRY pScope,
  2880. IN IPV4_ADDRESS ipAddress,
  2881. IN WORD wHoldTime
  2882. )
  2883. /*++
  2884. Description:
  2885. Finds ZBR in list, adding it if needed. Resets timer for ZBR.
  2886. Arguments:
  2887. IN pScope - scope to find/add a boundary router of
  2888. IN ipAddress - address of boundary router to find/add
  2889. IN wHoldTime - hold time in seconds remaining to reset timer to
  2890. Returns:
  2891. Pointer to boundary router entry
  2892. Called by:
  2893. HandleZAM(), HandleZCM()
  2894. Locks:
  2895. Assumes caller holds read lock on BOUNDARY_ENTRY
  2896. Locks MZAP_TIMER and then ZBR_LIST for writing
  2897. --*/
  2898. {
  2899. LARGE_INTEGER liCurrentTime, liExpiryTime;
  2900. ZBR_ENTRY *pZbr;
  2901. NtQuerySystemTime( &liCurrentTime );
  2902. liExpiryTime = RtlLargeIntegerAdd(liCurrentTime,
  2903. RtlConvertUlongToLargeInteger(TM_SECONDS((ULONG)wHoldTime)));
  2904. ENTER_WRITER(MZAP_TIMER);
  2905. ENTER_WRITER(ZBR_LIST);
  2906. {
  2907. pZbr = FindZBR( pScope, ipAddress );
  2908. if (!pZbr)
  2909. {
  2910. pZbr = AddZBR( pScope, ipAddress, liExpiryTime );
  2911. }
  2912. else
  2913. {
  2914. RemoveEntryList( &pZbr->leTimerLink );
  2915. SetZbrExpiryTime( pZbr, liExpiryTime );
  2916. }
  2917. }
  2918. EXIT_LOCK(ZBR_LIST);
  2919. EXIT_LOCK(MZAP_TIMER);
  2920. return pZbr;
  2921. }
  2922. VOID
  2923. DeleteZBR(
  2924. IN PZBR_ENTRY pZbr
  2925. )
  2926. /*++
  2927. Arguments:
  2928. IN pZbr - Pointer to boundary router entry to delete
  2929. Called by:
  2930. HandleMzapTimer()
  2931. Locks:
  2932. Assumes caller has write lock on ZBR_LIST
  2933. --*/
  2934. {
  2935. // Remove from timer list
  2936. RemoveEntryList( &pZbr->leTimerLink );
  2937. // Remove from ZBR list for the scope
  2938. RemoveEntryList( &pZbr->leZBRLink );
  2939. // We don't need to update the Zone ID, since it's recalculated
  2940. // whenever we need it
  2941. }
  2942. //////////////////////////////////////////////////////////////////////////////
  2943. // Functions for pending ZLE store manipulation
  2944. //////////////////////////////////////////////////////////////////////////////
  2945. typedef struct _ZLE_PENDING {
  2946. LIST_ENTRY leTimerLink;
  2947. PBYTE pBuffer;
  2948. ULONG ulBuffLen;
  2949. LARGE_INTEGER liExpiryTime;
  2950. } ZLE_PENDING, *PZLE_PENDING;
  2951. LIST_ENTRY g_leZleList;
  2952. PZLE_PENDING
  2953. AddPendingZLE(
  2954. IN PBYTE pBuffer,
  2955. IN ULONG ulBuffLen,
  2956. IN LARGE_INTEGER liExpiryTime
  2957. )
  2958. /*++
  2959. Arguments:
  2960. IN pBuffer - buffer holding ZLE message
  2961. IN ulBuffLen - size in bytes of buffer passed in
  2962. IN liExpiryTime - time at which to expire ZLE entry
  2963. Returns:
  2964. Pointer to ZLE entry added, or NULL on memory alloc error
  2965. Called by:
  2966. HandleZAM()
  2967. Locks:
  2968. Assumes caller holds write lock on ZLE_LIST
  2969. --*/
  2970. {
  2971. PLIST_ENTRY pleNode;
  2972. PZLE_PENDING pZle;
  2973. pZle = MALLOC( sizeof(ZLE_PENDING) );
  2974. if (!pZle)
  2975. {
  2976. return NULL;
  2977. }
  2978. pZle->pBuffer = pBuffer;
  2979. pZle->ulBuffLen = ulBuffLen;
  2980. pZle->liExpiryTime = liExpiryTime;
  2981. // Search for entry after the new one
  2982. for (pleNode = g_leZleList.Flink;
  2983. pleNode isnot &g_leZleList;
  2984. pleNode = pleNode->Flink)
  2985. {
  2986. PZLE_PENDING pPrev = CONTAINING_RECORD(pleNode,ZLE_PENDING,leTimerLink);
  2987. if (RtlLargeIntegerGreaterThan(pPrev->liExpiryTime,
  2988. pZle->liExpiryTime))
  2989. {
  2990. break;
  2991. }
  2992. }
  2993. // Insert into cache
  2994. InsertTailList( pleNode, &pZle->leTimerLink );
  2995. return pZle;
  2996. }
  2997. VOID
  2998. DeletePendingZLE(
  2999. IN PZLE_PENDING zle
  3000. )
  3001. /*++
  3002. Description:
  3003. Remove all state related to a pending ZLE
  3004. Arguments:
  3005. IN zle - pointer to ZLE entry to delete
  3006. Called by:
  3007. HandleZLE(), SendZLE()
  3008. Locks:
  3009. Assumes caller holds write lock on ZLE_LIST
  3010. --*/
  3011. {
  3012. RemoveEntryList( &zle->leTimerLink );
  3013. // Free up space
  3014. FREE(zle->pBuffer);
  3015. FREE(zle);
  3016. }
  3017. PZLE_PENDING
  3018. FindPendingZLE(
  3019. IN IPV4_MZAP_HEADER *mh
  3020. )
  3021. /*++
  3022. Description:
  3023. Find an entry for a pending ZLE which matches a given MZAP message header
  3024. Arguments:
  3025. IN mh - pointer to MZAP message header to locate a matching ZLE entry for
  3026. Returns:
  3027. Pointer to matching ZLE entry, if any
  3028. Called by:
  3029. HandleZAM(), HandleZLE()
  3030. Locks:
  3031. Assumes caller holds read lock on ZLE_LIST
  3032. --*/
  3033. {
  3034. PLIST_ENTRY pleNode;
  3035. IPV4_MZAP_HEADER *mh2;
  3036. for (pleNode = g_leZleList.Flink;
  3037. pleNode isnot &g_leZleList;
  3038. pleNode = pleNode->Flink)
  3039. {
  3040. PZLE_PENDING zle = CONTAINING_RECORD(pleNode, ZLE_PENDING, leTimerLink);
  3041. mh2 = (PIPV4_MZAP_HEADER)zle->pBuffer;
  3042. if (mh->ipScopeZoneID == mh2->ipScopeZoneID
  3043. && mh->ipScopeStart == mh2->ipScopeStart)
  3044. {
  3045. return zle;
  3046. }
  3047. }
  3048. return NULL;
  3049. }
  3050. //////////////////////////////////////////////////////////////////////////////
  3051. // Functions for ZAM cache manipulation
  3052. //////////////////////////////////////////////////////////////////////////////
  3053. typedef struct _ZAM_ENTRY {
  3054. LIST_ENTRY leCacheLink;
  3055. IPV4_ADDRESS ipScopeZoneID;
  3056. IPV4_ADDRESS ipStartAddress;
  3057. LARGE_INTEGER liExpiryTime;
  3058. } ZAM_ENTRY, *PZAM_ENTRY;
  3059. LIST_ENTRY g_leZamCache;
  3060. void
  3061. UpdateZamCache(
  3062. IN LARGE_INTEGER liCurrentTime
  3063. )
  3064. /*++
  3065. Description:
  3066. Throw any expired entries out of the ZAM cache.
  3067. Arguments:
  3068. IN liCurrentTime - current time, to compare vs expiry times of entries
  3069. Called by:
  3070. AssertInZamCache()
  3071. Locks:
  3072. Assumes caller has write lock on ZAM_CACHE
  3073. --*/
  3074. {
  3075. PLIST_ENTRY pleNode;
  3076. PZAM_ENTRY pZam;
  3077. // Throw out old cache entries
  3078. while (g_leZamCache.Flink isnot &g_leZamCache)
  3079. {
  3080. pleNode = g_leZamCache.Flink;
  3081. pZam = CONTAINING_RECORD(pleNode, ZAM_ENTRY, leCacheLink);
  3082. if ( RtlLargeIntegerLessThanOrEqualTo( pZam->liExpiryTime,
  3083. liCurrentTime )
  3084. || RtlLargeIntegerEqualToZero( liCurrentTime ))
  3085. {
  3086. Trace6(MCAST,
  3087. "Evicting %d.%d.%d.%d/%d.%d.%d.%d from ZAM cache with current time %x.%x exp %x.%x",
  3088. PRINT_IPADDR(pZam->ipScopeZoneID),
  3089. PRINT_IPADDR(pZam->ipStartAddress),
  3090. liCurrentTime.HighPart, liCurrentTime.LowPart,
  3091. pZam->liExpiryTime.HighPart, pZam->liExpiryTime.LowPart);
  3092. RemoveEntryList( &pZam->leCacheLink );
  3093. FREE( pZam );
  3094. continue;
  3095. }
  3096. // Ok, we've reached one that stays, so we're done
  3097. break;
  3098. }
  3099. }
  3100. PZAM_ENTRY
  3101. AddToZamCache(
  3102. IN IPV4_ADDRESS ipScopeZoneID,
  3103. IN IPV4_ADDRESS ipStartAddress,
  3104. IN LARGE_INTEGER liExpiryTime
  3105. )
  3106. /*++
  3107. Description:
  3108. This function takes a ZAM identifier and timeout, and adds it to the
  3109. ZAM cache.
  3110. Arguments:
  3111. IN ipScopeZoneID - scope zone ID to cache
  3112. IN ipStartAddress - scope start address to cache
  3113. IN liExpiryTime - time at which to expire the cache entry
  3114. Returns:
  3115. Pointer to cache entry, or NULL on memory error
  3116. Called by:
  3117. AssertInZamCache()
  3118. Locks:
  3119. Assumes caller holds write lock on ZAM_CACHE
  3120. --*/
  3121. {
  3122. PLIST_ENTRY pleNode;
  3123. PZAM_ENTRY pZam;
  3124. // Add entry to cache
  3125. pZam = MALLOC( sizeof(ZAM_ENTRY) );
  3126. if (!pZam)
  3127. {
  3128. return NULL;
  3129. }
  3130. pZam->ipScopeZoneID = ipScopeZoneID;
  3131. pZam->ipStartAddress = ipStartAddress;
  3132. pZam->liExpiryTime = liExpiryTime;
  3133. // Search for entry after the new one
  3134. for (pleNode = g_leZamCache.Flink;
  3135. pleNode isnot &g_leZamCache;
  3136. pleNode = pleNode->Flink)
  3137. {
  3138. PZAM_ENTRY pPrevC = CONTAINING_RECORD(pleNode, ZAM_ENTRY, leCacheLink);
  3139. if (RtlLargeIntegerGreaterThan(pPrevC->liExpiryTime,
  3140. pZam->liExpiryTime))
  3141. {
  3142. break;
  3143. }
  3144. }
  3145. // Insert into cache
  3146. InsertTailList( pleNode, &pZam->leCacheLink );
  3147. return pZam;
  3148. }
  3149. PZAM_ENTRY
  3150. FindInZamCache(
  3151. IN IPV4_ADDRESS ipScopeZoneID,
  3152. IN IPV4_ADDRESS ipStartAddress
  3153. )
  3154. /*++
  3155. Description:
  3156. See if a given ZAM spec is in the cache.
  3157. Arguments:
  3158. IN ipScopeZoneID - scope zone ID to match
  3159. IN ipStartAddress - scope start address to match
  3160. Return:
  3161. Pointer to cache entry, or NULL if not found.
  3162. Called by:
  3163. AssertInZamCache()
  3164. Locks:
  3165. Assumes caller has read lock on ZAM_CACHE
  3166. --*/
  3167. {
  3168. PLIST_ENTRY pleNode;
  3169. // Search for cache entry
  3170. for (pleNode = g_leZamCache.Flink;
  3171. pleNode isnot &g_leZamCache;
  3172. pleNode = pleNode->Flink)
  3173. {
  3174. ZAM_ENTRY *pZam = CONTAINING_RECORD(pleNode, ZAM_ENTRY, leCacheLink);
  3175. if ( ipScopeZoneID is pZam->ipScopeZoneID
  3176. && ipStartAddress is pZam->ipStartAddress)
  3177. {
  3178. return pZam;
  3179. }
  3180. }
  3181. return NULL;
  3182. }
  3183. PZAM_ENTRY
  3184. AssertInZamCache(
  3185. IN IPV4_ADDRESS ipScopeZoneID,
  3186. IN IPV4_ADDRESS ipStartAddress,
  3187. OUT BOOL *pbFound
  3188. )
  3189. /*++
  3190. Description:
  3191. Locate a ZAM spec in the cache, adding it if not already present.
  3192. Arguments:
  3193. IN ipScopeZoneID - scope zone ID to match/cache
  3194. IN ipStartAddress - scope start address to match/cache
  3195. OUT pbFound - TRUE if found, FALSE if newly cached
  3196. Called by:
  3197. HandleZAM()
  3198. Locks:
  3199. ZAM_CACHE for writing
  3200. --*/
  3201. {
  3202. PZAM_ENTRY pZam;
  3203. LARGE_INTEGER liCurrentTime, liExpiryTime;
  3204. // Get current time
  3205. NtQuerySystemTime(&liCurrentTime);
  3206. ENTER_WRITER(ZAM_CACHE);
  3207. {
  3208. UpdateZamCache(liCurrentTime);
  3209. pZam = FindInZamCache( ipScopeZoneID, ipStartAddress);
  3210. if (!pZam)
  3211. {
  3212. liExpiryTime = RtlLargeIntegerAdd(liCurrentTime,
  3213. RtlConvertUlongToLargeInteger(TM_SECONDS(ZAM_DUP_TIME)));
  3214. AddToZamCache( ipScopeZoneID, ipStartAddress, liExpiryTime );
  3215. Trace6(MCAST,
  3216. "Added %d.%d.%d.%d/%d.%d.%d.%d to ZAM cache with current time %x/%x exp %x/%x",
  3217. PRINT_IPADDR(ipScopeZoneID),
  3218. PRINT_IPADDR(ipStartAddress),
  3219. liCurrentTime.HighPart, liCurrentTime.LowPart,
  3220. liExpiryTime.HighPart, liExpiryTime.LowPart);
  3221. *pbFound = FALSE;
  3222. }
  3223. else
  3224. {
  3225. *pbFound = TRUE;
  3226. }
  3227. }
  3228. EXIT_LOCK(ZAM_CACHE);
  3229. return pZam;
  3230. }
  3231. //////////////////////////////////////////////////////////////////////////////
  3232. // Functions for message sending
  3233. //////////////////////////////////////////////////////////////////////////////
  3234. DWORD
  3235. SendMZAPMessageByIndex(
  3236. IN PBYTE pBuffer,
  3237. IN ULONG ulBuffLen,
  3238. IN IPV4_ADDRESS ipGroup,
  3239. IN DWORD dwIfIndex
  3240. )
  3241. {
  3242. SOCKADDR_IN sinAddr;
  3243. DWORD dwErr = NO_ERROR, dwLen;
  3244. dwErr = McSetMulticastIfByIndex( g_mzapLocalSocket, SOCK_DGRAM, dwIfIndex );
  3245. if (dwErr is SOCKET_ERROR)
  3246. {
  3247. dwErr = WSAGetLastError();
  3248. Trace2( ERR,
  3249. "SendMZAPMessage: error %d setting oif to IF %x",
  3250. dwErr,
  3251. dwIfIndex );
  3252. }
  3253. sinAddr.sin_family = AF_INET;
  3254. sinAddr.sin_addr.s_addr = ipGroup;
  3255. sinAddr.sin_port = htons(MZAP_PORT);
  3256. #ifdef DEBUG_MZAP
  3257. Trace2( ERR, "SendMZAPMessageByIndex: sending %d bytes on IF %d",
  3258. ulBuffLen, dwIfIndex );
  3259. #endif
  3260. dwLen = sendto( g_mzapLocalSocket,
  3261. pBuffer,
  3262. ulBuffLen,
  3263. 0,
  3264. (struct sockaddr*)&sinAddr,
  3265. sizeof(sinAddr));
  3266. #ifdef DEBUG_MZAP
  3267. Trace1( ERR, "SendMZAPMessageByIndex: sent %d bytes", dwLen);
  3268. #endif
  3269. if (dwLen is SOCKET_ERROR )
  3270. {
  3271. dwErr = WSAGetLastError();
  3272. Trace1( ERR,
  3273. "SendMZAPMessage: error %d sending message",
  3274. dwErr );
  3275. }
  3276. return dwErr;
  3277. }
  3278. DWORD
  3279. SendMZAPMessage(
  3280. IN PBYTE pBuffer,
  3281. IN ULONG ulBuffLen,
  3282. IN IPV4_ADDRESS ipGroup,
  3283. IN IPV4_ADDRESS ipInterface
  3284. )
  3285. /*++
  3286. Called by:
  3287. HandleZAM()
  3288. Arguments:
  3289. IN pBuffer - buffer containing message to send
  3290. IN ulBuffLen - length of buffer in bytes
  3291. IN ipGroup - destination address to send message to
  3292. IN ipInterface - interface to send message out
  3293. Returns:
  3294. whatever WSAGetLastError() returns
  3295. Locks:
  3296. None
  3297. --*/
  3298. {
  3299. SOCKADDR_IN sinAddr;
  3300. DWORD dwErr = NO_ERROR, dwLen;
  3301. dwErr = McSetMulticastIf( g_mzapLocalSocket, ipInterface );
  3302. if (dwErr is SOCKET_ERROR)
  3303. {
  3304. dwErr = WSAGetLastError();
  3305. Trace2( ERR,
  3306. "SendMZAPMessage: error %d setting oif to %d.%d.%d.%d",
  3307. dwErr,
  3308. PRINT_IPADDR(ipInterface) );
  3309. }
  3310. sinAddr.sin_family = AF_INET;
  3311. sinAddr.sin_addr.s_addr = ipGroup;
  3312. sinAddr.sin_port = htons(MZAP_PORT);
  3313. #ifdef DEBUG_MZAP
  3314. Trace2( ERR, "SendMZAPMessage: sending %d bytes on %d.%d.%d.%d", ulBuffLen,
  3315. PRINT_IPADDR(ipInterface));
  3316. #endif
  3317. dwLen = sendto( g_mzapLocalSocket,
  3318. pBuffer,
  3319. ulBuffLen,
  3320. 0,
  3321. (struct sockaddr*)&sinAddr,
  3322. sizeof(sinAddr));
  3323. #ifdef DEBUG_MZAP
  3324. Trace1( ERR, "SendMZAPMessage: sent %d bytes", dwLen);
  3325. #endif
  3326. if (dwLen is SOCKET_ERROR )
  3327. {
  3328. dwErr = WSAGetLastError();
  3329. Trace1( ERR,
  3330. "SendMZAPMessage: error %d sending message",
  3331. dwErr );
  3332. }
  3333. return dwErr;
  3334. }
  3335. void
  3336. AddMZAPHeader(
  3337. IN OUT PBYTE *ppb, // IN: pointer into buffer
  3338. IN BYTE byPType, // IN: message type
  3339. IN PSCOPE_ENTRY pScope // IN: scope
  3340. )
  3341. /*++
  3342. Description:
  3343. Compose an MZAP message header in a buffer.
  3344. Arguments:
  3345. IN/OUT ppb - buffer to add an MZAP header to
  3346. IN byPType - message type to fill into header
  3347. IN pScope - scope to fill into header
  3348. Called by:
  3349. SendZAM(), SendZCM()
  3350. Locks:
  3351. Assumes caller holds read lock on BOUNDARY_TABLE so pScope won't go away
  3352. --*/
  3353. {
  3354. PBYTE pb;
  3355. IPV4_MZAP_HEADER *mh = (PIPV4_MZAP_HEADER)*ppb;
  3356. BYTE pConfName[257];
  3357. ULONG ulConfNameLen, ulConfLangLen;
  3358. PSCOPE_NAME_ENTRY pName;
  3359. int iDefault;
  3360. PLIST_ENTRY pleNode;
  3361. PBYTE pLangName;
  3362. // Make sure packing is correct
  3363. ASSERT((((PBYTE)&mh->ipMessageOrigin) - ((PBYTE)mh)) is 4);
  3364. mh->byVersion = MZAP_VERSION;
  3365. mh->byBPType = byPType;
  3366. if (pScope->bDivisible)
  3367. {
  3368. mh->byBPType |= MZAP_BIG_BIT;
  3369. }
  3370. mh->byAddressFamily = ADDRFAMILY_IPV4;
  3371. mh->byNameCount = 0;
  3372. mh->ipMessageOrigin = g_ipMyAddress;
  3373. mh->ipScopeZoneID = MyScopeZoneID(pScope);
  3374. mh->ipScopeStart = pScope->ipGroupAddress;
  3375. mh->ipScopeEnd = TOP_OF_SCOPE( pScope );
  3376. // Append scope name blocks
  3377. pb = *ppb + sizeof(IPV4_MZAP_HEADER);
  3378. for (pleNode = pScope->leNameList.Flink;
  3379. pleNode isnot &pScope->leNameList;
  3380. pleNode = pleNode->Flink)
  3381. {
  3382. pName = CONTAINING_RECORD(pleNode, SCOPE_NAME_ENTRY, leNameLink);
  3383. iDefault = (pName->bDefault)? MZAP_DEFAULT_BIT : 0;
  3384. pLangName = GetLangName(pName->idLanguage);
  3385. ulConfLangLen = strlen(pLangName);
  3386. ulConfNameLen = WideCharToMultiByte( CP_UTF8,
  3387. 0,
  3388. pName->snScopeName,
  3389. sn_strlen( pName->snScopeName ),
  3390. pConfName,
  3391. sizeof(pConfName),
  3392. NULL,
  3393. NULL );
  3394. *pb++ = (BYTE)iDefault;
  3395. *pb++ = (BYTE)ulConfLangLen;
  3396. strncpy( pb, pLangName, ulConfLangLen );
  3397. pb += ulConfLangLen;
  3398. *pb++ = (BYTE)ulConfNameLen;
  3399. strncpy( pb, pConfName, ulConfNameLen );
  3400. pb += ulConfNameLen;
  3401. mh->byNameCount++;
  3402. }
  3403. // Pad to a 4-byte boundary
  3404. // Note that casting to a ULONG is 64-bit safe, since we only care about
  3405. // the low-order bits anyway.
  3406. while (((ULONG_PTR)pb) & 3)
  3407. {
  3408. *pb++ = '\0';
  3409. }
  3410. *ppb = pb;
  3411. }
  3412. INLINE
  3413. IPV4_ADDRESS
  3414. MzapRelativeGroup(
  3415. IN PSCOPE_ENTRY pScope
  3416. )
  3417. /*++
  3418. Description:
  3419. Returns the Scope-relative group address for MZAP within a given scope.
  3420. Arguments:
  3421. IN pScope - scope to find the MZAP group in
  3422. Returns:
  3423. Address of the MZAP group in the scope
  3424. Locks:
  3425. Assumes caller holds read lock on BOUNDARY_TABLE so pScope doesn't go away
  3426. --*/
  3427. {
  3428. return htonl(ntohl(TOP_OF_SCOPE(pScope)) - MZAP_RELATIVE_GROUP);
  3429. }
  3430. ULONG
  3431. GetMZAPHeaderSize(
  3432. IN PSCOPE_ENTRY pScope
  3433. )
  3434. {
  3435. PLIST_ENTRY pleNode;
  3436. ULONG ulLen = sizeof(IPV4_MZAP_HEADER);
  3437. BYTE pConfName[257];
  3438. PSCOPE_NAME_ENTRY pName;
  3439. PBYTE pLangName;
  3440. ULONG ulConfLangLen, ulConfNameLen;
  3441. // For each scope name, add size needed to store it
  3442. for (pleNode = pScope->leNameList.Flink;
  3443. pleNode isnot &pScope->leNameList;
  3444. pleNode = pleNode->Flink)
  3445. {
  3446. pName = CONTAINING_RECORD(pleNode, SCOPE_NAME_ENTRY, leNameLink);
  3447. pLangName = GetLangName(pName->idLanguage);
  3448. ulConfLangLen = strlen(pLangName);
  3449. WideCharToMultiByte( CP_UTF8,
  3450. 0,
  3451. pName->snScopeName,
  3452. sn_strlen( pName->snScopeName ),
  3453. pConfName,
  3454. sizeof(pConfName),
  3455. NULL,
  3456. NULL );
  3457. ulConfNameLen = strlen( pConfName );
  3458. ulLen += 3; // flags, langlen, and namelen
  3459. ulLen += ulConfLangLen;
  3460. ulLen += ulConfNameLen;
  3461. }
  3462. // Round up to multiple of 4
  3463. ulLen = 4 * ((ulLen + 3) / 4);
  3464. return ulLen;
  3465. }
  3466. ULONG
  3467. GetZAMBuffSize(
  3468. IN PSCOPE_ENTRY pScope
  3469. )
  3470. {
  3471. ULONG ulLen = GetMZAPHeaderSize(pScope) + sizeof(IPV4_ZAM_HEADER);
  3472. #ifdef SECURE_MZAP
  3473. // Add size of Authentication Block
  3474. // XXX
  3475. #endif
  3476. // return 512; // an unsigned IPv4 ZAM message is at most 284 bytes
  3477. return ulLen;
  3478. }
  3479. DWORD
  3480. SendZAM(
  3481. IN PSCOPE_ENTRY pScope
  3482. )
  3483. /*++
  3484. Description:
  3485. Send a ZAM message within a given scope.
  3486. Locks:
  3487. Assumes caller holds lock on BOUNDARY_TABLE so pScope doesn't go away
  3488. --*/
  3489. {
  3490. DWORD dwErr;
  3491. PBYTE pBuffer, pb;
  3492. PIPV4_ZAM_HEADER zam;
  3493. ULONG ulBuffLen;
  3494. ulBuffLen = GetZAMBuffSize( pScope );
  3495. pb = pBuffer = MALLOC( ulBuffLen );
  3496. if (!pb)
  3497. {
  3498. return ERROR_NOT_ENOUGH_MEMORY;
  3499. }
  3500. // Fill in MZAP header
  3501. AddMZAPHeader(&pb, PTYPE_ZAM, pScope);
  3502. zam = (PIPV4_ZAM_HEADER)pb;
  3503. zam->bZT = 0;
  3504. zam->bZTL = pScope->bZTL;
  3505. zam->wHoldTime = htons(ZAM_HOLDTIME);
  3506. zam->ipAddress[0] = g_ipMyLocalZoneID;
  3507. pb += sizeof(IPV4_ZAM_HEADER);
  3508. #ifdef SECURE_MZAP
  3509. // Add optional authentication block here
  3510. #endif
  3511. #ifdef DEBUG_MZAP
  3512. Trace0(ERR, "Originate ZAM inside...");
  3513. #endif
  3514. // Send on an interface which does not have a boundary for the given scope.
  3515. dwErr = SendMZAPMessage( pBuffer,
  3516. (DWORD)(pb-pBuffer),
  3517. MZAP_LOCAL_GROUP,
  3518. g_ipMyAddress );
  3519. FREE( pBuffer );
  3520. return dwErr;
  3521. }
  3522. ULONG
  3523. GetZCMBuffSize(
  3524. IN PSCOPE_ENTRY pScope
  3525. )
  3526. {
  3527. PLIST_ENTRY pleNode;
  3528. ULONG ulLen = GetMZAPHeaderSize(pScope) + sizeof(IPV4_ZCM_HEADER);
  3529. for (pleNode = pScope->leZBRList.Flink;
  3530. pleNode isnot &pScope->leZBRList;
  3531. pleNode = pleNode->Flink)
  3532. {
  3533. ulLen += sizeof(IPV4_ADDRESS);
  3534. }
  3535. return ulLen;
  3536. }
  3537. DWORD
  3538. SendZCM(
  3539. IN PSCOPE_ENTRY pScope
  3540. )
  3541. /*++
  3542. Description:
  3543. Sends a Zone Convexity Message for a given scope.
  3544. Locks:
  3545. Assumes caller has read lock on BOUNDARY_TABLE so pScope won't go away.
  3546. Locks ZBR_LIST for reading.
  3547. --*/
  3548. {
  3549. PBYTE pb;
  3550. PIPV4_ZCM_HEADER zcm;
  3551. PLIST_ENTRY pleNode;
  3552. PZBR_ENTRY pZbr;
  3553. WSABUF wsaZcmBuf;
  3554. DWORD dwSize, dwErr;
  3555. ENTER_READER(ZBR_LIST);
  3556. {
  3557. dwSize = GetZCMBuffSize(pScope);
  3558. wsaZcmBuf.len = dwSize;
  3559. wsaZcmBuf.buf = MALLOC( dwSize );
  3560. pb = wsaZcmBuf.buf;
  3561. if (!pb)
  3562. {
  3563. EXIT_LOCK(ZBR_LIST);
  3564. return GetLastError();
  3565. }
  3566. // Fill in MZAP header
  3567. AddMZAPHeader(&pb, PTYPE_ZCM, pScope);
  3568. zcm = (PIPV4_ZCM_HEADER)pb;
  3569. zcm->bZNUM = 0;
  3570. zcm->bReserved = 0;
  3571. zcm->wHoldTime = htons(ZCM_HOLDTIME);
  3572. // Add all known neighbors
  3573. for (pleNode = pScope->leZBRList.Flink;
  3574. pleNode isnot &pScope->leZBRList;
  3575. pleNode = pleNode->Flink)
  3576. {
  3577. pZbr = CONTAINING_RECORD(pleNode, ZBR_ENTRY, leZBRLink);
  3578. zcm->ipZBR[ zcm->bZNUM++ ] = pZbr->ipAddress;
  3579. }
  3580. }
  3581. EXIT_LOCK(ZBR_LIST);
  3582. pb += sizeof(IPV4_ZCM_HEADER) + zcm->bZNUM * sizeof(IPV4_ADDRESS);
  3583. #ifdef DEBUG_MZAP
  3584. Trace0(ERR, "Sending ZCM...");
  3585. #endif
  3586. dwErr = SendMZAPMessage( wsaZcmBuf.buf,
  3587. (DWORD)(pb-wsaZcmBuf.buf),
  3588. MzapRelativeGroup(pScope),
  3589. g_ipMyAddress );
  3590. // Free the buffer
  3591. FREE( wsaZcmBuf.buf );
  3592. return dwErr;
  3593. }
  3594. DWORD
  3595. SendZLE(
  3596. IN PZLE_PENDING zle
  3597. )
  3598. /*++
  3599. Description:
  3600. Given a buffer holding a ZAM, immediately send a ZLE to the origin.
  3601. Locks:
  3602. Assumes caller holds write lock on ZLE_LIST
  3603. --*/
  3604. {
  3605. DWORD dwErr;
  3606. PBYTE pBuffer = zle->pBuffer;
  3607. ULONG ulBuffLen = zle->ulBuffLen;
  3608. IPV4_MZAP_HEADER *mh = (PIPV4_MZAP_HEADER)pBuffer;
  3609. IPV4_ADDRESS ipDestAddr = mh->ipScopeEnd - MZAP_RELATIVE_GROUP;
  3610. // Change PType to ZLE
  3611. mh->byBPType = (mh->byBPType & MZAP_BIG_BIT) | PTYPE_ZLE;
  3612. #ifdef DEBUG_MZAP
  3613. Trace0(ERR, "Sending ZLE...");
  3614. #endif
  3615. // Return to sender
  3616. dwErr = SendMZAPMessage( pBuffer,
  3617. ulBuffLen,
  3618. ipDestAddr,
  3619. g_ipMyAddress );
  3620. // Free up space
  3621. DeletePendingZLE(zle);
  3622. return dwErr;
  3623. }
  3624. double
  3625. UniformRandom01()
  3626. {
  3627. return ((double)rand()) / RAND_MAX;
  3628. }
  3629. VOID
  3630. SendAllZamsAndZcms()
  3631. /*++
  3632. Locks:
  3633. BOUNDARY_TABLE for reading
  3634. --*/
  3635. {
  3636. PLIST_ENTRY pleNode;
  3637. PSCOPE_ENTRY pScope;
  3638. double t,x;
  3639. ULONG Tmin,Trange;
  3640. BOOL bSent = FALSE;
  3641. ENTER_READER(BOUNDARY_TABLE);
  3642. {
  3643. for (pleNode = g_MasterScopeList.Flink;
  3644. pleNode isnot &g_MasterScopeList;
  3645. pleNode = pleNode->Flink)
  3646. {
  3647. pScope = CONTAINING_RECORD(pleNode, SCOPE_ENTRY, leScopeLink);
  3648. // Send ZAM inside
  3649. SendZAM( pScope );
  3650. // Send ZCM inside
  3651. SendZCM( pScope );
  3652. bSent = TRUE;
  3653. }
  3654. if (bSent)
  3655. {
  3656. SendZCM( &g_LocalScope );
  3657. }
  3658. }
  3659. EXIT_LOCK(BOUNDARY_TABLE);
  3660. // Schedule the next time to send them
  3661. Tmin = ZAM_INTERVAL/2;
  3662. Trange = ZAM_INTERVAL;
  3663. x = UniformRandom01();
  3664. t = Tmin + x*Trange;
  3665. g_liZamExpiryTime = RtlLargeIntegerAdd( g_liZamExpiryTime,
  3666. RtlConvertUlongToLargeInteger(TM_SECONDS((ULONG)floor(t+0.5))));
  3667. }
  3668. //////////////////////////////////////////////////////////////////////////////
  3669. // Functions for message processing
  3670. //////////////////////////////////////////////////////////////////////////////
  3671. VOID
  3672. CheckForScopeNameMismatch(
  3673. IN PSCOPE_ENTRY pScope,
  3674. IN IPV4_MZAP_HEADER *mh
  3675. )
  3676. /*++
  3677. Locks:
  3678. Assumes caller holds read lock on BOUNDARY_TABLE so pScope won't go away
  3679. --*/
  3680. {
  3681. DWORD i, dwMsgNameLen, dwMsgLangLen, dwConfNameLen = 0, dwConfLangLen;
  3682. DWORD dwMsgNameWLen;
  3683. BYTE pMsgLang[257], *pb, *pConfLang;
  3684. SCOPE_NAME snConfName = NULL;
  3685. SCOPE_NAME_BUFFER snMsgName;
  3686. PLIST_ENTRY pleNode;
  3687. PSCOPE_NAME_ENTRY pName;
  3688. // For each language in the message
  3689. // If we know that language
  3690. // If the names are different
  3691. // Signal a conflict
  3692. pb = mh->pScopeNameBlock;
  3693. for (i=0; i<mh->byNameCount; i++)
  3694. {
  3695. pb++; // skip flags
  3696. dwMsgLangLen = *pb++;
  3697. strncpy(pMsgLang, pb, dwMsgLangLen);
  3698. pMsgLang[ dwMsgLangLen ] = '\0';
  3699. pb += dwMsgLangLen;
  3700. dwMsgNameLen = *pb++;
  3701. dwMsgNameWLen = MultiByteToWideChar( CP_UTF8,
  3702. 0,
  3703. pb,
  3704. dwMsgNameLen,
  3705. snMsgName,
  3706. MAX_SCOPE_NAME_LEN+1 );
  3707. snMsgName[dwMsgNameWLen] = L'\0';
  3708. pb += dwMsgNameLen;
  3709. pName = GetScopeNameByLangName( pScope, pMsgLang );
  3710. if (!pName)
  3711. continue;
  3712. snConfName = pName->snScopeName;
  3713. dwConfNameLen = sn_strlen(snConfName);
  3714. // Check for a name conflict
  3715. if (dwConfNameLen != dwMsgNameWLen
  3716. || sn_strncmp(snConfName, snMsgName, dwMsgNameWLen))
  3717. {
  3718. // Display origin and both scope names
  3719. MakeAddressStringW(g_AddrBuf1, mh->ipMessageOrigin);
  3720. Trace1( ERR,
  3721. "ERROR: Scope name conflict with %ls",
  3722. g_AddrBuf1 );
  3723. Trace1( ERR, "ERROR: Our name = %ls", snConfName );
  3724. Trace1( ERR, "ERROR: His name = %ls", snMsgName );
  3725. RouterLogEventExW( LOGHANDLE,
  3726. EVENTLOG_ERROR_TYPE,
  3727. 0,
  3728. ROUTERLOG_IP_SCOPE_NAME_CONFLICT,
  3729. L"%S%S%S",
  3730. g_AddrBuf1,
  3731. snConfName,
  3732. snMsgName );
  3733. }
  3734. }
  3735. }
  3736. VOID
  3737. ReportLeakyScope(
  3738. IN PSCOPE_ENTRY pScope,
  3739. IN IPV4_MZAP_HEADER *mh,
  3740. IN IPV4_ZAM_HEADER *zam
  3741. )
  3742. /*++
  3743. Called by:
  3744. HandleZAM(), HandleZLE()
  3745. Locks:
  3746. Assumes caller has read lock on BOUNDARY_TABLE so pScope won't go away
  3747. --*/
  3748. {
  3749. ULONG ulIdx;
  3750. PWCHAR pwszBuffer, pb;
  3751. Trace1( ERR,
  3752. "ERROR: Leak detected in '%ls' scope! One of the following routers is misconfigured:",
  3753. GetDefaultName( pScope ) );
  3754. pb = pwszBuffer = MALLOC( zam->bZT * 20 + 1 );
  3755. if (pwszBuffer is NULL)
  3756. {
  3757. Trace0( ERR, "ERROR: Couldn't allocate space for rest of message");
  3758. return;
  3759. }
  3760. // Add origin.
  3761. swprintf(pb, L" %d.%d.%d.%d", PRINT_IPADDR(mh->ipMessageOrigin ));
  3762. pb += wcslen(pb);
  3763. Trace1( ERR,
  3764. " %d.%d.%d.%d",
  3765. PRINT_IPADDR(mh->ipMessageOrigin ));
  3766. // Display addresses of routers in the path list.
  3767. for (ulIdx=0; ulIdx < zam->bZT; ulIdx++)
  3768. {
  3769. swprintf(pb,L" %d.%d.%d.%d", PRINT_IPADDR(zam->ipAddress[ulIdx*2+1]));
  3770. pb += wcslen(pb);
  3771. Trace1( ERR,
  3772. " %d.%d.%d.%d",
  3773. PRINT_IPADDR(zam->ipAddress[ulIdx*2+1] ));
  3774. }
  3775. // write to event log
  3776. RouterLogEventExW( LOGHANDLE,
  3777. EVENTLOG_ERROR_TYPE,
  3778. 0,
  3779. ROUTERLOG_IP_LEAKY_SCOPE,
  3780. L"%S%S",
  3781. GetDefaultName(pScope),
  3782. pwszBuffer );
  3783. FREE( pwszBuffer );
  3784. }
  3785. VOID
  3786. CheckForScopeRangeMismatch(
  3787. IN IPV4_MZAP_HEADER *mh
  3788. )
  3789. /*++
  3790. Called by:
  3791. HandleZAM(), HandleZCM()
  3792. Locks:
  3793. Assumes caller has read lock on BOUNDARY_TABLE
  3794. --*/
  3795. {
  3796. PLIST_ENTRY pleNode;
  3797. PSCOPE_ENTRY pScope;
  3798. for (pleNode = g_MasterScopeList.Flink;
  3799. pleNode isnot &g_MasterScopeList;
  3800. pleNode = pleNode->Flink)
  3801. {
  3802. pScope = CONTAINING_RECORD(pleNode, SCOPE_ENTRY, leScopeLink);
  3803. if (mh->ipScopeStart > TOP_OF_SCOPE(pScope)
  3804. || mh->ipScopeEnd < pScope->ipGroupAddress)
  3805. continue;
  3806. MakeAddressStringW(g_AddrBuf1, mh->ipScopeStart);
  3807. MakeAddressStringW(g_AddrBuf2, mh->ipScopeEnd);
  3808. MakeAddressStringW(g_AddrBuf3, pScope->ipGroupAddress);
  3809. MakeAddressStringW(g_AddrBuf4, TOP_OF_SCOPE(pScope) );
  3810. Trace1( ERR,
  3811. "ERROR: ZAM scope conflicts with configured scope '%ls'!",
  3812. GetDefaultName(pScope) );
  3813. Trace2( ERR,
  3814. "ERROR: ZAM has: (%ls-%ls)",
  3815. g_AddrBuf1,
  3816. g_AddrBuf2 );
  3817. Trace2( ERR,
  3818. "ERROR: Scope is (%ls-%ls)",
  3819. g_AddrBuf3,
  3820. g_AddrBuf4 );
  3821. RouterLogEventExW( LOGHANDLE,
  3822. EVENTLOG_ERROR_TYPE,
  3823. 0,
  3824. ROUTERLOG_IP_SCOPE_ADDR_CONFLICT,
  3825. L"%S%S%S%S%S",
  3826. GetDefaultName(pScope),
  3827. g_AddrBuf1,
  3828. g_AddrBuf2,
  3829. g_AddrBuf3,
  3830. g_AddrBuf4 );
  3831. break;
  3832. }
  3833. }
  3834. BOOL
  3835. ZamIncludesZoneID(
  3836. IPV4_ZAM_HEADER *zam,
  3837. IPV4_ADDRESS ipZoneID
  3838. )
  3839. {
  3840. ULONG ulIdx;
  3841. for (ulIdx=0; ulIdx <= ((ULONG)zam->bZT)*2; ulIdx+=2)
  3842. {
  3843. if (zam->ipAddress[ulIdx] == ipZoneID)
  3844. {
  3845. return TRUE;
  3846. }
  3847. }
  3848. return FALSE;
  3849. }
  3850. void
  3851. HandleZAM(
  3852. IN PBYTE pBuffer, // IN: Buffer holding ZAM received
  3853. IN ULONG ulBuffLen, // IN: Length of ZAM message
  3854. IN PBOUNDARY_IF pInBIf // IN: BIf on which ZAM arrived, or NULL
  3855. // if it came from "inside"
  3856. )
  3857. /*++
  3858. Called by:
  3859. HandleMZAPSocket()
  3860. Locks:
  3861. Assumes caller holds read lock on BOUNDARY_TABLE
  3862. Locks ZLE_LIST for writing
  3863. --*/
  3864. {
  3865. PBYTE pb;
  3866. IPV4_MZAP_HEADER *mh;
  3867. IPV4_ZAM_HEADER *zam;
  3868. BOOL bFound, bFromInside = FALSE;
  3869. PSCOPE_ENTRY pScope, pOverlap;
  3870. BOUNDARY_ENTRY *pBoundary = NULL;
  3871. ULONG ulIdx;
  3872. PBOUNDARY_IF pBIf;
  3873. mh = (PIPV4_MZAP_HEADER)pBuffer;
  3874. // Set pb to end of MZAP header
  3875. pb = pBuffer + sizeof(IPV4_MZAP_HEADER);
  3876. for (ulIdx=0; ulIdx < mh->byNameCount; ulIdx++)
  3877. {
  3878. // skip flags
  3879. pb ++;
  3880. // skip language tag len and str
  3881. pb += (1 + *pb);
  3882. // skip scope name len and str
  3883. pb += (1 + *pb);
  3884. }
  3885. // Note that casting to a ULONG is safe, since we only care about
  3886. // the low-order bits anyway.
  3887. while (((ULONG_PTR)pb) & 3)
  3888. *pb++ = '\0';
  3889. zam = (PIPV4_ZAM_HEADER)pb;
  3890. {
  3891. // Find matching scope entry
  3892. pScope = FindScope( mh->ipScopeStart,
  3893. ~(mh->ipScopeEnd - mh->ipScopeStart) );
  3894. if (pScope) {
  3895. pBoundary = (pInBIf)? FindBoundaryEntry(pInBIf, pScope) : NULL;
  3896. if (pBoundary)
  3897. {
  3898. // ZAM arrived from "outside"
  3899. //
  3900. // If ZAM is for a scope we're inside, but was received over a
  3901. // boundary, signal a leaky scope warning.
  3902. //
  3903. if (mh->ipScopeZoneID == MyScopeZoneID(pScope))
  3904. {
  3905. ReportLeakyScope(pScope, mh, zam);
  3906. }
  3907. // If the previous Local Zone ID was given, update our
  3908. // local copy.
  3909. if ( zam->ipAddress[ zam->bZT * 2 ] )
  3910. {
  3911. pInBIf->ipOtherLocalZoneID = zam->ipAddress[ zam->bZT * 2 ];
  3912. }
  3913. //
  3914. // If ZAM was received on an interface with a boundary for the
  3915. // given scope, drop it.
  3916. //
  3917. return;
  3918. }
  3919. else
  3920. {
  3921. // ZAM arrived from "inside"
  3922. bFromInside = TRUE;
  3923. // Make sure we know about the origin as a neighbor
  3924. AssertZBR(pScope, mh->ipMessageOrigin, zam->wHoldTime);
  3925. //
  3926. // If a ZAM was received from within the zone, then the
  3927. // Zone ID should match. Persistent mismatches are evidence
  3928. // of a leaky Local Scope.
  3929. //
  3930. if (mh->ipScopeZoneID != MyScopeZoneID(pScope))
  3931. {
  3932. //
  3933. // Display origin and scope info, warn about
  3934. // possible leaky local scope.
  3935. //
  3936. MakeAddressStringW(g_AddrBuf1, mh->ipMessageOrigin);
  3937. MakeAddressStringW(g_AddrBuf2, mh->ipScopeStart);
  3938. Trace2( ERR,
  3939. "WARNING: Possible leaky Local Scope detected between this machine and %ls, boundary exists for %ls.",
  3940. g_AddrBuf1,
  3941. g_AddrBuf2 );
  3942. RouterLogEventExW( LOGHANDLE,
  3943. EVENTLOG_WARNING_TYPE,
  3944. 0,
  3945. ROUTERLOG_IP_POSSIBLE_LEAKY_SCOPE,
  3946. L"%S%S",
  3947. g_AddrBuf1,
  3948. g_AddrBuf2 );
  3949. }
  3950. // See if scope names don't match
  3951. CheckForScopeNameMismatch(pScope, mh);
  3952. }
  3953. // If last local zone ID is 0, but we know a zone ID, fill it in.
  3954. if ( ! zam->ipAddress[ zam->bZT * 2 ] )
  3955. {
  3956. if (pBoundary)
  3957. zam->ipAddress[ zam->bZT*2 ] = pInBIf->ipOtherLocalZoneID;
  3958. else
  3959. zam->ipAddress[ zam->bZT*2 ] = MyScopeZoneID(pScope);
  3960. }
  3961. }
  3962. else
  3963. {
  3964. //
  3965. // Check for conflicting address ranges. A scope conflicts
  3966. // if any locally-configured scope's range overlaps that in the ZAM.
  3967. //
  3968. CheckForScopeRangeMismatch(mh);
  3969. }
  3970. }
  3971. // Check ZAM cache. If found, drop new ZAM.
  3972. AssertInZamCache(mh->ipScopeZoneID, mh->ipScopeStart, &bFound);
  3973. Trace3(MCAST, "ZAM Cache check for %d.%d.%d.%d, %d.%d.%d.%d is %d",
  3974. PRINT_IPADDR(mh->ipScopeZoneID),
  3975. PRINT_IPADDR( mh->ipScopeStart),
  3976. bFound);
  3977. if (bFound)
  3978. {
  3979. #ifdef SECURE_MZAP
  3980. // If cached ZAM wasn't authenticated, and this one is,
  3981. // then go ahead and forward it. XXX
  3982. #endif
  3983. return;
  3984. }
  3985. // If it's from outside, see if our Local Zone ID is already in
  3986. // the path list. If so, drop it.
  3987. if (!bFromInside)
  3988. {
  3989. if (ZamIncludesZoneID(zam, g_ipMyLocalZoneID))
  3990. return;
  3991. }
  3992. // Update Zones travelled, and drop if we've reached the limit
  3993. zam->bZT++;
  3994. if (zam->bZT >= zam->bZTL)
  3995. {
  3996. PBYTE pBufferDup;
  3997. ZLE_PENDING *zle;
  3998. LARGE_INTEGER liCurrentTime, liExpiryTime;
  3999. double x,c,t;
  4000. ENTER_WRITER(MZAP_TIMER);
  4001. ENTER_WRITER(ZLE_LIST);
  4002. {
  4003. // See if one is already scheduled
  4004. if (FindPendingZLE(mh))
  4005. {
  4006. EXIT_LOCK(ZLE_LIST);
  4007. EXIT_LOCK(MZAP_TIMER);
  4008. return;
  4009. }
  4010. // Schedule a ZLE message
  4011. x = UniformRandom01();
  4012. c = 256.0;
  4013. t = ZLE_SUPPRESSION_INTERVAL * log(c*x+1) / log(c);
  4014. // Duplicate the message
  4015. pBufferDup = MALLOC( ulBuffLen );
  4016. if (!pBufferDup)
  4017. {
  4018. EXIT_LOCK(ZLE_LIST);
  4019. EXIT_LOCK(MZAP_TIMER);
  4020. return;
  4021. }
  4022. memcpy(pBufferDup, pBuffer, ulBuffLen);
  4023. NtQuerySystemTime(&liCurrentTime);
  4024. liExpiryTime = RtlLargeIntegerAdd(liCurrentTime,
  4025. RtlConvertUlongToLargeInteger(TM_SECONDS((ULONG)floor(t+0.5))));
  4026. zle = AddPendingZLE(pBufferDup, ulBuffLen, liExpiryTime);
  4027. }
  4028. EXIT_LOCK(ZLE_LIST);
  4029. UpdateMzapTimer();
  4030. EXIT_LOCK(MZAP_TIMER);
  4031. return;
  4032. }
  4033. // Add our address
  4034. ulBuffLen += 2*sizeof(IPV4_ADDRESS);
  4035. zam->ipAddress[ zam->bZT*2 - 1 ] = g_ipMyAddress;
  4036. // If from outside, inject inside
  4037. if ( !bFromInside )
  4038. {
  4039. zam->ipAddress[ zam->bZT*2 ] = g_ipMyLocalZoneID;
  4040. #ifdef DEBUG_MZAP
  4041. Trace0(ERR, "Relaying ZAM inside...");
  4042. #endif
  4043. SendMZAPMessage( pBuffer,
  4044. ulBuffLen,
  4045. MZAP_LOCAL_GROUP,
  4046. g_ipMyAddress );
  4047. }
  4048. //
  4049. // Re-originate on all interfaces with boundaries
  4050. // (skipping the arrival interface, if it has a boundary)
  4051. // We don't need to hold the lock on the BOUNDARY_TABLE from
  4052. // the first pass above, since it doesn't matter whether the
  4053. // boundaries change in between.
  4054. //
  4055. ENTER_READER(BOUNDARY_TABLE);
  4056. {
  4057. PLIST_ENTRY pleNode;
  4058. DWORD dwBucketIdx;
  4059. for (dwBucketIdx = 0;
  4060. dwBucketIdx < BOUNDARY_HASH_TABLE_SIZE;
  4061. dwBucketIdx++)
  4062. {
  4063. for (pleNode = g_bbScopeTable[dwBucketIdx].leInterfaceList.Flink;
  4064. pleNode isnot & g_bbScopeTable[dwBucketIdx].leInterfaceList;
  4065. pleNode = pleNode->Flink)
  4066. {
  4067. pBIf = CONTAINING_RECORD( pleNode,
  4068. BOUNDARY_IF,
  4069. leBoundaryIfLink );
  4070. if ( pBIf == pInBIf )
  4071. continue;
  4072. if (FindBoundaryEntry(pBIf, pScope))
  4073. {
  4074. #ifdef DEBUG_MZAP
  4075. Trace1(ERR, "NOT relaying ZAM on IF %d due to boundary",
  4076. pBIf->dwIfIndex );
  4077. #endif
  4078. continue;
  4079. }
  4080. // If other local zone ID is already in the path,
  4081. // skip it.
  4082. if (pBIf->ipOtherLocalZoneID
  4083. && ZamIncludesZoneID(zam, pBIf->ipOtherLocalZoneID))
  4084. continue;
  4085. zam->ipAddress[ zam->bZT*2 ] = pBIf->ipOtherLocalZoneID;
  4086. #ifdef DEBUG_MZAP
  4087. Trace0(ERR, "Relaying ZAM outside by index...");
  4088. #endif
  4089. SendMZAPMessageByIndex( pBuffer,
  4090. ulBuffLen,
  4091. MZAP_LOCAL_GROUP,
  4092. pBIf->dwIfIndex );
  4093. }
  4094. }
  4095. }
  4096. EXIT_LOCK(BOUNDARY_TABLE);
  4097. }
  4098. void
  4099. HandleZCM(
  4100. IN PBYTE pBuffer, // IN: Buffer holding ZAM received
  4101. IN ULONG ulBuffLen, // IN: Length of ZAM message
  4102. IN PBOUNDARY_IF pInBIf // IN: Interface on which the message arrived,
  4103. // or NULL if from "inside"
  4104. )
  4105. /*++
  4106. Called by:
  4107. HandleMZAPSocket()
  4108. Locks:
  4109. BOUNDARY_TABLE for reading
  4110. --*/
  4111. {
  4112. PBYTE pb;
  4113. IPV4_MZAP_HEADER *mh = (PIPV4_MZAP_HEADER)pBuffer;
  4114. IPV4_ZCM_HEADER *zcm;
  4115. PSCOPE_ENTRY pScope;
  4116. ULONG i;
  4117. BOOL bRouteFound;
  4118. // Set pb to end of MZAP header
  4119. pb = pBuffer + sizeof(IPV4_MZAP_HEADER);
  4120. for (i=0; i < mh->byNameCount; i++)
  4121. {
  4122. // skip flags
  4123. pb ++;
  4124. // skip language tag len and str
  4125. pb += (1 + *pb);
  4126. // skip scope name len and str
  4127. pb += (1 + *pb);
  4128. }
  4129. //
  4130. // Note that casting to a ULONG is safe, since we only care about
  4131. // the low-order bits anyway.
  4132. //
  4133. while (((ULONG_PTR)pb) & 3)
  4134. *pb++ = '\0';
  4135. zcm = (PIPV4_ZCM_HEADER)pb;
  4136. ENTER_READER(BOUNDARY_TABLE);
  4137. {
  4138. // Find matching scope entry
  4139. if (mh->ipScopeStart == IPV4_LOCAL_SCOPE_ADDR
  4140. && ~(mh->ipScopeEnd - mh->ipScopeStart) == IPV4_LOCAL_SCOPE_MASK)
  4141. {
  4142. pScope = &g_LocalScope;
  4143. }
  4144. else
  4145. {
  4146. pScope = FindScope( mh->ipScopeStart,
  4147. ~(mh->ipScopeEnd - mh->ipScopeStart) );
  4148. }
  4149. if (pScope) {
  4150. PBOUNDARY_IF pBIf;
  4151. PBOUNDARY_ENTRY pBoundary;
  4152. pBoundary = (pInBIf)? FindBoundaryEntry(pInBIf, pScope) : NULL;
  4153. if (pBoundary)
  4154. {
  4155. // ZCM arrived from "outside"
  4156. //
  4157. // If ZCM was received on an interface with a boundary for the
  4158. // given scope, drop it.
  4159. //
  4160. EXIT_LOCK(BOUNDARY_TABLE);
  4161. return;
  4162. }
  4163. else
  4164. {
  4165. // ZCM arrived from "inside"
  4166. #ifdef HAVE_RTMV2
  4167. RTM_NET_ADDRESS naZBR;
  4168. RTM_DEST_INFO rdi;
  4169. PRTM_ROUTE_INFO pri;
  4170. RTM_NEXTHOP_INFO nhi;
  4171. ULONG ulIdx;
  4172. #endif
  4173. // Make sure we know about the origin as a neighbor
  4174. AssertZBR(pScope, mh->ipMessageOrigin, zcm->wHoldTime);
  4175. #ifdef HAVE_RTMV2
  4176. //
  4177. // If multicast RIB route to any router address included
  4178. // is over a boundary for the given scope, signal
  4179. // non-convexity warning.
  4180. //
  4181. pri = HeapAlloc(
  4182. IPRouterHeap,
  4183. 0,
  4184. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  4185. );
  4186. if (pri == NULL)
  4187. {
  4188. EXIT_LOCK(BOUNDARY_TABLE);
  4189. return;
  4190. }
  4191. for (i = 0; i < zcm->bZNUM; i++)
  4192. {
  4193. RTM_IPV4_MAKE_NET_ADDRESS(&naZBR, zcm->ipZBR[i], 32);
  4194. // Look up route in multicast RIB
  4195. if ( RtmGetMostSpecificDestination( g_hLocalRoute,
  4196. &naZBR,
  4197. RTM_BEST_PROTOCOL,
  4198. RTM_VIEW_MASK_MCAST,
  4199. &rdi ) isnot NO_ERROR )
  4200. {
  4201. continue;
  4202. }
  4203. //
  4204. // See if next hop interface has a boundary for the
  4205. // ZCM group
  4206. //
  4207. ASSERT(rdi.ViewInfo[0].ViewId == RTM_VIEW_ID_MCAST);
  4208. if ( RtmGetRouteInfo( g_hLocalRoute,
  4209. rdi.ViewInfo[0].Route,
  4210. pri,
  4211. NULL ) is NO_ERROR )
  4212. {
  4213. for (ulIdx = 0;
  4214. ulIdx < pri->NextHopsList.NumNextHops;
  4215. ulIdx++)
  4216. {
  4217. if ( RtmGetNextHopInfo( g_hLocalRoute,
  4218. pri->NextHopsList.NextHops[ulIdx],
  4219. &nhi ) is NO_ERROR )
  4220. {
  4221. if ( RmHasBoundary( nhi.InterfaceIndex,
  4222. MzapRelativeGroup(pScope) ))
  4223. {
  4224. MakeAddressStringW(g_AddrBuf1,
  4225. mh->ipMessageOrigin);
  4226. Trace2( ERR,
  4227. "ERROR: non-convex scope zone for '%ls', router %ls",
  4228. GetDefaultName(pScope),
  4229. g_AddrBuf1 );
  4230. RouterLogEventExW( LOGHANDLE,
  4231. EVENTLOG_ERROR_TYPE,
  4232. 0,
  4233. ROUTERLOG_NONCONVEX_SCOPE_ZONE,
  4234. L"%S%S",
  4235. GetDefaultName(pScope),
  4236. g_AddrBuf1
  4237. );
  4238. }
  4239. RtmReleaseNextHopInfo( g_hLocalRoute, &nhi);
  4240. }
  4241. }
  4242. RtmReleaseRouteInfo( g_hLocalRoute, pri );
  4243. }
  4244. RtmReleaseDestInfo(g_hLocalRoute, &rdi);
  4245. }
  4246. HeapFree(IPRouterHeap, 0, pri);
  4247. #endif /* HAVE_RTMV2 */
  4248. // See if scope names don't match
  4249. CheckForScopeNameMismatch(pScope, mh);
  4250. }
  4251. }
  4252. else
  4253. {
  4254. //
  4255. // Check for conflicting address ranges. A scope conflicts
  4256. // if any locally-configured scope's range overlaps that in the ZAM.
  4257. //
  4258. CheckForScopeRangeMismatch(mh);
  4259. }
  4260. }
  4261. EXIT_LOCK(BOUNDARY_TABLE);
  4262. }
  4263. void
  4264. HandleZLE(
  4265. IN PBYTE pBuffer,
  4266. IN ULONG ulBuffLen
  4267. )
  4268. /*++
  4269. Called by:
  4270. HandleMZAPSocket()
  4271. Locks:
  4272. BOUNDARY_TABLE for reading
  4273. ZLE_LIST for writing
  4274. --*/
  4275. {
  4276. PBYTE pb;
  4277. IPV4_MZAP_HEADER *mh;
  4278. IPV4_ZAM_HEADER *zam;
  4279. PSCOPE_ENTRY pScope;
  4280. ZLE_PENDING *zle;
  4281. ULONG ulIdx;
  4282. mh = (PIPV4_MZAP_HEADER)pBuffer;
  4283. // Set pb to end of MZAP header
  4284. pb = pBuffer + sizeof(IPV4_MZAP_HEADER);
  4285. for (ulIdx=0; ulIdx < mh->byNameCount; ulIdx++)
  4286. {
  4287. // skip flags
  4288. pb ++;
  4289. // skip language tag len and str
  4290. pb += (1 + *pb);
  4291. // skip scope name len and ptr
  4292. pb += (1 + *pb);
  4293. }
  4294. //
  4295. // Note that casting to a ULONG is safe, since we only care about
  4296. // the low-order bits anyway.
  4297. //
  4298. while (((ULONG_PTR)pb) & 3)
  4299. *pb++ = '\0';
  4300. zam = (PIPV4_ZAM_HEADER)pb;
  4301. ENTER_READER(BOUNDARY_TABLE);
  4302. {
  4303. // Find matching scope entry
  4304. pScope = FindScope( mh->ipScopeStart,
  4305. ~(mh->ipScopeEnd - mh->ipScopeStart) );
  4306. //
  4307. // ZLE's are multicast. If we are the "Message Origin", signal a
  4308. // leaky scope warning. Display addresses of routers in the path list.
  4309. //
  4310. if (mh->ipMessageOrigin == g_ipMyAddress)
  4311. {
  4312. ReportLeakyScope(pScope, mh, zam);
  4313. EXIT_LOCK(BOUNDARY_TABLE);
  4314. return;
  4315. }
  4316. }
  4317. EXIT_LOCK(BOUNDARY_TABLE);
  4318. // Otherwise, abort any pending ZLE which matches the one received
  4319. ENTER_WRITER(ZLE_LIST);
  4320. {
  4321. if ((zle = FindPendingZLE(mh)) isnot NULL)
  4322. {
  4323. DeletePendingZLE(zle);
  4324. }
  4325. }
  4326. EXIT_LOCK(ZLE_LIST);
  4327. }
  4328. VOID
  4329. HandleMZAPSocket(
  4330. PBOUNDARY_IF pBIf,
  4331. SOCKET s
  4332. )
  4333. /*++
  4334. Description:
  4335. Receive an MZAP message on a socket s, and dispatch it to the
  4336. appropriate function.
  4337. Called by:
  4338. HandleMZAPMessages()
  4339. Locks:
  4340. Assumes caller holds read lock on BOUNDARY_TABLE if pBIf is non-NULL
  4341. --*/
  4342. {
  4343. IPV4_MZAP_HEADER *mh;
  4344. DWORD dwErr, dwNumBytes, dwFlags, dwAddrLen, dwSizeOfHeader;
  4345. DWORD dwDataLen;
  4346. SOCKADDR_IN sinFrom;
  4347. WSANETWORKEVENTS wsaNetworkEvents;
  4348. if (s is INVALID_SOCKET)
  4349. return;
  4350. if (WSAEnumNetworkEvents( s,
  4351. NULL,
  4352. &wsaNetworkEvents) is SOCKET_ERROR)
  4353. {
  4354. dwErr = GetLastError();
  4355. Trace1(ERR,
  4356. "HandleMZAPMessages: WSAEnumNetworkEvents() returned %d",
  4357. dwErr);
  4358. return;
  4359. }
  4360. if (!(wsaNetworkEvents.lNetworkEvents & FD_READ))
  4361. {
  4362. return;
  4363. }
  4364. if (wsaNetworkEvents.iErrorCode[FD_READ_BIT] isnot NO_ERROR)
  4365. {
  4366. Trace1( ERR,
  4367. "HandleMZAPMessages: Error %d on FD_READ",
  4368. wsaNetworkEvents.iErrorCode[FD_READ_BIT] );
  4369. return;
  4370. }
  4371. //
  4372. // read the incoming packet. If the buffer isn't big enough,
  4373. // WSAEMSGSIZE will be returned, and we'll ignore the message.
  4374. // We don't currently expect this will ever happen.
  4375. //
  4376. dwAddrLen = sizeof(sinFrom);
  4377. dwFlags = 0;
  4378. dwErr = WSARecvFrom( s,
  4379. &g_wsaMcRcvBuf,
  4380. 1,
  4381. &dwNumBytes,
  4382. &dwFlags,
  4383. (SOCKADDR FAR *)&sinFrom,
  4384. &dwAddrLen,
  4385. NULL,
  4386. NULL );
  4387. //
  4388. // check if any error in reading packet
  4389. //
  4390. if ((dwErr!=0) || (dwNumBytes==0))
  4391. {
  4392. dwErr = WSAGetLastError();
  4393. Trace1( MCAST,
  4394. "HandleMZAPSocket: Error %d receiving MZAP message",
  4395. dwErr);
  4396. // LogErr1(RECVFROM_FAILED, lpszAddr, dwErr);
  4397. return;
  4398. }
  4399. mh = (PIPV4_MZAP_HEADER)g_wsaMcRcvBuf.buf;
  4400. if (mh->byVersion isnot MZAP_VERSION)
  4401. return;
  4402. #ifdef DEBUG_MZAP
  4403. Trace4( MCAST,
  4404. "HandleMZAPSocket: received type %x len %d IF %x from %d.%d.%d.%d",
  4405. mh->byBPType,
  4406. dwNumBytes,
  4407. ((pBIf)? pBIf->dwIfIndex : 0),
  4408. PRINT_IPADDR(mh->ipMessageOrigin) );
  4409. #endif
  4410. switch(mh->byBPType & ~MZAP_BIG_BIT) {
  4411. case PTYPE_ZAM:
  4412. HandleZAM(g_wsaMcRcvBuf.buf, dwNumBytes, pBIf);
  4413. break;
  4414. case PTYPE_ZLE:
  4415. HandleZLE(g_wsaMcRcvBuf.buf, dwNumBytes);
  4416. break;
  4417. case PTYPE_ZCM:
  4418. HandleZCM(g_wsaMcRcvBuf.buf, dwNumBytes, pBIf);
  4419. break;
  4420. }
  4421. return;
  4422. }
  4423. VOID
  4424. HandleMZAPMessages()
  4425. /*++
  4426. Called by:
  4427. WorkerThread() in worker.c
  4428. Locks:
  4429. BOUNDARY_TABLE for reading
  4430. --*/
  4431. {
  4432. DWORD dwBucketIdx;
  4433. PLIST_ENTRY pleNode;
  4434. TraceEnter("HandleMZAPMessages");
  4435. ENTER_READER(BOUNDARY_TABLE);
  4436. {
  4437. // Check local socket
  4438. HandleMZAPSocket(NULL, g_mzapLocalSocket);
  4439. // Loop through all BIf entries...
  4440. for (dwBucketIdx = 0;
  4441. dwBucketIdx < BOUNDARY_HASH_TABLE_SIZE;
  4442. dwBucketIdx++)
  4443. {
  4444. for (pleNode = g_bbScopeTable[dwBucketIdx].leInterfaceList.Flink;
  4445. pleNode isnot & g_bbScopeTable[dwBucketIdx].leInterfaceList;
  4446. pleNode = pleNode->Flink)
  4447. {
  4448. PBOUNDARY_IF pBIf = CONTAINING_RECORD( pleNode,
  4449. BOUNDARY_IF,
  4450. leBoundaryIfLink );
  4451. HandleMZAPSocket(pBIf, pBIf->sMzapSocket);
  4452. }
  4453. }
  4454. }
  4455. EXIT_LOCK(BOUNDARY_TABLE);
  4456. TraceLeave("HandleMZAPMessages");
  4457. }
  4458. //////////////////////////////////////////////////////////////////////////////
  4459. // Functions for timer events
  4460. //////////////////////////////////////////////////////////////////////////////
  4461. DWORD
  4462. UpdateMzapTimer()
  4463. /*++
  4464. Called by:
  4465. AddZBR(), HandleZAM(), HandleMzapTimer()
  4466. Locks:
  4467. Assumes caller has write lock on MZAP_TIMER
  4468. --*/
  4469. {
  4470. DWORD dwErr = NO_ERROR;
  4471. LARGE_INTEGER liExpiryTime;
  4472. PLIST_ENTRY pleNode;
  4473. TraceEnter("UpdateMzapTimer");
  4474. //
  4475. // Expiry time of next ZAM/ZCM advertisement is already in
  4476. // g_liZamExpiryTime
  4477. //
  4478. liExpiryTime = g_liZamExpiryTime;
  4479. //
  4480. // Get expiry time of first ZBR
  4481. //
  4482. if (!IsListEmpty( &g_zbrTimerList ))
  4483. {
  4484. ZBR_ENTRY *pZbr;
  4485. pleNode = g_zbrTimerList.Flink;
  4486. pZbr = CONTAINING_RECORD(pleNode, ZBR_ENTRY, leTimerLink);
  4487. if (RtlLargeIntegerLessThan(pZbr->liExpiryTime, liExpiryTime))
  4488. {
  4489. liExpiryTime = pZbr->liExpiryTime;
  4490. }
  4491. }
  4492. //
  4493. // Get expiry time of first ZLE
  4494. //
  4495. if (!IsListEmpty( &g_zleTimerList ))
  4496. {
  4497. ZLE_PENDING *zle;
  4498. pleNode = g_zleTimerList.Flink;
  4499. zle = CONTAINING_RECORD(pleNode, ZLE_PENDING, leTimerLink);
  4500. if (RtlLargeIntegerLessThan(zle->liExpiryTime, liExpiryTime))
  4501. {
  4502. liExpiryTime = zle->liExpiryTime;
  4503. }
  4504. }
  4505. //
  4506. // Reset the event timer
  4507. //
  4508. if (!SetWaitableTimer( g_hMzapTimer,
  4509. &liExpiryTime,
  4510. 0,
  4511. NULL,
  4512. NULL,
  4513. FALSE ))
  4514. {
  4515. dwErr = GetLastError();
  4516. Trace1( ERR,
  4517. "UpdateMzapTimer: Error %d setting timer",
  4518. dwErr );
  4519. }
  4520. TraceLeave("UpdateMzapTimer");
  4521. return dwErr;
  4522. }
  4523. VOID
  4524. HandleMzapTimer(
  4525. VOID
  4526. )
  4527. /*++
  4528. Description:
  4529. Process all events which are now due
  4530. Locks:
  4531. MZAP_TIMER and then ZBR_LIST for writing
  4532. --*/
  4533. {
  4534. LARGE_INTEGER liCurrentTime;
  4535. PLIST_ENTRY pleNode;
  4536. BOOL bDidSomething;
  4537. TraceEnter("HandleMzapTimer");
  4538. ENTER_WRITER(MZAP_TIMER);
  4539. do
  4540. {
  4541. bDidSomething = FALSE;
  4542. NtQuerySystemTime(&liCurrentTime);
  4543. //
  4544. // Process timing out ZBRs if due
  4545. //
  4546. ENTER_WRITER(ZBR_LIST);
  4547. {
  4548. for ( pleNode = g_zbrTimerList.Flink;
  4549. pleNode isnot &g_zbrTimerList;
  4550. pleNode = g_zbrTimerList.Flink)
  4551. {
  4552. ZBR_ENTRY *pZbr;
  4553. pZbr = CONTAINING_RECORD(pleNode, ZBR_ENTRY, leTimerLink);
  4554. if (RtlLargeIntegerLessThan(liCurrentTime, pZbr->liExpiryTime))
  4555. break;
  4556. DeleteZBR(pZbr);
  4557. bDidSomething = TRUE;
  4558. }
  4559. }
  4560. EXIT_LOCK(ZBR_LIST);
  4561. //
  4562. // Process sending ZAM/ZCMs if due
  4563. //
  4564. if (RtlLargeIntegerGreaterThanOrEqualTo(liCurrentTime,
  4565. g_liZamExpiryTime))
  4566. {
  4567. SendAllZamsAndZcms();
  4568. bDidSomething = TRUE;
  4569. }
  4570. //
  4571. // Process sending ZLEs if due
  4572. //
  4573. ENTER_WRITER(ZLE_LIST);
  4574. {
  4575. for ( pleNode = g_zleTimerList.Flink;
  4576. pleNode isnot &g_zleTimerList;
  4577. pleNode = g_zleTimerList.Flink)
  4578. {
  4579. ZLE_PENDING *zle;
  4580. zle = CONTAINING_RECORD(pleNode, ZLE_PENDING, leTimerLink);
  4581. if (RtlLargeIntegerLessThan(liCurrentTime, zle->liExpiryTime))
  4582. break;
  4583. SendZLE( zle );
  4584. bDidSomething = TRUE;
  4585. }
  4586. }
  4587. EXIT_LOCK(ZLE_LIST);
  4588. } while (bDidSomething);
  4589. // Reset the timer
  4590. UpdateMzapTimer();
  4591. EXIT_LOCK(MZAP_TIMER);
  4592. TraceLeave("HandleMzapTimer");
  4593. }
  4594. //////////////////////////////////////////////////////////////////////////////
  4595. DWORD
  4596. ActivateMZAP()
  4597. /*++
  4598. Called by:
  4599. StartMZAP(), BindBoundaryInterface()
  4600. --*/
  4601. {
  4602. DWORD dwErr = NO_ERROR;
  4603. DWORD dwBucketIdx;
  4604. PLIST_ENTRY pleNode;
  4605. BOOL bOption;
  4606. SOCKADDR_IN sinAddr;
  4607. TraceEnter("ActivateMZAP");
  4608. g_ipMyLocalZoneID = g_ipMyAddress;
  4609. MzapInitLocalScope();
  4610. // Start listening for MZAP messages
  4611. g_mzapLocalSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
  4612. if (g_mzapLocalSocket is INVALID_SOCKET)
  4613. {
  4614. dwErr = WSAGetLastError();
  4615. Trace1(ERR, "ActivateMZAP: error %d creating socket", dwErr);
  4616. TraceLeave("ActivateMZAP");
  4617. return dwErr;
  4618. }
  4619. if (WSAEventSelect( g_mzapLocalSocket,
  4620. g_hMzapSocketEvent,
  4621. FD_READ) is SOCKET_ERROR)
  4622. {
  4623. dwErr = WSAGetLastError();
  4624. Trace1(ERR,
  4625. "ActivateMZAP: WSAEventSelect failed for local socket, Err=%d",
  4626. dwErr);
  4627. closesocket( g_mzapLocalSocket );
  4628. g_mzapLocalSocket = INVALID_SOCKET;
  4629. TraceLeave("ActivateMZAP");
  4630. return dwErr;
  4631. }
  4632. bOption = TRUE;
  4633. if(setsockopt(g_mzapLocalSocket,
  4634. SOL_SOCKET,
  4635. SO_REUSEADDR,
  4636. (const char FAR*)&bOption,
  4637. sizeof(BOOL)) is SOCKET_ERROR)
  4638. {
  4639. Trace1(ERR,
  4640. "ActivateMZAP: Couldn't set reuse option - continuing. Error %d",
  4641. WSAGetLastError());
  4642. }
  4643. // Bind to INADDR_ANY/MZAP_PORT to get ZLEs
  4644. sinAddr.sin_family = AF_INET;
  4645. sinAddr.sin_addr.s_addr = INADDR_ANY;
  4646. sinAddr.sin_port = htons(MZAP_PORT);
  4647. if (bind(g_mzapLocalSocket, (struct sockaddr*)&sinAddr, sizeof(sinAddr))
  4648. is SOCKET_ERROR)
  4649. {
  4650. dwErr = WSAGetLastError();
  4651. Trace2(ERR, "ActivateMZAP: error %d binding to port %d", dwErr, MZAP_PORT);
  4652. TraceLeave("ActivateMZAP");
  4653. return dwErr;
  4654. }
  4655. // Set TTL to 255
  4656. if (McSetMulticastTtl( g_mzapLocalSocket, 255 ) is SOCKET_ERROR)
  4657. {
  4658. Trace1(ERR,
  4659. "ActivateMZAP: Couldn't set TTL. Error %d",
  4660. WSAGetLastError());
  4661. }
  4662. ENTER_READER(BOUNDARY_TABLE);
  4663. {
  4664. //
  4665. // Join MZAP_RELATIVE_GROUPs locally, to get ZCMs
  4666. //
  4667. for (pleNode = g_MasterScopeList.Flink;
  4668. pleNode isnot &g_MasterScopeList;
  4669. pleNode = pleNode->Flink)
  4670. {
  4671. SCOPE_ENTRY *pScope = CONTAINING_RECORD(pleNode, SCOPE_ENTRY,
  4672. leScopeLink);
  4673. if (McJoinGroup( g_mzapLocalSocket,
  4674. MzapRelativeGroup(pScope),
  4675. g_ipMyAddress ) is SOCKET_ERROR)
  4676. {
  4677. dwErr = WSAGetLastError();
  4678. Trace3( ERR,
  4679. "Error %d joining %d.%d.%d.%d on %d.%d.%d.%d",
  4680. dwErr,
  4681. PRINT_IPADDR(MzapRelativeGroup(pScope)),
  4682. PRINT_IPADDR(g_ipMyAddress) );
  4683. EXIT_LOCK(BOUNDARY_TABLE);
  4684. TraceLeave("ActivateMZAP");
  4685. return dwErr;
  4686. }
  4687. }
  4688. //
  4689. // Join MZAP_LOCAL_GROUP in each local zone we connect to, to get ZAMs
  4690. //
  4691. if (McJoinGroup( g_mzapLocalSocket,
  4692. MZAP_LOCAL_GROUP,
  4693. g_ipMyAddress ) is SOCKET_ERROR)
  4694. {
  4695. dwErr = WSAGetLastError();
  4696. Trace3( ERR,
  4697. "Error %d joining %d.%d.%d.%d on %d.%d.%d.%d",
  4698. dwErr,
  4699. PRINT_IPADDR(MZAP_LOCAL_GROUP),
  4700. PRINT_IPADDR(g_ipMyAddress) );
  4701. EXIT_LOCK(BOUNDARY_TABLE);
  4702. TraceLeave("ActivateMZAP");
  4703. return dwErr;
  4704. }
  4705. for (dwBucketIdx = 0;
  4706. dwBucketIdx < BOUNDARY_HASH_TABLE_SIZE;
  4707. dwBucketIdx++)
  4708. {
  4709. for (pleNode = g_bbScopeTable[dwBucketIdx].leInterfaceList.Flink;
  4710. pleNode isnot & g_bbScopeTable[dwBucketIdx].leInterfaceList;
  4711. pleNode = pleNode->Flink)
  4712. {
  4713. PBOUNDARY_IF pBIf = CONTAINING_RECORD( pleNode,
  4714. BOUNDARY_IF,
  4715. leBoundaryIfLink );
  4716. if ( pBIf->sMzapSocket is INVALID_SOCKET )
  4717. {
  4718. // Interface is not yet active. The join will be
  4719. // done at the time BindBoundaryInterface() is called
  4720. continue;
  4721. }
  4722. if (McJoinGroupByIndex( pBIf->sMzapSocket,
  4723. SOCK_DGRAM,
  4724. MZAP_LOCAL_GROUP,
  4725. pBIf->dwIfIndex ) is SOCKET_ERROR)
  4726. {
  4727. dwErr = WSAGetLastError();
  4728. Trace3( ERR,
  4729. "Error %d joining %d.%d.%d.%d on IF %x",
  4730. dwErr,
  4731. PRINT_IPADDR(MZAP_LOCAL_GROUP),
  4732. pBIf->dwIfIndex );
  4733. EXIT_LOCK(BOUNDARY_TABLE);
  4734. TraceLeave("ActivateMZAP");
  4735. return dwErr;
  4736. }
  4737. }
  4738. }
  4739. }
  4740. EXIT_LOCK(BOUNDARY_TABLE);
  4741. //
  4742. // Initialize timer used for sending messages
  4743. //
  4744. ENTER_WRITER(MZAP_TIMER);
  4745. {
  4746. LARGE_INTEGER liCurrentTime, liExpiryTime;
  4747. NtQuerySystemTime( &liCurrentTime );
  4748. g_liZamExpiryTime = RtlLargeIntegerAdd( liCurrentTime,
  4749. RtlConvertUlongToLargeInteger(TM_SECONDS(ZAM_STARTUP_DELAY)) );
  4750. UpdateMzapTimer();
  4751. }
  4752. EXIT_LOCK(MZAP_TIMER);
  4753. TraceLeave("ActivateMZAP");
  4754. return dwErr;
  4755. }
  4756. VOID
  4757. UpdateLowestAddress(
  4758. PIPV4_ADDRESS pIpAddr,
  4759. PICB picb
  4760. )
  4761. {
  4762. ULONG ulIdx;
  4763. for (ulIdx=0; ulIdx<picb->dwNumAddresses; ulIdx++)
  4764. {
  4765. if (IS_ROUTABLE(picb->pibBindings[ulIdx].dwAddress)
  4766. && (!*pIpAddr ||
  4767. ntohl(picb->pibBindings[ulIdx].dwAddress)
  4768. < ntohl(*pIpAddr)))
  4769. {
  4770. *pIpAddr = picb->pibBindings[ulIdx].dwAddress;
  4771. }
  4772. }
  4773. }
  4774. DWORD
  4775. MzapActivateBIf(
  4776. PBOUNDARY_IF pBIf
  4777. )
  4778. /*++
  4779. Called by:
  4780. AddBIfEntry(), BindBoundaryInterface()
  4781. Locks:
  4782. Assumes caller holds at least a read lock on BOUNDARY_TABLE
  4783. --*/
  4784. {
  4785. BOOL bOption;
  4786. DWORD dwErr = NO_ERROR;
  4787. pBIf->sMzapSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
  4788. if ( pBIf->sMzapSocket is INVALID_SOCKET )
  4789. {
  4790. dwErr = WSAGetLastError();
  4791. Trace1(ERR, "StartMZAP: error %d creating socket", dwErr);
  4792. return dwErr;
  4793. }
  4794. if (setsockopt( pBIf->sMzapSocket,
  4795. SOL_SOCKET,
  4796. SO_REUSEADDR,
  4797. (const char FAR*)&bOption,
  4798. sizeof(BOOL)) is SOCKET_ERROR)
  4799. {
  4800. Trace1(ERR,
  4801. "MzapInitBIf: Couldn't set reuse option - continuing. Error %d",
  4802. WSAGetLastError());
  4803. }
  4804. #if 1
  4805. {
  4806. struct sockaddr_in sinAddr;
  4807. //
  4808. // WORKAROUND FOR BUG #222214: must bind before set TTL will work
  4809. //
  4810. sinAddr.sin_family = AF_INET;
  4811. sinAddr.sin_addr.s_addr = INADDR_ANY;
  4812. sinAddr.sin_port = htons(MZAP_PORT);
  4813. if (bind( pBIf->sMzapSocket,
  4814. (struct sockaddr*)&sinAddr,
  4815. sizeof(sinAddr) ) is SOCKET_ERROR)
  4816. {
  4817. dwErr = WSAGetLastError();
  4818. Trace2( ERR,
  4819. "StartMZAP: error %d binding boundary socket to port %d",
  4820. dwErr,
  4821. MZAP_PORT);
  4822. return dwErr;
  4823. }
  4824. }
  4825. #endif
  4826. // Set TTL to 255
  4827. if (McSetMulticastTtl( pBIf->sMzapSocket, 255) is SOCKET_ERROR)
  4828. {
  4829. Trace1(ERR,
  4830. "StartMZAP: Couldn't set TTL. Error %d",
  4831. WSAGetLastError());
  4832. }
  4833. if (WSAEventSelect( pBIf->sMzapSocket,
  4834. g_hMzapSocketEvent,
  4835. FD_READ) is SOCKET_ERROR)
  4836. {
  4837. dwErr = WSAGetLastError();
  4838. Trace1(ERR,
  4839. "StartMZAP: WSAEventSelect failed for local socket, Err=%d",
  4840. dwErr);
  4841. closesocket( pBIf->sMzapSocket );
  4842. pBIf->sMzapSocket = INVALID_SOCKET;
  4843. return dwErr;
  4844. }
  4845. if (g_bMzapStarted)
  4846. {
  4847. if (McJoinGroupByIndex( pBIf->sMzapSocket,
  4848. SOCK_DGRAM,
  4849. MZAP_LOCAL_GROUP,
  4850. pBIf->dwIfIndex ) is SOCKET_ERROR)
  4851. {
  4852. dwErr = WSAGetLastError();
  4853. Trace3( ERR,
  4854. "Error %d joining %d.%d.%d.%d on IF %x",
  4855. dwErr,
  4856. PRINT_IPADDR(MZAP_LOCAL_GROUP),
  4857. pBIf->dwIfIndex );
  4858. }
  4859. }
  4860. return dwErr;
  4861. }
  4862. DWORD
  4863. BindBoundaryInterface(
  4864. PICB picb
  4865. )
  4866. {
  4867. DWORD dwErr = NO_ERROR;
  4868. ULONG ulIdx;
  4869. BOUNDARY_IF *pBif;
  4870. TraceEnter("BindBoundaryInterface");
  4871. if (!g_bMzapStarted)
  4872. return NO_ERROR;
  4873. ENTER_READER(BOUNDARY_TABLE);
  4874. {
  4875. pBif = FindBIfEntry(picb->dwIfIndex);
  4876. if ( ! g_ipMyAddress && ! pBif )
  4877. {
  4878. UpdateLowestAddress(&g_ipMyAddress, picb);
  4879. if (g_ipMyAddress)
  4880. dwErr = ActivateMZAP();
  4881. }
  4882. if ( pBif && (pBif->sMzapSocket is INVALID_SOCKET))
  4883. {
  4884. dwErr = MzapActivateBIf(pBif );
  4885. }
  4886. }
  4887. EXIT_LOCK(BOUNDARY_TABLE);
  4888. TraceLeave("BindBoundaryInterface");
  4889. return dwErr;
  4890. }
  4891. DWORD
  4892. StartMZAP()
  4893. /*++
  4894. Description:
  4895. Initialize state and start running MZAP()
  4896. Called by:
  4897. SetScopeInfo()
  4898. Locks:
  4899. ICB_LIST for reading
  4900. BOUNDARY_TABLE for reading
  4901. --*/
  4902. {
  4903. DWORD dwErr = NO_ERROR,
  4904. dwBucketIdx;
  4905. SOCKADDR_IN sinAddr;
  4906. ULONG ulIdx;
  4907. PLIST_ENTRY pleNode;
  4908. PSCOPE_ENTRY pScope;
  4909. BOOL bOption;
  4910. if (g_bMzapStarted)
  4911. return NO_ERROR;
  4912. g_bMzapStarted = TRUE;
  4913. // Initialize local data structures
  4914. InitializeListHead( &g_leZamCache );
  4915. InitializeListHead( &g_leZleList );
  4916. InitializeListHead( &g_zbrTimerList );
  4917. InitializeListHead( &g_zleTimerList );
  4918. //
  4919. // Set address to lowest routable IP address which has no boundary
  4920. // configured on it.
  4921. //
  4922. ENTER_READER(ICB_LIST);
  4923. {
  4924. PICB picb;
  4925. for (pleNode = ICBList.Flink;
  4926. pleNode isnot &ICBList;
  4927. pleNode = pleNode->Flink)
  4928. {
  4929. picb = CONTAINING_RECORD(pleNode, ICB, leIfLink);
  4930. if (FindBIfEntry(picb->dwIfIndex))
  4931. continue;
  4932. UpdateLowestAddress(&g_ipMyAddress, picb);
  4933. }
  4934. }
  4935. EXIT_LOCK(ICB_LIST);
  4936. if (!g_ipMyAddress)
  4937. {
  4938. Trace0(ERR, "StartMZAP: no IP address found in local scope");
  4939. return ERROR_NOT_SUPPORTED;
  4940. }
  4941. dwErr = ActivateMZAP();
  4942. return dwErr;
  4943. }
  4944. void
  4945. StopMZAP()
  4946. /*++
  4947. Called by:
  4948. SetScopeInfo()
  4949. --*/
  4950. {
  4951. if (!g_bMzapStarted)
  4952. return;
  4953. g_bMzapStarted = FALSE;
  4954. // Stop timer used for sending messages
  4955. ENTER_WRITER(MZAP_TIMER);
  4956. {
  4957. CancelWaitableTimer(g_hMzapTimer);
  4958. }
  4959. EXIT_LOCK(MZAP_TIMER);
  4960. // Stop listening for MZAP messages
  4961. if (g_mzapLocalSocket isnot INVALID_SOCKET)
  4962. {
  4963. closesocket(g_mzapLocalSocket);
  4964. g_mzapLocalSocket = INVALID_SOCKET;
  4965. }
  4966. //
  4967. // Free up local data stores
  4968. // Empty ZAM cache
  4969. //
  4970. ENTER_WRITER(ZAM_CACHE);
  4971. UpdateZamCache(RtlConvertUlongToLargeInteger(0));
  4972. EXIT_LOCK(ZAM_CACHE);
  4973. }
  4974. VOID
  4975. MzapInitScope(
  4976. PSCOPE_ENTRY pScope
  4977. )
  4978. /*++
  4979. Description:
  4980. Initialize MZAP fields of a scope
  4981. --*/
  4982. {
  4983. pScope->ipMyZoneID = g_ipMyLocalZoneID;
  4984. InitializeListHead(&pScope->leZBRList);
  4985. pScope->bZTL = MZAP_DEFAULT_ZTL;
  4986. pScope->ulNumInterfaces = 0;
  4987. pScope->bDivisible = FALSE;
  4988. }
  4989. DWORD
  4990. MzapInitBIf(
  4991. PBOUNDARY_IF pBIf
  4992. )
  4993. /*++
  4994. Description:
  4995. Called when the first boundary is added to an interface, and we
  4996. need to start up MZAP on it. MZAP may (if we add a boundary
  4997. while the router is running) or may not (startup time) already be
  4998. running at this point.
  4999. Called by:
  5000. AddBIfEntry()
  5001. Locks:
  5002. Assumes caller holds a write lock on BOUNDARY_TABLE
  5003. --*/
  5004. {
  5005. BOOL bOption;
  5006. DWORD dwErr = NO_ERROR;
  5007. pBIf->ipOtherLocalZoneID = 0;
  5008. pBIf->sMzapSocket = INVALID_SOCKET;
  5009. return dwErr;
  5010. }
  5011. VOID
  5012. MzapUninitBIf(
  5013. PBOUNDARY_IF pBIf
  5014. )
  5015. /*++
  5016. Called by:
  5017. --*/
  5018. {
  5019. if ( pBIf->sMzapSocket isnot INVALID_SOCKET )
  5020. {
  5021. closesocket( pBIf->sMzapSocket );
  5022. pBIf->sMzapSocket = INVALID_SOCKET;
  5023. }
  5024. }