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

2990 lines
80 KiB

  1. /*++
  2. Copyright(c) 2000 Microsoft Corporation
  3. Module Name:
  4. brdgsta.c
  5. Abstract:
  6. Ethernet MAC level bridge.
  7. Spanning Tree Algorithm section
  8. Author:
  9. Mark Aiken
  10. Environment:
  11. Kernel mode driver
  12. Revision History:
  13. June 2000 - Original version
  14. --*/
  15. #define NDIS_MINIPORT_DRIVER
  16. #define NDIS50_MINIPORT 1
  17. #define NDIS_WDM 1
  18. #pragma warning( push, 3 )
  19. #include <ndis.h>
  20. #pragma warning( pop )
  21. #include "bridge.h"
  22. #include "brdgsta.h"
  23. #include "brdgmini.h"
  24. #include "brdgprot.h"
  25. #include "brdgbuf.h"
  26. #include "brdgfwd.h"
  27. #include "brdgtbl.h"
  28. #include "brdgctl.h"
  29. // ===========================================================================
  30. //
  31. // TYPES
  32. //
  33. // ===========================================================================
  34. // BPDU types
  35. typedef enum
  36. {
  37. ConfigBPDU,
  38. TopologyChangeBPDU
  39. } BPDU_TYPE;
  40. // ===========================================================================
  41. //
  42. // CONSTANTS
  43. //
  44. // ===========================================================================
  45. // These values measured in STA units (1/256ths of a second)
  46. #define DEFAULT_MAX_AGE (8 * 256) // 8 seconds
  47. #define DEFAULT_HELLO_TIME (2 * 256) // 2 seconds
  48. #define DEFAULT_FORWARD_DELAY (5 * 256) // 5 seconds
  49. #define MESSAGE_AGE_INCREMENT 1 // 1 STA time unit
  50. // These values measured in milliseconds
  51. #define HOLD_TIMER_PERIOD (1 * 1000) // 1 second in milliseconds
  52. // Normal size, in bytes, of a full-size (non-TCN) STA packet
  53. #define CONFIG_BPDU_PACKET_SIZE 35
  54. // Size, in bytes, of a TCN STA packet
  55. #define TCN_BPDU_PACKET_SIZE 4
  56. // The name of the registry entry that causes the STA to be disabled
  57. const PWCHAR gDisableSTAParameterName = L"DisableSTA";
  58. // The size of an 802.3 header with LLC
  59. #define _802_3_HEADER_SIZE 17
  60. // Value to be added to port IDs; must leave the bottom byte clear to store
  61. // actual port ID
  62. #define PORT_PRIORITY 0x8000
  63. // ===========================================================================
  64. //
  65. // STRUCTURES
  66. //
  67. // ===========================================================================
  68. //
  69. // This structure holds the information for a complete BPDU (although
  70. // it is not laid out as the BPDU is actually transmitted on the wire)
  71. //
  72. typedef struct _CONFIG_BPDU
  73. {
  74. BPDU_TYPE Type;
  75. UCHAR RootID[BRIDGE_ID_LEN];
  76. PATH_COST RootCost;
  77. UCHAR BridgeID[BRIDGE_ID_LEN];
  78. PORT_ID PortID;
  79. STA_TIME MessageAge;
  80. STA_TIME MaxAge;
  81. STA_TIME HelloTime;
  82. STA_TIME ForwardDelay;
  83. BOOLEAN bTopologyChangeAck;
  84. BOOLEAN bTopologyChange;
  85. } CONFIG_BPDU, *PCONFIG_BPDU;
  86. // ===========================================================================
  87. //
  88. // GLOBALS
  89. //
  90. // ===========================================================================
  91. // Global spin lock protects all STA data accesses (for data stored in adapters
  92. // as well as globals)
  93. NDIS_SPIN_LOCK gSTALock;
  94. // The bridge we believe is the root bridge
  95. UCHAR gDesignatedRootID[BRIDGE_ID_LEN];
  96. // Our own unique ID
  97. UCHAR gOurID[BRIDGE_ID_LEN];
  98. // Whether our ID has been set yet
  99. BOOLEAN gHaveID = FALSE;
  100. // Our cost to reach the root
  101. PATH_COST gRootCost = 0;
  102. // Our root port (adapter)
  103. PADAPT gRootAdapter = NULL;
  104. // Whether we have detected a topology change
  105. BOOLEAN gTopologyChangeDetected = FALSE;
  106. // Whether we tell other bridges that the topology has changed
  107. BOOLEAN gTopologyChange = FALSE;
  108. // Current bridge maximum message age
  109. STA_TIME gMaxAge = DEFAULT_MAX_AGE;
  110. // Current bridge Hello time
  111. STA_TIME gHelloTime = DEFAULT_HELLO_TIME;
  112. // Current bridge forward delay
  113. STA_TIME gForwardDelay = DEFAULT_FORWARD_DELAY;
  114. // Every adapter must have a unique ID number, but there is no requirement that
  115. // that number be unique over the lifetime of the bridge. This array is used as
  116. // a bitfield that records which IDs are in use.
  117. ULONG gUsedPortIDs[MAX_ADAPTERS / sizeof(ULONG) / 8];
  118. //
  119. // Timers
  120. //
  121. BRIDGE_TIMER gTopologyChangeTimer;
  122. BRIDGE_TIMER gTopologyChangeNotificationTimer;
  123. BRIDGE_TIMER gHelloTimer;
  124. // TRUE if the STA is disabled for the lifetime of the bridge
  125. BOOLEAN gDisableSTA = FALSE;
  126. // ===========================================================================
  127. //
  128. // PRIVATE PROTOTYPES
  129. //
  130. // ===========================================================================
  131. VOID
  132. BrdgSTARootSelection();
  133. VOID
  134. BrdgSTADesignatedPortSelection();
  135. BOOLEAN
  136. BrdgSTAPortStateSelection();
  137. VOID
  138. BrdgSTAGenerateConfigBPDUs();
  139. VOID
  140. BrdgSTABecomeDesignatedPort(
  141. IN PADAPT pAdapt
  142. );
  143. VOID
  144. BrdgSTAProcessTCNBPDU(
  145. IN PADAPT pAdapt
  146. );
  147. VOID
  148. BrdgSTAProcessConfigBPDU(
  149. IN PADAPT pAdapt,
  150. IN PCONFIG_BPDU pbpdu
  151. );
  152. BOOLEAN
  153. BrdgSTATopologyChangeDetected();
  154. VOID
  155. BrdgSTACopyFromPacketToBuffer(
  156. OUT PUCHAR pPacketOut,
  157. IN ULONG BufferSize,
  158. OUT PULONG pWrittenCount,
  159. IN PNDIS_PACKET pPacketIn
  160. );
  161. VOID
  162. BrdgSTADeferredSetAdapterState(
  163. IN PVOID Arg
  164. );
  165. VOID
  166. BrdgSTAHelloTimerExpiry(
  167. IN PVOID Unused
  168. );
  169. VOID
  170. BrdgSTAMessageAgeTimerExpiry(
  171. IN PVOID Context
  172. );
  173. VOID
  174. BrdgSTAForwardDelayTimerExpiry(
  175. IN PVOID Context
  176. );
  177. VOID
  178. BrdgSTATopologyChangeNotificationTimerExpiry(
  179. IN PVOID Unused
  180. );
  181. VOID
  182. BrdgSTATopologyChangeTimerExpiry(
  183. IN PVOID Unused
  184. );
  185. VOID
  186. BrdgSTAHoldTimerExpiry(
  187. IN PVOID Context
  188. );
  189. VOID
  190. BrdgSTATransmitTCNPacket();
  191. VOID
  192. BrdgSTASetAdapterState(
  193. IN PADAPT pAdapt,
  194. IN PORT_STATE NewState
  195. );
  196. // ===========================================================================
  197. //
  198. // INLINES / MACROS
  199. //
  200. // ===========================================================================
  201. //
  202. // Does a complete re-evaluation of STA info
  203. //
  204. // ASSUMES the caller has acquired gSTALock
  205. //
  206. __forceinline
  207. VOID
  208. BrdgSTAConfigUpdate()
  209. {
  210. BrdgSTARootSelection();
  211. BrdgSTADesignatedPortSelection();
  212. }
  213. //
  214. // Sets an NDIS timer using a time expressed in STA units
  215. //
  216. // No requirements on caller-held locks
  217. //
  218. __forceinline
  219. VOID
  220. BrdgSTASetTimerWithSTATime(
  221. IN PBRIDGE_TIMER pTimer,
  222. IN STA_TIME Time,
  223. IN BOOLEAN bRecurring
  224. )
  225. {
  226. BrdgSetTimer( pTimer, Time * 1000 / 256, bRecurring );
  227. }
  228. //
  229. // Compares two bridge IDs.
  230. //
  231. // -1 : A < B
  232. // 0 : A == B
  233. // 1 : A > B
  234. //
  235. // No requirements on caller-held locks
  236. //
  237. __forceinline
  238. INT
  239. BrdgSTABridgeIDCmp(
  240. IN PUCHAR pIDa,
  241. IN PUCHAR pIDb
  242. )
  243. {
  244. UINT i;
  245. for( i = 0; i < BRIDGE_ID_LEN; i++ )
  246. {
  247. if( pIDa[i] > pIDb[i] )
  248. {
  249. return 1;
  250. }
  251. else if( pIDa[i] < pIDb[i] )
  252. {
  253. return -1;
  254. }
  255. }
  256. return 0;
  257. }
  258. //
  259. // Returns whether or not we currently believe ourselves to be the root
  260. // bridge.
  261. //
  262. // ASSUMES the caller has acquired gSTALock
  263. //
  264. __forceinline
  265. BOOLEAN
  266. BrdgSTAWeAreRoot()
  267. {
  268. SAFEASSERT( gHaveID );
  269. return (BOOLEAN)(BrdgSTABridgeIDCmp( gOurID, gDesignatedRootID ) == 0);
  270. }
  271. //
  272. // Copies a bridge ID from pIDSrc to pIDDest.
  273. //
  274. // No requirements on caller-held locks
  275. //
  276. __forceinline
  277. VOID
  278. BrdgSTACopyID(
  279. IN PUCHAR pIDDest,
  280. IN PUCHAR pIDSrc
  281. )
  282. {
  283. UINT i;
  284. for( i = 0; i < BRIDGE_ID_LEN; i++ )
  285. {
  286. pIDDest[i] = pIDSrc[i];
  287. }
  288. }
  289. //
  290. // Calculates the STA path cost from an adapter's link speed.
  291. // Follows IEEE 802.1D-1990 recommendation that the link cost be set
  292. // to 1000 / (Speed in Mbits/s).
  293. //
  294. // No requirements on caller-held locks
  295. //
  296. __forceinline
  297. PATH_COST
  298. BrdgSTALinkCostFromLinkSpeed(
  299. IN ULONG LinkSpeed
  300. )
  301. {
  302. ULONG retVal;
  303. // Link speed is reported in units of 100bps
  304. if( LinkSpeed == 0L )
  305. {
  306. // Avoid div by zero and return very high path cost
  307. DBGPRINT(STA, ("Zero link speed reported\n"));
  308. retVal = 0xFFFFFFFF;
  309. }
  310. else
  311. {
  312. retVal = (PATH_COST)(10000000L / LinkSpeed);
  313. }
  314. if( retVal == 0L )
  315. {
  316. // STA spec calls for path costs to always be at least 1
  317. return 1L;
  318. }
  319. else
  320. {
  321. return retVal;
  322. }
  323. }
  324. //
  325. // Updates the global gTopologyChange flag. When this flag is set,
  326. // we must use a forwarding table timeout value equal to the bridge's
  327. // current forwarding delay. When the flag is not set, we use
  328. // the table's default timeout value.
  329. //
  330. // ASSUMES the caller has acquired gSTALock
  331. //
  332. __forceinline
  333. VOID
  334. BrdgSTAUpdateTopologyChange(
  335. IN BOOLEAN NewValue
  336. )
  337. {
  338. if( gTopologyChange != NewValue )
  339. {
  340. gTopologyChange = NewValue;
  341. if( gTopologyChange )
  342. {
  343. // Convert the forward delay to ms
  344. BrdgTblSetTimeout( gForwardDelay * 1000 / 256 );
  345. }
  346. else
  347. {
  348. BrdgTblRevertTimeout();
  349. }
  350. }
  351. }
  352. // ===========================================================================
  353. //
  354. // PUBLIC FUNCTIONS
  355. //
  356. // ===========================================================================
  357. VOID
  358. BrdgSTAGetAdapterSTAInfo(
  359. IN PADAPT pAdapt,
  360. PBRIDGE_STA_ADAPTER_INFO pInfo
  361. )
  362. /*++
  363. Routine Description:
  364. Copies STA information for a particular adapter into a structure
  365. Called to collect information for user-mode components
  366. Arguments:
  367. pAdapt The adapter
  368. pInfo Structure to receive STA information
  369. Return Value:
  370. None
  371. Locking Constraints:
  372. Top-level function. Assumes no locks are held by caller.
  373. --*/
  374. {
  375. NdisAcquireSpinLock( &gSTALock );
  376. pInfo->ID = pAdapt->STAInfo.ID;
  377. pInfo->PathCost = pAdapt->STAInfo.PathCost;
  378. BrdgSTACopyID( pInfo->DesignatedRootID, pAdapt->STAInfo.DesignatedRootID );
  379. pInfo->DesignatedCost = pAdapt->STAInfo.DesignatedCost;
  380. BrdgSTACopyID( pInfo->DesignatedBridgeID, pAdapt->STAInfo.DesignatedBridgeID );
  381. pInfo->DesignatedPort = pAdapt->STAInfo.DesignatedPort;
  382. NdisReleaseSpinLock( &gSTALock );
  383. }
  384. VOID
  385. BrdgSTAGetSTAInfo(
  386. PBRIDGE_STA_GLOBAL_INFO pInfo
  387. )
  388. /*++
  389. Routine Description:
  390. Copies global STA information into a structure
  391. Called to collect information for user-mode components
  392. Arguments:
  393. pInfo Structure to receive STA information
  394. Return Value:
  395. None
  396. Locking Constraints:
  397. Top-level function. Assumes no locks are held by caller.
  398. --*/
  399. {
  400. NdisAcquireSpinLock( &gSTALock );
  401. SAFEASSERT( gHaveID );
  402. BrdgSTACopyID( pInfo->OurID, gOurID );
  403. BrdgSTACopyID( pInfo->DesignatedRootID, gDesignatedRootID );
  404. pInfo->RootCost = gRootCost;
  405. pInfo->RootAdapter = (BRIDGE_ADAPTER_HANDLE)gRootAdapter;
  406. pInfo->bTopologyChangeDetected = gTopologyChangeDetected;
  407. pInfo->bTopologyChange = gTopologyChange;
  408. pInfo->MaxAge = gMaxAge;
  409. pInfo->HelloTime = gHelloTime;
  410. pInfo->ForwardDelay = gForwardDelay;
  411. NdisReleaseSpinLock( &gSTALock );
  412. }
  413. VOID
  414. BrdgSTAUpdateAdapterCost(
  415. IN PADAPT pAdapt,
  416. ULONG LinkSpeed
  417. )
  418. /*++
  419. Routine Description:
  420. Updates an adapter's path cost to reflect an updated link speed
  421. Arguments:
  422. pAdapt The adapter
  423. LinkSpeed The adapter's new link speed
  424. Return Value:
  425. None
  426. Locking Constraints:
  427. Top-level function. Assumes no locks are held by caller.
  428. --*/
  429. {
  430. BOOLEAN bTransmitTCN = FALSE;
  431. NdisAcquireSpinLock( &gSTALock );
  432. if( pAdapt->bSTAInited )
  433. {
  434. pAdapt->STAInfo.PathCost = BrdgSTALinkCostFromLinkSpeed(LinkSpeed);
  435. // Do a global re-evaluation of STA info
  436. BrdgSTAConfigUpdate();
  437. bTransmitTCN = BrdgSTAPortStateSelection();
  438. }
  439. else
  440. {
  441. DBGPRINT(STA, ("BrdgSTAUpdateAdapterCost() called with uninitialized adapter; ignoring!\n"));
  442. }
  443. NdisReleaseSpinLock( &gSTALock );
  444. if( bTransmitTCN )
  445. {
  446. BrdgSTATransmitTCNPacket();
  447. }
  448. }
  449. NTSTATUS
  450. BrdgSTADriverInit()
  451. /*++
  452. Routine Description:
  453. Driver load-time initialization
  454. Return Value:
  455. Status of initialization
  456. Locking Constraints:
  457. Top-level function. Assumes no locks are held by caller.
  458. --*/
  459. {
  460. NTSTATUS NtStatus;
  461. UINT i;
  462. ULONG regValue;
  463. NdisAllocateSpinLock( &gSTALock );
  464. BrdgInitializeTimer( &gTopologyChangeTimer, BrdgSTATopologyChangeTimerExpiry, NULL );
  465. BrdgInitializeTimer( &gTopologyChangeNotificationTimer, BrdgSTATopologyChangeNotificationTimerExpiry, NULL );
  466. BrdgInitializeTimer( &gHelloTimer, BrdgSTAHelloTimerExpiry, NULL );
  467. // We haven't used any port IDs yet...
  468. for( i = 0; i < sizeof(gUsedPortIDs) / sizeof(ULONG); i++ )
  469. {
  470. gUsedPortIDs[i] = 0;
  471. }
  472. // Check if we're supposed to disable the STA
  473. NtStatus = BrdgReadRegDWord( &gRegistryPath, gDisableSTAParameterName, &regValue );
  474. if( (NtStatus == STATUS_SUCCESS) &&
  475. (regValue != 0L) )
  476. {
  477. gDisableSTA = TRUE;
  478. DBGPRINT(STA, ("DISABLING SPANNING TREE ALGORITHM\n"));
  479. }
  480. return STATUS_SUCCESS;
  481. }
  482. VOID
  483. BrdgSTADeferredInit(
  484. IN PUCHAR pBridgeMACAddress
  485. )
  486. /*++
  487. Routine Description:
  488. Second initialization pass; called when we determine the bridge's
  489. MAC address (which is needed for STA operations)
  490. Arguments:
  491. pBridgeMACAddress The bridge miniport's MAC address
  492. Return Value:
  493. None
  494. Locking Constraints:
  495. Top-level function. Assumes no locks are held by caller.
  496. --*/
  497. {
  498. UINT i;
  499. // Our identifier consists of our MAC address preceeded with 0x8000
  500. gOurID[0] = 0x80;
  501. gOurID[1] = 0x00;
  502. for( i = BRIDGE_ID_LEN - ETH_LENGTH_OF_ADDRESS; i < BRIDGE_ID_LEN; i++ )
  503. {
  504. gOurID[i] = pBridgeMACAddress[i - (BRIDGE_ID_LEN - ETH_LENGTH_OF_ADDRESS)];
  505. }
  506. // Set the root bridge ID as our own to start out with
  507. BrdgSTACopyID( gDesignatedRootID, gOurID );
  508. gHaveID = TRUE;
  509. if (BrdgFwdBridgingNetworks())
  510. {
  511. // Don't use locks; rely on this function being non-reentrant and always run
  512. // before any other functions
  513. if( BrdgSTAPortStateSelection() )
  514. {
  515. BrdgSTATransmitTCNPacket();
  516. }
  517. BrdgSTAGenerateConfigBPDUs();
  518. BrdgSTASetTimerWithSTATime( &gHelloTimer, gHelloTime, TRUE );
  519. }
  520. }
  521. VOID
  522. BrdgSTACleanup()
  523. /*++
  524. Routine Description:
  525. Driver unload-time cleanup
  526. Return Value:
  527. None
  528. Locking Constraints:
  529. Top-level function. Assumes no locks are held by caller.
  530. --*/
  531. {
  532. BrdgShutdownTimer( &gTopologyChangeTimer );
  533. BrdgShutdownTimer( &gTopologyChangeNotificationTimer );
  534. BrdgShutdownTimer( &gHelloTimer );
  535. }
  536. VOID
  537. BrdgSTAEnableAdapter(
  538. IN PADAPT pAdapt
  539. )
  540. /*++
  541. Routine Description:
  542. Enables STA operations on an adapter. Can be called multiple times
  543. (in conjunction with BrdgSTADisableAdapter()) for a given adapter
  544. Arguments:
  545. pAdapt The adapter
  546. Return Value:
  547. None
  548. Locking Constraints:
  549. Top-level function. Assumes no locks are held by caller.
  550. --*/
  551. {
  552. BOOLEAN bTransmitTCN = FALSE;
  553. DBGPRINT(STA, ("ENABLING adapter %p\n", pAdapt));
  554. NdisAcquireSpinLock( &gSTALock );
  555. if( pAdapt->bSTAInited )
  556. {
  557. BrdgSTABecomeDesignatedPort(pAdapt);
  558. BrdgSTASetAdapterState( pAdapt, Blocking );
  559. pAdapt->STAInfo.bTopologyChangeAck = FALSE;
  560. pAdapt->STAInfo.bConfigPending = FALSE;
  561. bTransmitTCN = BrdgSTAPortStateSelection();
  562. }
  563. else
  564. {
  565. DBGPRINT(STA, ("BrdgSTAEnableAdapter() called with uninitialized adapter; ignoring!\n"));
  566. }
  567. NdisReleaseSpinLock( &gSTALock );
  568. if( bTransmitTCN && BrdgFwdBridgingNetworks())
  569. {
  570. BrdgSTATransmitTCNPacket();
  571. }
  572. }
  573. VOID
  574. BrdgSTAInitializeAdapter(
  575. IN PADAPT pAdapt
  576. )
  577. /*++
  578. Routine Description:
  579. One-time initialization for a new adatper
  580. Arguments:
  581. pAdapt The adapter
  582. Return Value:
  583. None
  584. Locking Constraints:
  585. Top-level function. Assumes no locks are held by caller.
  586. ASSUMES the adapter has already been added to the global list
  587. --*/
  588. {
  589. if( BrdgAcquireAdapter(pAdapt) )
  590. {
  591. UINT i, j;
  592. // Adapters should always be disabled when being initialized, either because they are
  593. // brand new and this is how they start out, or as a way of checking that they were
  594. // correctly stopped when they were last disconnected.
  595. SAFEASSERT( pAdapt->State == Disabled );
  596. pAdapt->STAInfo.PathCost = BrdgSTALinkCostFromLinkSpeed(pAdapt->LinkSpeed);
  597. BrdgInitializeTimer( &pAdapt->STAInfo.MessageAgeTimer, BrdgSTAMessageAgeTimerExpiry, pAdapt );
  598. BrdgInitializeTimer( &pAdapt->STAInfo.ForwardDelayTimer, BrdgSTAForwardDelayTimerExpiry, pAdapt );
  599. BrdgInitializeTimer( &pAdapt->STAInfo.HoldTimer, BrdgSTAHoldTimerExpiry, pAdapt );
  600. pAdapt->STAInfo.LastConfigTime = 0L;
  601. // Find an unused port number in the bitfield
  602. NdisAcquireSpinLock( &gSTALock );
  603. for( i = 0; i < sizeof(gUsedPortIDs) / sizeof(ULONG); i++ )
  604. {
  605. for( j = 0; j < sizeof(ULONG) * 8; j++ )
  606. {
  607. if( (gUsedPortIDs[i] & (1 << j)) == 0 )
  608. {
  609. pAdapt->STAInfo.ID = (PORT_ID)(PORT_PRIORITY | ((i * sizeof(ULONG) * 8) + j));
  610. DBGPRINT(STA, ("Adapter %p gets ID %i\n", pAdapt, pAdapt->STAInfo.ID));
  611. gUsedPortIDs[i] |= (1 << j);
  612. goto doneID;
  613. }
  614. }
  615. }
  616. // Should be impossible to not have an available ID
  617. SAFEASSERT( FALSE );
  618. pAdapt->STAInfo.ID = PORT_PRIORITY | 0xFF;
  619. doneID:
  620. // Set this before releasing the lock
  621. pAdapt->bSTAInited = TRUE;
  622. NdisReleaseSpinLock( &gSTALock );
  623. // Start the adapter off enabled / disabled based on its media state
  624. // The enable / disable functions take locks
  625. if( pAdapt->MediaState == NdisMediaStateConnected )
  626. {
  627. BrdgSTAEnableAdapter( pAdapt );
  628. }
  629. else
  630. {
  631. SAFEASSERT( pAdapt->MediaState == NdisMediaStateDisconnected );
  632. BrdgSTADisableAdapter( pAdapt );
  633. }
  634. }
  635. else
  636. {
  637. SAFEASSERT( FALSE );
  638. }
  639. }
  640. VOID
  641. BrdgSTADisableAdapter(
  642. IN PADAPT pAdapt
  643. )
  644. /*++
  645. Routine Description:
  646. Disable STA operation on an adapter. Can be called multiple times
  647. (in conjunction with BrdgSTAEnableAdapter()) on a given adapter
  648. Arguments:
  649. pAdapt The adapter
  650. Return Value:
  651. None
  652. Locking Constraints:
  653. Top-level function. Assumes no locks are held by caller.
  654. --*/
  655. {
  656. BOOLEAN bWereRoot, bTransmitTCN = FALSE;
  657. DBGPRINT(STA, ("DISABLING adapter %p\n", pAdapt));
  658. NdisAcquireSpinLock( &gSTALock );
  659. if( pAdapt->bSTAInited )
  660. {
  661. bWereRoot = BrdgSTAWeAreRoot();
  662. BrdgSTABecomeDesignatedPort(pAdapt);
  663. BrdgSTASetAdapterState( pAdapt, Disabled );
  664. pAdapt->STAInfo.bTopologyChangeAck = FALSE;
  665. pAdapt->STAInfo.bConfigPending = FALSE;
  666. BrdgCancelTimer( &pAdapt->STAInfo.MessageAgeTimer );
  667. pAdapt->STAInfo.LastConfigTime = 0L;
  668. BrdgCancelTimer( &pAdapt->STAInfo.ForwardDelayTimer );
  669. BrdgSTAConfigUpdate();
  670. bTransmitTCN = BrdgSTAPortStateSelection();
  671. if( BrdgSTAWeAreRoot() && (! bWereRoot) )
  672. {
  673. // We're the root bridge now
  674. DBGPRINT(STA, ("Became root through disabling of adapter %p\n", pAdapt));
  675. gMaxAge = DEFAULT_MAX_AGE;
  676. gHelloTime = DEFAULT_HELLO_TIME;
  677. gForwardDelay = DEFAULT_FORWARD_DELAY;
  678. bTransmitTCN = BrdgSTATopologyChangeDetected();
  679. BrdgCancelTimer( &gTopologyChangeNotificationTimer );
  680. // Don't do packet sends with a spin lock held
  681. NdisReleaseSpinLock( &gSTALock );
  682. if (BrdgFwdBridgingNetworks())
  683. {
  684. BrdgSTAGenerateConfigBPDUs();
  685. BrdgSTASetTimerWithSTATime( &gHelloTimer, gHelloTime, TRUE );
  686. }
  687. }
  688. else
  689. {
  690. NdisReleaseSpinLock( &gSTALock );
  691. }
  692. }
  693. else
  694. {
  695. NdisReleaseSpinLock( &gSTALock );
  696. DBGPRINT(STA, ("BrdgSTADisableAdapter() called with uninitialized adapter; ignoring!\n"));
  697. }
  698. if( bTransmitTCN )
  699. {
  700. BrdgSTATransmitTCNPacket();
  701. }
  702. }
  703. VOID
  704. BrdgSTAShutdownAdapter(
  705. IN PADAPT pAdapt
  706. )
  707. /*++
  708. Routine Description:
  709. One-time teardown of an adapter
  710. Arguments:
  711. pAdapt The adapter
  712. Return Value:
  713. None
  714. Locking Constraints:
  715. Top-level function. Assumes no locks are held by caller.
  716. ASSUMES the adapter has been taken out of the global list
  717. --*/
  718. {
  719. UINT i;
  720. PORT_ID ActualID = pAdapt->STAInfo.ID & (~PORT_PRIORITY);
  721. // Shouldn't be possible to go through a formal shutdown without
  722. // having completed initialization.
  723. SAFEASSERT( pAdapt->bSTAInited );
  724. // Shutdown all this adapter's timers
  725. BrdgShutdownTimer( &pAdapt->STAInfo.HoldTimer );
  726. BrdgShutdownTimer( &pAdapt->STAInfo.ForwardDelayTimer );
  727. BrdgShutdownTimer( &pAdapt->STAInfo.MessageAgeTimer );
  728. // Disable the adapter
  729. BrdgSTADisableAdapter( pAdapt );
  730. // Note that this adapter's port ID is now free
  731. NdisAcquireSpinLock( &gSTALock );
  732. i = (UINT)(ActualID / (sizeof(ULONG) * 8));
  733. SAFEASSERT( i < sizeof(gUsedPortIDs) / sizeof(ULONG) );
  734. gUsedPortIDs[i] &= ~(1 << (ActualID % (sizeof(ULONG) * 8)));
  735. NdisReleaseSpinLock( &gSTALock );
  736. // We're all done with this adapter structure
  737. SAFEASSERT( gRootAdapter != pAdapt );
  738. BrdgReleaseAdapter( pAdapt );
  739. }
  740. VOID
  741. BrdgSTAReceivePacket(
  742. IN PADAPT pAdapt,
  743. IN PNDIS_PACKET pPacket
  744. )
  745. /*++
  746. Routine Description:
  747. Function to handle the processing of a packet received on the reserved
  748. STA multicast channel
  749. Arguments:
  750. pAdapt The adapter the packet was received on
  751. pPacket The received packet
  752. Return Value:
  753. None
  754. Locking Constraints:
  755. Top-level function. Assumes no locks are held by caller.
  756. --*/
  757. {
  758. UCHAR STAPacket[CONFIG_BPDU_PACKET_SIZE + _802_3_HEADER_SIZE];
  759. ULONG written;
  760. SHORT dataLen;
  761. // Copy the data from the packet into our data buffer
  762. BrdgSTACopyFromPacketToBuffer( STAPacket, sizeof(STAPacket), &written, pPacket );
  763. if( written < TCN_BPDU_PACKET_SIZE + _802_3_HEADER_SIZE )
  764. {
  765. THROTTLED_DBGPRINT(STA, ("Undersize STA packet received on %p\n", pAdapt));
  766. return;
  767. }
  768. // The LLC header must identify the STA protocol
  769. if( (STAPacket[14] != 0x42) || (STAPacket[15] != 0x42) )
  770. {
  771. THROTTLED_DBGPRINT(STA, ("Packet with bad protocol type received on %p\n", pAdapt));
  772. return;
  773. }
  774. // Bytes 13 and 14 encode the length of data.
  775. dataLen = STAPacket[12] << 8;
  776. dataLen |= STAPacket[13];
  777. // The first two bytes are the protocol identifier and must be zero.
  778. // The third byte is the version identifier and must be zero.
  779. if( (STAPacket[_802_3_HEADER_SIZE] != 0) ||
  780. (STAPacket[_802_3_HEADER_SIZE + 1] != 0) ||
  781. (STAPacket[_802_3_HEADER_SIZE + 2] != 0) )
  782. {
  783. THROTTLED_DBGPRINT(STA, ("Invalid STA packet received\n"));
  784. return;
  785. }
  786. if( STAPacket[_802_3_HEADER_SIZE + 3] == 0x80 )
  787. {
  788. // The length of the frame with LLC header must be 7 bytes for a TCN BPDU
  789. if( dataLen != 7 )
  790. {
  791. THROTTLED_DBGPRINT(STA, ("Bad header size for TCN BPDU on %p\n", pAdapt));
  792. return;
  793. }
  794. // This is a Topology Change BPDU.
  795. BrdgSTAProcessTCNBPDU( pAdapt );
  796. }
  797. else if( STAPacket[_802_3_HEADER_SIZE + 3] == 0x00 )
  798. {
  799. CONFIG_BPDU bpdu;
  800. if( written < CONFIG_BPDU_PACKET_SIZE + _802_3_HEADER_SIZE )
  801. {
  802. THROTTLED_DBGPRINT(STA, ("Undersize config BPDU received on %p\n", pAdapt));
  803. return;
  804. }
  805. // The length of the frame with LLC header must be 38 bytes for a Config BPDU
  806. if( dataLen != 38 )
  807. {
  808. THROTTLED_DBGPRINT(STA, ("Bad header size for Config BPDU on %p\n", pAdapt));
  809. return;
  810. }
  811. bpdu.Type = ConfigBPDU;
  812. // The high bit of byte 5 encodes the topology change acknowledge flag
  813. bpdu.bTopologyChangeAck = (BOOLEAN)((STAPacket[_802_3_HEADER_SIZE + 4] & 0x80) != 0);
  814. // The low bit of byte 5 encodes the topology change flag
  815. bpdu.bTopologyChange = (BOOLEAN)((STAPacket[_802_3_HEADER_SIZE + 4] & 0x01) != 0);
  816. // Bytes 6 thru 13 encode the root bridge ID
  817. bpdu.RootID[0] = STAPacket[_802_3_HEADER_SIZE + 5];
  818. bpdu.RootID[1] = STAPacket[_802_3_HEADER_SIZE + 6];
  819. bpdu.RootID[2] = STAPacket[_802_3_HEADER_SIZE + 7];
  820. bpdu.RootID[3] = STAPacket[_802_3_HEADER_SIZE + 8];
  821. bpdu.RootID[4] = STAPacket[_802_3_HEADER_SIZE + 9];
  822. bpdu.RootID[5] = STAPacket[_802_3_HEADER_SIZE + 10];
  823. bpdu.RootID[6] = STAPacket[_802_3_HEADER_SIZE + 11];
  824. bpdu.RootID[7] = STAPacket[_802_3_HEADER_SIZE + 12];
  825. // Bytes 14 thru 17 encode the root path cost
  826. bpdu.RootCost = 0;
  827. bpdu.RootCost |= STAPacket[_802_3_HEADER_SIZE + 13] << 24;
  828. bpdu.RootCost |= STAPacket[_802_3_HEADER_SIZE + 14] << 16;
  829. bpdu.RootCost |= STAPacket[_802_3_HEADER_SIZE + 15] << 8;
  830. bpdu.RootCost |= STAPacket[_802_3_HEADER_SIZE + 16];
  831. // Bytes 18 thru 15 encode the designated bridge ID
  832. bpdu.BridgeID[0] = STAPacket[_802_3_HEADER_SIZE + 17];
  833. bpdu.BridgeID[1] = STAPacket[_802_3_HEADER_SIZE + 18];
  834. bpdu.BridgeID[2] = STAPacket[_802_3_HEADER_SIZE + 19];
  835. bpdu.BridgeID[3] = STAPacket[_802_3_HEADER_SIZE + 20];
  836. bpdu.BridgeID[4] = STAPacket[_802_3_HEADER_SIZE + 21];
  837. bpdu.BridgeID[5] = STAPacket[_802_3_HEADER_SIZE + 22];
  838. bpdu.BridgeID[6] = STAPacket[_802_3_HEADER_SIZE + 23];
  839. bpdu.BridgeID[7] = STAPacket[_802_3_HEADER_SIZE + 24];
  840. // Bytes 26 and 27 encode the port identifier
  841. bpdu.PortID = 0;
  842. bpdu.PortID |= STAPacket[_802_3_HEADER_SIZE + 25] << 8;
  843. bpdu.PortID |= STAPacket[_802_3_HEADER_SIZE + 26];
  844. // Bytes 28 and 29 encode the message age
  845. bpdu.MessageAge = 0;
  846. bpdu.MessageAge |= STAPacket[_802_3_HEADER_SIZE + 27] << 8;
  847. bpdu.MessageAge |= STAPacket[_802_3_HEADER_SIZE + 28];
  848. // Bytes 30 and 31 encode the Max Age
  849. bpdu.MaxAge = 0;
  850. bpdu.MaxAge |= STAPacket[_802_3_HEADER_SIZE + 29] << 8;
  851. bpdu.MaxAge |= STAPacket[_802_3_HEADER_SIZE + 30];
  852. if( bpdu.MaxAge == 0 )
  853. {
  854. THROTTLED_DBGPRINT(STA, ("Ignoring BPDU packet with zero MaxAge on adapter %p\n", pAdapt));
  855. return;
  856. }
  857. // Bytes 32 and 33 encode the Hello Time
  858. bpdu.HelloTime = 0;
  859. bpdu.HelloTime |= STAPacket[_802_3_HEADER_SIZE + 31] << 8;
  860. bpdu.HelloTime |= STAPacket[_802_3_HEADER_SIZE + 32];
  861. if( bpdu.HelloTime == 0 )
  862. {
  863. THROTTLED_DBGPRINT(STA, ("Ignoring BPDU packet with zero HelloTime on adapter %p\n", pAdapt));
  864. return;
  865. }
  866. // Bytes 34 and 35 encode the forwarding delay
  867. bpdu.ForwardDelay = 0;
  868. bpdu.ForwardDelay |= STAPacket[_802_3_HEADER_SIZE + 33] << 8;
  869. bpdu.ForwardDelay |= STAPacket[_802_3_HEADER_SIZE + 34];
  870. if( bpdu.ForwardDelay == 0 )
  871. {
  872. THROTTLED_DBGPRINT(STA, ("Ignoring BPDU packet with zero ForwardDelay on adapter %p\n", pAdapt));
  873. return;
  874. }
  875. BrdgSTAProcessConfigBPDU( pAdapt, &bpdu );
  876. }
  877. else
  878. {
  879. THROTTLED_DBGPRINT(STA, ("Packet with unrecognized BPDU type received on %p\n", pAdapt));
  880. return;
  881. }
  882. }
  883. // ===========================================================================
  884. //
  885. // PRIVATE FUNCTIONS
  886. //
  887. // ===========================================================================
  888. VOID
  889. BrdgSTASetAdapterState(
  890. IN PADAPT pAdapt,
  891. IN PORT_STATE NewState
  892. )
  893. /*++
  894. Routine Description:
  895. Updates an adapter's forwarding state correctly
  896. This function is designed to be callable at high IRQL, so it defers
  897. the actual call to BrdgProtDoAdapterStateChange, which must be called
  898. at low IRQL.
  899. Arguments:
  900. pAdapt The adapter the packet was received on
  901. pPacket The received packet
  902. Return Value:
  903. None
  904. Locking Constraints:
  905. No requirements on caller-held locks
  906. --*/
  907. {
  908. LOCK_STATE LockState;
  909. BOOLEAN bailOut = FALSE;
  910. // Set the adapter's new state.
  911. NdisAcquireReadWriteLock( &gAdapterCharacteristicsLock, TRUE/*Write access*/, &LockState );
  912. if( pAdapt->State == NewState )
  913. {
  914. bailOut = TRUE;
  915. }
  916. else
  917. {
  918. pAdapt->State = NewState;
  919. }
  920. NdisReleaseReadWriteLock( &gAdapterCharacteristicsLock, &LockState );
  921. // Don't do additional work if the adapter is already in the requested state
  922. if( bailOut )
  923. {
  924. return;
  925. }
  926. #if DBG
  927. switch( NewState )
  928. {
  929. case Blocking:
  930. DBGPRINT(STA, ("Adapter %p becomes BLOCKING\n", pAdapt));
  931. break;
  932. case Listening:
  933. DBGPRINT(STA, ("Adapter %p becomes LISTENING\n", pAdapt));
  934. break;
  935. case Learning:
  936. DBGPRINT(STA, ("Adapter %p becomes LEARNING\n", pAdapt));
  937. break;
  938. case Forwarding:
  939. DBGPRINT(STA, ("Adapter %p becomes FORWARDING\n", pAdapt));
  940. break;
  941. }
  942. #endif
  943. //
  944. // We will be hanging onto the adapter pointer in order to defer the call
  945. // to BrdgSTADeferredSetAdapterState.
  946. //
  947. if( BrdgAcquireAdapter(pAdapt) )
  948. {
  949. NDIS_STATUS Status;
  950. // We need to defer the call to BrdgProtDoAdapterStateChange since it must run
  951. // at PASSIVE_IRQL
  952. Status = BrdgDeferFunction( BrdgSTADeferredSetAdapterState, pAdapt );
  953. if( Status != NDIS_STATUS_SUCCESS )
  954. {
  955. DBGPRINT(STA, ("Unable to defer call to BrdgSTADeferredSetAdapterState\n", pAdapt));
  956. BrdgReleaseAdapter( pAdapt );
  957. }
  958. // else adapter will be released in BrdgSTADeferredSetAdapterState
  959. }
  960. else
  961. {
  962. DBGPRINT(STA, ("Adapter %p already shutting down when attempted to set adapter state\n", pAdapt));
  963. }
  964. }
  965. VOID
  966. BrdgSTADeferredSetAdapterState(
  967. IN PVOID Arg
  968. )
  969. /*++
  970. Routine Description:
  971. Deferred function from BrdgSTASetAdapterState; does housekeeping associated with
  972. changing an adapter's forwarding state.
  973. Must be called at PASSIVE
  974. Arguments:
  975. Arg The adapter that needs updating
  976. Return Value:
  977. None
  978. Locking Constraints:
  979. No requirements on caller-held locks
  980. --*/
  981. {
  982. PADAPT pAdapt = (PADAPT)Arg;
  983. SAFEASSERT( CURRENT_IRQL == PASSIVE_LEVEL );
  984. BrdgProtDoAdapterStateChange( pAdapt );
  985. // Tell user-mode about the change
  986. BrdgCtlNotifyAdapterChange( pAdapt, BrdgNotifyAdapterStateChange );
  987. // Adapter was acquired in BrdgSTASetAdapterState()
  988. BrdgReleaseAdapter( pAdapt );
  989. }
  990. VOID
  991. BrdgSTATransmitConfigBPDUPacket(
  992. IN PADAPT pAdapt,
  993. PCONFIG_BPDU pbpdu
  994. )
  995. /*++
  996. Routine Description:
  997. Transmits a config BPDU packet on a particular adapter
  998. Arguments:
  999. pAdapt The adapter to transmit on
  1000. pbpdu A structure describing the BPDU information
  1001. Return Value:
  1002. None
  1003. Locking Constraints:
  1004. No requirements on caller-held locks
  1005. --*/
  1006. {
  1007. UCHAR STAPacket[CONFIG_BPDU_PACKET_SIZE + _802_3_HEADER_SIZE];
  1008. NDIS_STATUS Status;
  1009. if (BrdgProtGetAdapterCount() < 2)
  1010. {
  1011. return;
  1012. }
  1013. if (!BrdgFwdBridgingNetworks())
  1014. {
  1015. DBGPRINT(STA, ("Not Transmitting STA Packet (we're not bridging)\r\n"));
  1016. return;
  1017. }
  1018. //
  1019. // First encode the Ethernet header.
  1020. //
  1021. // Destination MAC address of packet must be STA multicast address
  1022. STAPacket[0] = STA_MAC_ADDR[0];
  1023. STAPacket[1] = STA_MAC_ADDR[1];
  1024. STAPacket[2] = STA_MAC_ADDR[2];
  1025. STAPacket[3] = STA_MAC_ADDR[3];
  1026. STAPacket[4] = STA_MAC_ADDR[4];
  1027. STAPacket[5] = STA_MAC_ADDR[5];
  1028. // The the source MAC address to the adapter's own MAC address
  1029. STAPacket[6] = pAdapt->MACAddr[0];
  1030. STAPacket[7] = pAdapt->MACAddr[1];
  1031. STAPacket[8] = pAdapt->MACAddr[2];
  1032. STAPacket[9] = pAdapt->MACAddr[3];
  1033. STAPacket[10] = pAdapt->MACAddr[4];
  1034. STAPacket[11] = pAdapt->MACAddr[5];
  1035. // Next two bytes are the size of the frame (38 bytes)
  1036. STAPacket[12] = 0x00;
  1037. STAPacket[13] = 0x26;
  1038. // Next two bytes are the LLC DSAP and SSAP fields, set to 0x42 for STA
  1039. STAPacket[14] = 0x42;
  1040. STAPacket[15] = 0x42;
  1041. // Next byte is the LLC frame type, 3 for unnumbered
  1042. STAPacket[16] = 0x03;
  1043. //
  1044. // Now we are encoding the payload.
  1045. //
  1046. // First 4 bytes are the protocol identifier, version and BPDU type, all zero
  1047. STAPacket[_802_3_HEADER_SIZE] = STAPacket[_802_3_HEADER_SIZE + 1] =
  1048. STAPacket[_802_3_HEADER_SIZE + 2] = STAPacket[_802_3_HEADER_SIZE + 3] = 0x00;
  1049. // Byte 5 encodes the Topology Change Ack flag in the high bit and the
  1050. // Topology Change flag in the low bit.
  1051. STAPacket[_802_3_HEADER_SIZE + 4] = 0;
  1052. if( pbpdu->bTopologyChangeAck )
  1053. {
  1054. STAPacket[_802_3_HEADER_SIZE + 4] |= 0x80;
  1055. }
  1056. if( pbpdu->bTopologyChange )
  1057. {
  1058. STAPacket[_802_3_HEADER_SIZE + 4] |= 0x01;
  1059. }
  1060. // Bytes 6-13 encode the root bridge ID
  1061. STAPacket[_802_3_HEADER_SIZE + 5] = pbpdu->RootID[0];
  1062. STAPacket[_802_3_HEADER_SIZE + 6] = pbpdu->RootID[1];
  1063. STAPacket[_802_3_HEADER_SIZE + 7] = pbpdu->RootID[2];
  1064. STAPacket[_802_3_HEADER_SIZE + 8] = pbpdu->RootID[3];
  1065. STAPacket[_802_3_HEADER_SIZE + 9] = pbpdu->RootID[4];
  1066. STAPacket[_802_3_HEADER_SIZE + 10] = pbpdu->RootID[5];
  1067. STAPacket[_802_3_HEADER_SIZE + 11] = pbpdu->RootID[6];
  1068. STAPacket[_802_3_HEADER_SIZE + 12] = pbpdu->RootID[7];
  1069. // Bytes 14 - 17 encode the root path cost
  1070. STAPacket[_802_3_HEADER_SIZE + 13] = (UCHAR)(pbpdu->RootCost >> 24);
  1071. STAPacket[_802_3_HEADER_SIZE + 14] = (UCHAR)(pbpdu->RootCost >> 16);
  1072. STAPacket[_802_3_HEADER_SIZE + 15] = (UCHAR)(pbpdu->RootCost >> 8);
  1073. STAPacket[_802_3_HEADER_SIZE + 16] = (UCHAR)(pbpdu->RootCost);
  1074. // Bytes 18-25 encode the designated bridge ID
  1075. STAPacket[_802_3_HEADER_SIZE + 17] = pbpdu->BridgeID[0];
  1076. STAPacket[_802_3_HEADER_SIZE + 18] = pbpdu->BridgeID[1];
  1077. STAPacket[_802_3_HEADER_SIZE + 19] = pbpdu->BridgeID[2];
  1078. STAPacket[_802_3_HEADER_SIZE + 20] = pbpdu->BridgeID[3];
  1079. STAPacket[_802_3_HEADER_SIZE + 21] = pbpdu->BridgeID[4];
  1080. STAPacket[_802_3_HEADER_SIZE + 22] = pbpdu->BridgeID[5];
  1081. STAPacket[_802_3_HEADER_SIZE + 23] = pbpdu->BridgeID[6];
  1082. STAPacket[_802_3_HEADER_SIZE + 24] = pbpdu->BridgeID[7];
  1083. // Bytes 26 and 27 encode the port identifier
  1084. STAPacket[_802_3_HEADER_SIZE + 25] = (UCHAR)(pbpdu->PortID >> 8);
  1085. STAPacket[_802_3_HEADER_SIZE + 26] = (UCHAR)(pbpdu->PortID);
  1086. // Bytes 28 and 29 encode the message age
  1087. STAPacket[_802_3_HEADER_SIZE + 27] = (UCHAR)(pbpdu->MessageAge >> 8);
  1088. STAPacket[_802_3_HEADER_SIZE + 28] = (UCHAR)(pbpdu->MessageAge);
  1089. // Bytes 30 and 31 encode the max age
  1090. STAPacket[_802_3_HEADER_SIZE + 29] = (UCHAR)(pbpdu->MaxAge >> 8);
  1091. STAPacket[_802_3_HEADER_SIZE + 30] = (UCHAR)(pbpdu->MaxAge);
  1092. // Bytes 32 and 33 encode the hello time
  1093. STAPacket[_802_3_HEADER_SIZE + 31] = (UCHAR)(pbpdu->HelloTime >> 8);
  1094. STAPacket[_802_3_HEADER_SIZE + 32] = (UCHAR)(pbpdu->HelloTime);
  1095. // Bytes 34 and 35 encode the forward delay
  1096. STAPacket[_802_3_HEADER_SIZE + 33] = (UCHAR)(pbpdu->ForwardDelay >> 8);
  1097. STAPacket[_802_3_HEADER_SIZE + 34] = (UCHAR)(pbpdu->ForwardDelay);
  1098. // Send the finished packet
  1099. Status = BrdgFwdSendBuffer( pAdapt, STAPacket, sizeof(STAPacket) );
  1100. if( Status != NDIS_STATUS_SUCCESS )
  1101. {
  1102. THROTTLED_DBGPRINT(STA, ("BPDU packet send failed: %08x\n", Status));
  1103. }
  1104. }
  1105. VOID
  1106. BrdgSTATransmitTCNPacket()
  1107. /*++
  1108. Routine Description:
  1109. Transmits a Topology Change Notification BPDU packet on the root adapter
  1110. Arguments:
  1111. None
  1112. Return Value:
  1113. None
  1114. Locking Constraints:
  1115. ASSUMES the caller has NOT acquired gSTALock
  1116. --*/
  1117. {
  1118. UCHAR STAPacket[TCN_BPDU_PACKET_SIZE + _802_3_HEADER_SIZE];
  1119. NDIS_STATUS Status;
  1120. PADAPT pRootAdapter;
  1121. BOOLEAN bAcquired;
  1122. if (BrdgProtGetAdapterCount() < 2)
  1123. {
  1124. return;
  1125. }
  1126. if (!BrdgFwdBridgingNetworks())
  1127. {
  1128. DBGPRINT(STA, ("Not Transmitting STA Packet (we're not bridging)\r\n"));
  1129. return;
  1130. }
  1131. NdisAcquireSpinLock( &gSTALock );
  1132. // Freeze this value for the rest of the function
  1133. pRootAdapter = gRootAdapter;
  1134. if( pRootAdapter == NULL )
  1135. {
  1136. NdisReleaseSpinLock( &gSTALock );
  1137. return;
  1138. }
  1139. bAcquired = BrdgAcquireAdapter( pRootAdapter );
  1140. NdisReleaseSpinLock( &gSTALock );
  1141. if( ! bAcquired )
  1142. {
  1143. SAFEASSERT( FALSE );
  1144. return;
  1145. }
  1146. SAFEASSERT( gHaveID );
  1147. //
  1148. // First encode the Ethernet header.
  1149. //
  1150. // Destination MAC address of packet must be STA multicast address
  1151. STAPacket[0] = STA_MAC_ADDR[0];
  1152. STAPacket[1] = STA_MAC_ADDR[1];
  1153. STAPacket[2] = STA_MAC_ADDR[2];
  1154. STAPacket[3] = STA_MAC_ADDR[3];
  1155. STAPacket[4] = STA_MAC_ADDR[4];
  1156. STAPacket[5] = STA_MAC_ADDR[5];
  1157. // Set the packet's MAC address to the adapter's own MAC address
  1158. STAPacket[6] = pRootAdapter->MACAddr[0];
  1159. STAPacket[7] = pRootAdapter->MACAddr[1];
  1160. STAPacket[8] = pRootAdapter->MACAddr[2];
  1161. STAPacket[9] = pRootAdapter->MACAddr[3];
  1162. STAPacket[10] = pRootAdapter->MACAddr[4];
  1163. STAPacket[11] = pRootAdapter->MACAddr[5];
  1164. // Next two bytes are the size of the frame (7 bytes)
  1165. STAPacket[12] = 0x00;
  1166. STAPacket[13] = 0x07;
  1167. // Next two bytes are the LLC DSAP and SSAP fields, set to 0x42 for STA
  1168. STAPacket[14] = 0x42;
  1169. STAPacket[15] = 0x42;
  1170. // Next byte is the LLC frame type, 3 for unnumbered
  1171. STAPacket[16] = 0x03;
  1172. //
  1173. // Now we are encoding the payload.
  1174. //
  1175. // First 3 bytes are the protocol identifier and protocol version number, all zero
  1176. STAPacket[_802_3_HEADER_SIZE] = STAPacket[_802_3_HEADER_SIZE + 1] =
  1177. STAPacket[_802_3_HEADER_SIZE + 2] = 0x00;
  1178. // Byte 4 is the BPDU type, which is 0x80 for TCN.
  1179. STAPacket[_802_3_HEADER_SIZE + 3] = 0x80;
  1180. // Send the finished packet
  1181. Status = BrdgFwdSendBuffer( pRootAdapter, STAPacket, sizeof(STAPacket) );
  1182. // We are done with the root adapter
  1183. BrdgReleaseAdapter( pRootAdapter );
  1184. if( Status != NDIS_STATUS_SUCCESS )
  1185. {
  1186. THROTTLED_DBGPRINT(STA, ("BPDU packet send failed: %08x\n", Status));
  1187. }
  1188. }
  1189. VOID
  1190. BrdgSTACopyFromPacketToBuffer(
  1191. OUT PUCHAR pPacketOut,
  1192. IN ULONG BufferSize,
  1193. OUT PULONG pWrittenCount,
  1194. IN PNDIS_PACKET pPacketIn
  1195. )
  1196. /*++
  1197. Routine Description:
  1198. Copies data out of a packet descriptor into a flat buffer
  1199. Arguments:
  1200. pPacketOut Data buffer to copy info
  1201. BufferSize Size of pPacketOut
  1202. pWrittenCount Number of bytes actually written
  1203. pPacketIn Packet to copy from
  1204. Return Value:
  1205. None
  1206. Locking Constraints:
  1207. No requirements on caller-held locks
  1208. --*/
  1209. {
  1210. PNDIS_BUFFER pBuf;
  1211. *pWrittenCount = 0L;
  1212. pBuf = BrdgBufPacketHeadBuffer(pPacketIn);
  1213. while( pBuf != NULL )
  1214. {
  1215. PVOID pData;
  1216. UINT Len;
  1217. NdisQueryBufferSafe( pBuf, &pData, &Len, NormalPagePriority );
  1218. if( pData != NULL )
  1219. {
  1220. ULONG BytesToWrite;
  1221. if( *pWrittenCount + Len > BufferSize )
  1222. {
  1223. BytesToWrite = BufferSize - *pWrittenCount;
  1224. }
  1225. else
  1226. {
  1227. BytesToWrite = Len;
  1228. }
  1229. NdisMoveMemory( pPacketOut, pData, BytesToWrite );
  1230. pPacketOut += BytesToWrite;
  1231. *pWrittenCount += BytesToWrite;
  1232. if( BytesToWrite < Len )
  1233. {
  1234. // We're full, so we're done.
  1235. return;
  1236. }
  1237. }
  1238. else
  1239. {
  1240. // Shouldn't happen
  1241. SAFEASSERT( FALSE );
  1242. }
  1243. NdisGetNextBuffer( pBuf, &pBuf );
  1244. }
  1245. }
  1246. VOID
  1247. BrdgSTATransmitConfig(
  1248. PADAPT pAdapt
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. Transmits a config BPDU on a particular adapter. Collects appropriate
  1253. information and calls BrdgSTATransmitConfigBPDUPacket().
  1254. Arguments:
  1255. pAdapt The adapter to transmit on
  1256. Return Value:
  1257. None
  1258. Locking Constraints:
  1259. ASSUMES the caller DOES NOT hold gSTALock
  1260. --*/
  1261. {
  1262. NdisAcquireSpinLock( &gSTALock );
  1263. if( BrdgTimerIsRunning( &pAdapt->STAInfo.HoldTimer ) )
  1264. {
  1265. // We have sent a config packet recently. Wait until the hold timer
  1266. // expires before sending another one so we don't flood other bridges.
  1267. pAdapt->STAInfo.bConfigPending = TRUE;
  1268. NdisReleaseSpinLock( &gSTALock );
  1269. }
  1270. else
  1271. {
  1272. CONFIG_BPDU bpdu;
  1273. // Fill out the BPDU information structure
  1274. bpdu.Type = ConfigBPDU;
  1275. SAFEASSERT( gHaveID );
  1276. BrdgSTACopyID( bpdu.RootID, gDesignatedRootID );
  1277. bpdu.RootCost = gRootCost;
  1278. BrdgSTACopyID( bpdu.BridgeID, gOurID );
  1279. bpdu.PortID = pAdapt->STAInfo.ID;
  1280. if( BrdgSTAWeAreRoot() )
  1281. {
  1282. // We are the root, so the age of this config information is zero.
  1283. bpdu.MessageAge = 0;
  1284. }
  1285. else
  1286. {
  1287. // The MessageAge field is to be set to the age of the last received
  1288. // config BPDU on the root port.
  1289. if( (gRootAdapter != NULL) && BrdgAcquireAdapter(gRootAdapter) )
  1290. {
  1291. ULONG CurrentTime, deltaTime;
  1292. NdisGetSystemUpTime( &CurrentTime );
  1293. // The message age timer should be running on the root adapter if
  1294. // we are not root.
  1295. SAFEASSERT( BrdgTimerIsRunning(&gRootAdapter->STAInfo.MessageAgeTimer) );
  1296. SAFEASSERT( gRootAdapter->STAInfo.LastConfigTime != 0L );
  1297. // The last parameter is the max acceptable delta. We should have
  1298. // received the last piece of config information from the root no more
  1299. // than gMaxAge STA units ago, since if it was longer than that, we
  1300. // should have become root. Allow an additional second for processing.
  1301. deltaTime = BrdgDeltaSafe( gRootAdapter->STAInfo.LastConfigTime, CurrentTime,
  1302. (ULONG)(((gMaxAge * 1000) / 256) + 1000) );
  1303. // STA times are in 1/256ths of a second.
  1304. bpdu.MessageAge = (STA_TIME)((deltaTime * 256) / 1000);
  1305. // MESSAGE_AGE_INCREMENT allows for the transmission time, etc.
  1306. bpdu.MessageAge += MESSAGE_AGE_INCREMENT;
  1307. BrdgReleaseAdapter(gRootAdapter);
  1308. }
  1309. else
  1310. {
  1311. // Why isn't there a root port if we're not root?
  1312. SAFEASSERT( FALSE );
  1313. bpdu.MessageAge = 0;
  1314. }
  1315. }
  1316. bpdu.MaxAge = gMaxAge;
  1317. bpdu.HelloTime = gHelloTime;
  1318. bpdu.ForwardDelay = gForwardDelay;
  1319. // Are we supposed to acknowledge a topology change signal?
  1320. bpdu.bTopologyChangeAck = pAdapt->STAInfo.bTopologyChangeAck;
  1321. // We just sent out the topology change ack if there was one to send
  1322. pAdapt->STAInfo.bTopologyChangeAck = FALSE;
  1323. bpdu.bTopologyChange = gTopologyChange;
  1324. // Start the hold timer to make sure another BPDU isn't sent prematurely
  1325. pAdapt->STAInfo.bConfigPending = FALSE;
  1326. // Don't send a packet with the spin lock held
  1327. NdisReleaseSpinLock( &gSTALock );
  1328. // Send off the config BPDU
  1329. BrdgSTATransmitConfigBPDUPacket( pAdapt, &bpdu );
  1330. BrdgSetTimer( &pAdapt->STAInfo.HoldTimer, HOLD_TIMER_PERIOD, FALSE /*Not periodic*/ );
  1331. }
  1332. }
  1333. BOOLEAN
  1334. BrdgSTASupersedesPortInfo(
  1335. IN PADAPT pAdapt,
  1336. IN PCONFIG_BPDU pbpdu
  1337. )
  1338. /*++
  1339. Routine Description:
  1340. Determines whether a given bpdu's information supersedes the information
  1341. already associated with a particular adapter
  1342. Arguments:
  1343. pAdapt The adapter
  1344. pbpdu Received BPDU information to examine
  1345. Return Value:
  1346. TRUE if the given information supersedes (i.e., is better) than the information
  1347. previously held by the adapter. FALSE otherwise.
  1348. Locking Constraints:
  1349. ASSUMES the caller has acquired gSTALock
  1350. --*/
  1351. {
  1352. INT cmp;
  1353. /* The information advertised on a given link supersedes the existing information for that
  1354. link if the following conditions hold (applied in order; TRUE at any step causes immediate
  1355. success)
  1356. (1) The advertised root has a lower ID than the previous root
  1357. (2) The advertised root is the same as the previous root and the new cost-to-root is
  1358. lower than the previous value
  1359. (3) The root IDs and costs are the same, and the ID of the advertising bridge is
  1360. lower than the previous value
  1361. (4) The root ID, cost-to-root and bridge IDs are the same and the advertising bridge
  1362. is not us
  1363. (5) The root ID, cost-to-root, bridge IDs are the same, the bridge is us, and the
  1364. advertised port number is lower than the previous value (this happens if we have
  1365. more than one port on the same physical link and we see the advertisement from
  1366. our other port).
  1367. */
  1368. // Compare the advertised root ID to the adapter's previous designated root ID
  1369. cmp = BrdgSTABridgeIDCmp( pbpdu->RootID, pAdapt->STAInfo.DesignatedRootID );
  1370. if( cmp == -1 ) // (1)
  1371. {
  1372. return TRUE;
  1373. }
  1374. else if( cmp == 0 )
  1375. {
  1376. if( pbpdu->RootCost < pAdapt->STAInfo.DesignatedCost ) // (2)
  1377. {
  1378. return TRUE;
  1379. }
  1380. else if( pbpdu->RootCost == pAdapt->STAInfo.DesignatedCost )
  1381. {
  1382. // Compare the advertised bridge ID to the previous designated bridge ID
  1383. cmp = BrdgSTABridgeIDCmp( pbpdu->BridgeID, pAdapt->STAInfo.DesignatedBridgeID );
  1384. if( cmp == -1 )
  1385. {
  1386. return TRUE; // (3)
  1387. }
  1388. else if( cmp == 0 )
  1389. {
  1390. SAFEASSERT( gHaveID );
  1391. // Compare the advertised bridge ID to our own ID
  1392. cmp = BrdgSTABridgeIDCmp( pbpdu->BridgeID, gOurID );
  1393. if( cmp != 0 )
  1394. {
  1395. return TRUE; // (4)
  1396. }
  1397. else if( cmp == 0 )
  1398. {
  1399. return (BOOLEAN)(pbpdu->PortID <= pAdapt->STAInfo.DesignatedPort); // (5)
  1400. }
  1401. }
  1402. }
  1403. }
  1404. return FALSE;
  1405. }
  1406. VOID
  1407. BrdgSTARecordConfigInfo(
  1408. IN PADAPT pAdapt,
  1409. IN PCONFIG_BPDU pbpdu
  1410. )
  1411. /*++
  1412. Routine Description:
  1413. Associates the information from a received BPDU with a particular adapter
  1414. Arguments:
  1415. pAdapt The adapter
  1416. pbpdu Received BPDU information to record
  1417. Return Value:
  1418. None
  1419. Locking Constraints:
  1420. ASSUMES the caller has acquired gSTALock
  1421. --*/
  1422. {
  1423. ULONG msgAgeInMs = (pbpdu->MessageAge / 256) * 1000;
  1424. // Update the port's information with the new data
  1425. BrdgSTACopyID( pAdapt->STAInfo.DesignatedRootID, pbpdu->RootID );
  1426. pAdapt->STAInfo.DesignatedCost = pbpdu->RootCost;
  1427. BrdgSTACopyID( pAdapt->STAInfo.DesignatedBridgeID, pbpdu->BridgeID );
  1428. pAdapt->STAInfo.DesignatedPort = pbpdu->PortID;
  1429. // Start the message age timer. It is specified to expire after
  1430. // gMaxAge - MessageAge STA time units.
  1431. if( pbpdu->MessageAge < gMaxAge )
  1432. {
  1433. BrdgSTASetTimerWithSTATime( &pAdapt->STAInfo.MessageAgeTimer,
  1434. gMaxAge - pbpdu->MessageAge, FALSE /*Not periodic*/ );
  1435. }
  1436. else
  1437. {
  1438. // How odd. The message was already too old. Start the timer so that it
  1439. // will expire immediately.
  1440. THROTTLED_DBGPRINT(STA, ("Received over-age BPDU (%i / %i) on adapter %p", pbpdu->MessageAge,
  1441. gMaxAge, pAdapt));
  1442. BrdgSTASetTimerWithSTATime( &pAdapt->STAInfo.MessageAgeTimer, 0, FALSE /*Not periodic*/ );
  1443. }
  1444. NdisGetSystemUpTime( &pAdapt->STAInfo.LastConfigTime );
  1445. // Roll back by the age of the info we got.
  1446. SAFEASSERT( msgAgeInMs < pAdapt->STAInfo.LastConfigTime );
  1447. pAdapt->STAInfo.LastConfigTime -= msgAgeInMs;
  1448. }
  1449. VOID
  1450. BrdgSTARecordTimeoutInfo(
  1451. IN PCONFIG_BPDU pbpdu
  1452. )
  1453. /*++
  1454. Routine Description:
  1455. Records timeout information conveyed by a BPDU received from the root bridge
  1456. Arguments:
  1457. pbpdu Received BPDU information to record
  1458. Return Value:
  1459. None
  1460. Locking Constraints:
  1461. ASSUMES the caller has acquired gSTALock
  1462. --*/
  1463. {
  1464. gMaxAge = pbpdu->MaxAge;
  1465. gHelloTime = pbpdu->HelloTime;
  1466. gForwardDelay = pbpdu->ForwardDelay;
  1467. BrdgSTAUpdateTopologyChange( pbpdu->bTopologyChange );
  1468. }
  1469. VOID
  1470. BrdgSTAGenerateConfigBPDUs()
  1471. /*++
  1472. Routine Description:
  1473. Sends configuration BPDUs out every designated port
  1474. Arguments:
  1475. pbpdu Received BPDU information to record
  1476. Return Value:
  1477. None
  1478. Locking Constraints:
  1479. ASSUMES the caller does NOT hold gSTALock
  1480. --*/
  1481. {
  1482. LOCK_STATE LockState;
  1483. PADAPT Adapters[MAX_ADAPTERS];
  1484. INT cmpID;
  1485. PADAPT pAdapt;
  1486. UINT numAdapters = 0, i;
  1487. NdisAcquireSpinLock( &gSTALock );
  1488. SAFEASSERT( gHaveID );
  1489. NdisAcquireReadWriteLock( &gAdapterListLock, FALSE /*read only*/, &LockState );
  1490. for( pAdapt = gAdapterList; pAdapt != NULL; pAdapt = pAdapt->Next )
  1491. {
  1492. if( (pAdapt->bSTAInited) && (pAdapt->State != Disabled) )
  1493. {
  1494. cmpID = BrdgSTABridgeIDCmp( pAdapt->STAInfo.DesignatedBridgeID, gOurID );
  1495. if( (cmpID == 0) && (pAdapt->STAInfo.ID == pAdapt->STAInfo.DesignatedPort) )
  1496. {
  1497. // This adapter is a designated port. We will send a config BPDU out it.
  1498. BrdgAcquireAdapterInLock( pAdapt );
  1499. Adapters[numAdapters] = pAdapt;
  1500. numAdapters++;
  1501. }
  1502. }
  1503. }
  1504. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  1505. NdisReleaseSpinLock( &gSTALock );
  1506. // Send a BPDU out every adapter that we chose
  1507. for( i = 0; i < numAdapters; i++ )
  1508. {
  1509. BrdgSTATransmitConfig(Adapters[i]);
  1510. BrdgReleaseAdapter(Adapters[i]);
  1511. }
  1512. }
  1513. VOID
  1514. BrdgSTARootSelection()
  1515. /*++
  1516. Routine Description:
  1517. Examines the information associated with every bridge port to determine
  1518. the root bridge ID and root port
  1519. Arguments:
  1520. None
  1521. Return Value:
  1522. None
  1523. Locking Constraints:
  1524. ASSUMES the caller has acquired gSTALock
  1525. --*/
  1526. {
  1527. LOCK_STATE LockState;
  1528. PADAPT pAdapt, pRootAdapt = NULL;
  1529. INT cmp;
  1530. SAFEASSERT( gHaveID );
  1531. NdisAcquireReadWriteLock( &gAdapterListLock, FALSE /*read only*/, &LockState );
  1532. for( pAdapt = gAdapterList; pAdapt != NULL; pAdapt = pAdapt->Next )
  1533. {
  1534. if( (pAdapt->bSTAInited) && (pAdapt->State != Disabled) )
  1535. {
  1536. /*
  1537. We consider the information advertised on each link to determine which port should
  1538. be the new root port. If no link advertises sufficiently attractive information, we declare
  1539. ourselves to be the root. A port is acceptable as the root port if all the following
  1540. conditions hold:
  1541. (1) The port receiving the advertisement must not be a designated port
  1542. (2) The link's advertised root must have a lower ID than us
  1543. (3) The link's advertised root ID must be lower than the advertised root ID on any other link
  1544. (4) If the advertised root ID is the same as another advertised root, the cost-to-root
  1545. must be lower
  1546. (5) If the root ID and cost are the same, the designated bridge on the port must have a
  1547. lower ID than the designated bridge on other ports (this chooses arbitrarily
  1548. between two bridges that can reach the root with the same cost)
  1549. (6) If the root ID, cost-to-root and designated bridge IDs are the same, the designated
  1550. port must be less than on other ports (this happens if two links have the same
  1551. designated bridge)
  1552. (7) If the root ID, cost-to-root, designated bridge ID and designated port IDs are all
  1553. the same, the port number of the port itself must be lower (this only happens if
  1554. we have more than one port onto the same physical link; we pick the lower-numbered
  1555. one as the root port)
  1556. */
  1557. cmp = BrdgSTABridgeIDCmp( pAdapt->STAInfo.DesignatedBridgeID, gOurID );
  1558. if( (cmp != 0) || (pAdapt->STAInfo.ID != pAdapt->STAInfo.DesignatedPort) ) // (1)
  1559. {
  1560. cmp = BrdgSTABridgeIDCmp(pAdapt->STAInfo.DesignatedRootID, gOurID);
  1561. if( cmp == -1 ) // (2)
  1562. {
  1563. BOOLEAN betterRoot = FALSE;
  1564. if( pRootAdapt == NULL )
  1565. {
  1566. // Hadn't seen a root better than ourselves before now; take this one.
  1567. betterRoot = TRUE;
  1568. }
  1569. else
  1570. {
  1571. // Compare the advertised root ID to our previous best
  1572. cmp = BrdgSTABridgeIDCmp(pAdapt->STAInfo.DesignatedRootID, pRootAdapt->STAInfo.DesignatedRootID);
  1573. if( cmp == -1 ) // (3)
  1574. {
  1575. betterRoot = TRUE;
  1576. }
  1577. else if( cmp == 0 )
  1578. {
  1579. PATH_COST thisCost = pAdapt->STAInfo.DesignatedCost + pAdapt->STAInfo.PathCost,
  1580. prevBestCost = pRootAdapt->STAInfo.DesignatedCost + pRootAdapt->STAInfo.PathCost;
  1581. if( thisCost < prevBestCost )
  1582. {
  1583. betterRoot = TRUE; // (4)
  1584. }
  1585. else if( thisCost == prevBestCost )
  1586. {
  1587. // Compare the IDs of the designated bridge
  1588. cmp = BrdgSTABridgeIDCmp(pAdapt->STAInfo.DesignatedBridgeID, pRootAdapt->STAInfo.DesignatedBridgeID);
  1589. if( cmp == -1 )
  1590. {
  1591. betterRoot = TRUE; // (5)
  1592. }
  1593. else if( cmp == 0 )
  1594. {
  1595. if( pAdapt->STAInfo.DesignatedPort < pRootAdapt->STAInfo.DesignatedPort )
  1596. {
  1597. betterRoot = TRUE; // (6)
  1598. }
  1599. else if( pAdapt->STAInfo.DesignatedPort == pRootAdapt->STAInfo.DesignatedPort )
  1600. {
  1601. if( pAdapt->STAInfo.ID < pRootAdapt->STAInfo.ID )
  1602. {
  1603. betterRoot = TRUE; // (7)
  1604. }
  1605. else
  1606. {
  1607. // Sanity-check that the two adapters' IDs are different!
  1608. SAFEASSERT( pAdapt->STAInfo.ID != pRootAdapt->STAInfo.ID );
  1609. }
  1610. }
  1611. }
  1612. }
  1613. }
  1614. }
  1615. if( betterRoot )
  1616. {
  1617. // We have a better root port.
  1618. pRootAdapt = pAdapt;
  1619. }
  1620. }
  1621. }
  1622. }
  1623. }
  1624. if( pRootAdapt == NULL )
  1625. {
  1626. gRootAdapter = NULL;
  1627. BrdgSTACopyID( gDesignatedRootID, gOurID );
  1628. gRootCost = 0;
  1629. }
  1630. else
  1631. {
  1632. gRootAdapter = pRootAdapt;
  1633. BrdgSTACopyID( gDesignatedRootID, pRootAdapt->STAInfo.DesignatedRootID );
  1634. gRootCost = pRootAdapt->STAInfo.DesignatedCost + pRootAdapt->STAInfo.PathCost;
  1635. }
  1636. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  1637. }
  1638. VOID
  1639. BrdgSTABecomeDesignatedPort(
  1640. IN PADAPT pAdapt
  1641. )
  1642. /*++
  1643. Routine Description:
  1644. Sets the information associated with an adapter to make it a designated port
  1645. Arguments:
  1646. pAdapt The adapter to make designated
  1647. Return Value:
  1648. None
  1649. Locking Constraints:
  1650. ASSUMES the caller has acquired gSTALock
  1651. --*/
  1652. {
  1653. SAFEASSERT( gHaveID );
  1654. BrdgSTACopyID( pAdapt->STAInfo.DesignatedRootID, gDesignatedRootID );
  1655. pAdapt->STAInfo.DesignatedCost = gRootCost;
  1656. BrdgSTACopyID( pAdapt->STAInfo.DesignatedBridgeID, gOurID );
  1657. pAdapt->STAInfo.DesignatedPort = pAdapt->STAInfo.ID;
  1658. }
  1659. VOID
  1660. BrdgSTADesignatedPortSelection()
  1661. /*++
  1662. Routine Description:
  1663. Examines the information associated with each port to determine
  1664. which should become designated ports
  1665. Arguments:
  1666. None
  1667. Return Value:
  1668. None
  1669. Locking Constraints:
  1670. ASSUMES the caller has acquired gSTALock
  1671. --*/
  1672. {
  1673. LOCK_STATE LockState;
  1674. PADAPT pAdapt;
  1675. INT cmp;
  1676. SAFEASSERT( gHaveID );
  1677. NdisAcquireReadWriteLock( &gAdapterListLock, FALSE /*read only*/, &LockState );
  1678. for( pAdapt = gAdapterList; pAdapt != NULL; pAdapt = pAdapt->Next )
  1679. {
  1680. if( pAdapt->bSTAInited )
  1681. {
  1682. BOOLEAN becomeDesignated = FALSE;
  1683. /* We consider each port to determine whether it should become a designated port
  1684. (if it previously was not one). A port becomes a designated port if the
  1685. following conditions hold:
  1686. (1) The port is the link's designated port by advertised info
  1687. (2) The link's previous designated root is not the correct root
  1688. (3) Our cost-to-root is lower than the current cost advertised on the link
  1689. (4) We have a same cost-to-root but a lower ID than the current designated
  1690. bridge on the link
  1691. (5) We have the same cost-to-root and ID as the designated bridge on the link
  1692. but a lower port number (this only happens if we have two or more ports
  1693. on the same physical link)
  1694. */
  1695. // See if the link's designated bridge is already us
  1696. cmp = BrdgSTABridgeIDCmp(pAdapt->STAInfo.DesignatedBridgeID, gOurID);
  1697. if( (cmp == 0) && (pAdapt->STAInfo.DesignatedPort == pAdapt->STAInfo.ID) )
  1698. {
  1699. becomeDesignated = TRUE; // (1)
  1700. }
  1701. else
  1702. {
  1703. // Compare the link's advertised root to the one we believe is root
  1704. cmp = BrdgSTABridgeIDCmp(pAdapt->STAInfo.DesignatedRootID, gDesignatedRootID);
  1705. if( cmp != 0 )
  1706. {
  1707. becomeDesignated = TRUE; // (2)
  1708. }
  1709. else if( gRootCost < pAdapt->STAInfo.DesignatedCost )
  1710. {
  1711. becomeDesignated = TRUE; // (3)
  1712. }
  1713. else if( gRootCost == pAdapt->STAInfo.DesignatedCost )
  1714. {
  1715. // Compare the link's designated bridge to our own ID
  1716. cmp = BrdgSTABridgeIDCmp(gOurID, pAdapt->STAInfo.DesignatedBridgeID);
  1717. if( cmp == -1 )
  1718. {
  1719. becomeDesignated = TRUE; // (4)
  1720. }
  1721. else if( cmp == 0 )
  1722. {
  1723. if( pAdapt->STAInfo.ID < pAdapt->STAInfo.DesignatedPort )
  1724. {
  1725. becomeDesignated = TRUE; // (5)
  1726. }
  1727. else
  1728. {
  1729. // If this SAFEASSERT fires, we should have succeeded on test (1)
  1730. SAFEASSERT( pAdapt->STAInfo.ID > pAdapt->STAInfo.DesignatedPort );
  1731. }
  1732. }
  1733. }
  1734. }
  1735. if( becomeDesignated )
  1736. {
  1737. BrdgSTABecomeDesignatedPort( pAdapt );
  1738. }
  1739. }
  1740. }
  1741. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  1742. }
  1743. BOOLEAN
  1744. BrdgSTATopologyChangeDetected()
  1745. /*++
  1746. Routine Description:
  1747. Takes appropriate action when a topology change is detected. If we are
  1748. the root, this consists of setting the TopologyChange flag in future
  1749. BPDUs until the expiry of the gTopologyChangeTimer. If we are not the
  1750. root, this consists of sending a TCN BPDU periodically until it is
  1751. acknowledged
  1752. Arguments:
  1753. None
  1754. Return Value:
  1755. TRUE means the caller should arrange to send a TCN BPDU from outside the
  1756. gSTALock. FALSE means it is not necessary to send such a packet.
  1757. Locking Constraints:
  1758. ASSUMES the caller has acquired gSTALock
  1759. --*/
  1760. {
  1761. BOOLEAN rc = FALSE;
  1762. if( BrdgSTAWeAreRoot() )
  1763. {
  1764. BrdgSTAUpdateTopologyChange( TRUE );
  1765. BrdgSTASetTimerWithSTATime( &gTopologyChangeTimer, DEFAULT_MAX_AGE + DEFAULT_FORWARD_DELAY, FALSE /*Not periodic*/ );
  1766. }
  1767. else
  1768. {
  1769. rc = TRUE;
  1770. BrdgSTASetTimerWithSTATime( &gTopologyChangeNotificationTimer, DEFAULT_HELLO_TIME, FALSE /*Not periodic*/ );
  1771. }
  1772. gTopologyChangeDetected = TRUE;
  1773. return rc;
  1774. }
  1775. VOID
  1776. BrdgSTAMakeForwarding(
  1777. IN PADAPT pAdapt
  1778. )
  1779. /*++
  1780. Routine Description:
  1781. Starts the process of putting an adapter in the forwarding state.
  1782. Adapters must pass through the Listening and Learning states before entering
  1783. the Forwarding state.
  1784. Arguments:
  1785. pAdapt The adapter
  1786. Return Value:
  1787. None
  1788. Locking Constraints:
  1789. None
  1790. --*/
  1791. {
  1792. if( pAdapt->State == Blocking )
  1793. {
  1794. BrdgSTASetAdapterState( pAdapt, Listening );
  1795. BrdgSTASetTimerWithSTATime( &pAdapt->STAInfo.ForwardDelayTimer, gForwardDelay, FALSE /*Not periodic*/ );
  1796. }
  1797. }
  1798. BOOLEAN
  1799. BrdgSTAMakeBlocking(
  1800. IN PADAPT pAdapt
  1801. )
  1802. /*++
  1803. Routine Description:
  1804. Puts an adapter in the blocking state
  1805. Arguments:
  1806. pAdapt The adapter
  1807. Return Value:
  1808. TRUE means the caller should arrange to send a TCN BPDU from outside the
  1809. gSTALock. FALSE means it is not necessary to send such a packet.
  1810. Locking Constraints:
  1811. ASSUMES the caller has acquired gSTALock
  1812. --*/
  1813. {
  1814. BOOLEAN rc = FALSE;
  1815. if( pAdapt->State != Blocking )
  1816. {
  1817. if( (pAdapt->State == Forwarding) ||
  1818. (pAdapt->State == Learning) )
  1819. {
  1820. rc = BrdgSTATopologyChangeDetected();
  1821. }
  1822. BrdgSTASetAdapterState( pAdapt, Blocking );
  1823. BrdgCancelTimer( &pAdapt->STAInfo.ForwardDelayTimer );
  1824. }
  1825. return rc;
  1826. }
  1827. BOOLEAN
  1828. BrdgSTAPortStateSelection()
  1829. /*++
  1830. Routine Description:
  1831. Examines all ports and puts them in an appropriate state
  1832. Arguments:
  1833. None
  1834. Return Value:
  1835. TRUE means the caller should arrange to send a TCN BPDU from outside the
  1836. gSTALock. FALSE means it is not necessary to send such a packet.
  1837. Locking Constraints:
  1838. ASSUMES the caller has acquired gSTALock
  1839. --*/
  1840. {
  1841. BOOLEAN rc = FALSE;
  1842. LOCK_STATE LockState;
  1843. PADAPT pAdapt;
  1844. SAFEASSERT( gHaveID );
  1845. NdisAcquireReadWriteLock( &gAdapterListLock, FALSE /*read only*/, &LockState );
  1846. for( pAdapt = gAdapterList; pAdapt != NULL; pAdapt = pAdapt->Next )
  1847. {
  1848. if( pAdapt->bSTAInited )
  1849. {
  1850. if( pAdapt == gRootAdapter )
  1851. {
  1852. pAdapt->STAInfo.bConfigPending = FALSE;
  1853. pAdapt->STAInfo.bTopologyChangeAck = FALSE;
  1854. BrdgSTAMakeForwarding( pAdapt );
  1855. }
  1856. else if( (BrdgSTABridgeIDCmp(pAdapt->STAInfo.DesignatedBridgeID, gOurID) == 0) &&
  1857. (pAdapt->STAInfo.DesignatedPort == pAdapt->STAInfo.ID) )
  1858. {
  1859. // This port is a designated port.
  1860. BrdgCancelTimer( &pAdapt->STAInfo.MessageAgeTimer );
  1861. pAdapt->STAInfo.LastConfigTime = 0L;
  1862. BrdgSTAMakeForwarding( pAdapt );
  1863. }
  1864. else
  1865. {
  1866. pAdapt->STAInfo.bConfigPending = FALSE;
  1867. pAdapt->STAInfo.bTopologyChangeAck = FALSE;
  1868. rc = BrdgSTAMakeBlocking( pAdapt );
  1869. }
  1870. }
  1871. }
  1872. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  1873. return rc;
  1874. }
  1875. VOID
  1876. BrdgSTATopologyChangeAcknowledged()
  1877. /*++
  1878. Routine Description:
  1879. Called when we receive an acknowledgement from the root bridge that
  1880. our topology change notification has been noted.
  1881. Arguments:
  1882. None
  1883. Return Value:
  1884. None
  1885. Locking Constraints:
  1886. ASSUMES the caller has acquired gSTALock
  1887. --*/
  1888. {
  1889. DBGPRINT(STA, ("BrdgSTATopologyChangeAcknowledged\n"));
  1890. gTopologyChangeDetected = FALSE;
  1891. BrdgCancelTimer( &gTopologyChangeNotificationTimer );
  1892. }
  1893. VOID
  1894. BrdgSTAAcknowledgeTopologyChange(
  1895. IN PADAPT pAdapt
  1896. )
  1897. /*++
  1898. Routine Description:
  1899. Called when we are the root bridge to send a config BPDU acknowledging
  1900. another bridge's topology change notification
  1901. Arguments:
  1902. pAdapt The adapter on which the TCN was received
  1903. Return Value:
  1904. None
  1905. Locking Constraints:
  1906. ASSUMES the caller DOES NOT have gSTALock
  1907. --*/
  1908. {
  1909. DBGPRINT(STA, ("BrdgSTAAcknowledgeTopologyChange\n"));
  1910. pAdapt->STAInfo.bTopologyChangeAck = TRUE;
  1911. BrdgSTATransmitConfig( pAdapt );
  1912. }
  1913. VOID
  1914. BrdgSTAProcessConfigBPDU(
  1915. IN PADAPT pAdapt,
  1916. IN PCONFIG_BPDU pbpdu
  1917. )
  1918. /*++
  1919. Routine Description:
  1920. Processes received BPDU information
  1921. Arguments:
  1922. pAdapt The adapter on which the BPDU was received
  1923. pbpdu The received information
  1924. Return Value:
  1925. None
  1926. Locking Constraints:
  1927. ASSUMES the caller does NOT have gSTALock
  1928. --*/
  1929. {
  1930. BOOLEAN bWasRoot;
  1931. NdisAcquireSpinLock( &gSTALock );
  1932. bWasRoot = BrdgSTAWeAreRoot();
  1933. if( BrdgSTASupersedesPortInfo(pAdapt, pbpdu) )
  1934. {
  1935. BOOLEAN bTransmitTCN = FALSE;
  1936. // The new information is better than what we had before. Use it.
  1937. BrdgSTARecordConfigInfo(pAdapt, pbpdu);
  1938. BrdgSTAConfigUpdate();
  1939. bTransmitTCN = BrdgSTAPortStateSelection();
  1940. if( bWasRoot && (! BrdgSTAWeAreRoot()) )
  1941. {
  1942. // We used to be the root bridge but now we're not!
  1943. DBGPRINT(STA, ("Saw superseding information that made us NOT root on adapter %p\n", pAdapt));
  1944. BrdgCancelTimer( &gHelloTimer );
  1945. if( gTopologyChangeDetected )
  1946. {
  1947. BrdgCancelTimer( &gTopologyChangeTimer );
  1948. bTransmitTCN = TRUE;
  1949. BrdgSTASetTimerWithSTATime( &gTopologyChangeNotificationTimer, DEFAULT_HELLO_TIME, FALSE /*Not periodic*/ );
  1950. }
  1951. }
  1952. if( pAdapt == gRootAdapter )
  1953. {
  1954. // This is the root port. Heed config information from the root and pass along
  1955. // its information.
  1956. BrdgSTARecordTimeoutInfo( pbpdu );
  1957. if( pbpdu->bTopologyChangeAck )
  1958. {
  1959. BrdgSTATopologyChangeAcknowledged();
  1960. }
  1961. // Don't send packets from inside the spin lock
  1962. NdisReleaseSpinLock( &gSTALock );
  1963. BrdgSTAGenerateConfigBPDUs();
  1964. }
  1965. else
  1966. {
  1967. NdisReleaseSpinLock( &gSTALock );
  1968. }
  1969. if( bTransmitTCN )
  1970. {
  1971. BrdgSTATransmitTCNPacket();
  1972. }
  1973. }
  1974. else
  1975. {
  1976. // The received information does not supersede our previous info
  1977. SAFEASSERT( gHaveID );
  1978. if( (BrdgSTABridgeIDCmp(pAdapt->STAInfo.DesignatedBridgeID, gOurID) == 0) &&
  1979. (pAdapt->STAInfo.DesignatedPort == pAdapt->STAInfo.ID) )
  1980. {
  1981. NdisReleaseSpinLock( &gSTALock );
  1982. // This is the designated port for this link, and the information we just received
  1983. // is inferior to the information we already have. Reply by sending out our own info.
  1984. BrdgSTATransmitConfig(pAdapt);
  1985. }
  1986. else
  1987. {
  1988. NdisReleaseSpinLock( &gSTALock );
  1989. }
  1990. }
  1991. }
  1992. VOID
  1993. BrdgSTAProcessTCNBPDU(
  1994. IN PADAPT pAdapt
  1995. )
  1996. /*++
  1997. Routine Description:
  1998. Processes a received TopologyChangeNotification BPDU
  1999. Arguments:
  2000. pAdapt The adapter on which the TCN was received
  2001. Return Value:
  2002. None
  2003. Locking Constraints:
  2004. ASSUMES the caller does NOT have gSTALock
  2005. --*/
  2006. {
  2007. DBGPRINT(STA, ("BrdgSTAProcessTCNBPDU()\n"));
  2008. SAFEASSERT( gHaveID );
  2009. NdisAcquireSpinLock( &gSTALock );
  2010. if( (BrdgSTABridgeIDCmp(pAdapt->STAInfo.DesignatedBridgeID, gOurID) == 0) &&
  2011. (pAdapt->STAInfo.DesignatedPort == pAdapt->STAInfo.ID) )
  2012. {
  2013. BOOLEAN bTransmitTCN = FALSE;
  2014. // This is a designated port.
  2015. bTransmitTCN = BrdgSTATopologyChangeDetected();
  2016. NdisReleaseSpinLock( &gSTALock );
  2017. if( bTransmitTCN )
  2018. {
  2019. BrdgSTATransmitTCNPacket();
  2020. }
  2021. BrdgSTAAcknowledgeTopologyChange(pAdapt);
  2022. }
  2023. else
  2024. {
  2025. NdisReleaseSpinLock( &gSTALock );
  2026. }
  2027. }
  2028. VOID
  2029. BrdgSTAHelloTimerExpiry(
  2030. IN PVOID Unused
  2031. )
  2032. /*++
  2033. Routine Description:
  2034. Called when the Hello Timer expires. Sends another Config BPDU.
  2035. Arguments:
  2036. Unused
  2037. Return Value:
  2038. None
  2039. Locking Constraints:
  2040. ASSUMES the caller does NOT have gSTALock
  2041. --*/
  2042. {
  2043. BrdgSTAGenerateConfigBPDUs();
  2044. }
  2045. VOID
  2046. BrdgSTAMessageAgeTimerExpiry(
  2047. IN PVOID Context
  2048. )
  2049. /*++
  2050. Routine Description:
  2051. Called when the Message Age Timer expires. Recalculates STA information
  2052. given the fact that no bridge is being heard on the given port anymore.
  2053. Arguments:
  2054. Context The adapter on which the timer expired
  2055. Return Value:
  2056. None
  2057. Locking Constraints:
  2058. ASSUMES the caller does NOT have gSTALock
  2059. --*/
  2060. {
  2061. PADAPT pAdapt;
  2062. BOOLEAN bWasRoot, bTransmitTCN = FALSE;
  2063. NdisAcquireSpinLock( &gSTALock );
  2064. pAdapt = (PADAPT)Context;
  2065. pAdapt->STAInfo.LastConfigTime = 0L;
  2066. bWasRoot = BrdgSTAWeAreRoot();
  2067. BrdgSTABecomeDesignatedPort(pAdapt);
  2068. BrdgSTAConfigUpdate();
  2069. bTransmitTCN = BrdgSTAPortStateSelection();
  2070. if( BrdgSTAWeAreRoot() && (! bWasRoot) )
  2071. {
  2072. DBGPRINT(STA, ("Became root through message age timer expiry of %p\n", pAdapt));
  2073. // We just became root.
  2074. gMaxAge = DEFAULT_MAX_AGE;
  2075. gHelloTime = DEFAULT_HELLO_TIME;
  2076. gForwardDelay = DEFAULT_FORWARD_DELAY;
  2077. bTransmitTCN = BrdgSTATopologyChangeDetected();
  2078. BrdgCancelTimer( &gTopologyChangeNotificationTimer );
  2079. NdisReleaseSpinLock( &gSTALock );
  2080. BrdgSTAGenerateConfigBPDUs();
  2081. BrdgSTASetTimerWithSTATime( &gHelloTimer, gHelloTime, TRUE /*Periodic*/ );
  2082. }
  2083. else
  2084. {
  2085. NdisReleaseSpinLock( &gSTALock );
  2086. }
  2087. if( bTransmitTCN )
  2088. {
  2089. BrdgSTATransmitTCNPacket();
  2090. }
  2091. }
  2092. VOID
  2093. BrdgSTAForwardDelayTimerExpiry(
  2094. IN PVOID Context
  2095. )
  2096. /*++
  2097. Routine Description:
  2098. Called when the Forward Delay Timer expires. Continues stepping an
  2099. adapter through the process of becoming Forwarding.
  2100. Arguments:
  2101. Context The adapter on which the timer expired
  2102. Return Value:
  2103. None
  2104. Locking Constraints:
  2105. ASSUMES the caller does NOT have gSTALock
  2106. --*/
  2107. {
  2108. PADAPT pAdapt = (PADAPT)Context;
  2109. BOOLEAN bTransmitTCN = FALSE;
  2110. NdisAcquireSpinLock( &gSTALock );
  2111. SAFEASSERT( gHaveID );
  2112. if( pAdapt->State == Listening )
  2113. {
  2114. // Move to learning state
  2115. BrdgSTASetAdapterState( pAdapt, Learning );
  2116. BrdgSTASetTimerWithSTATime( &pAdapt->STAInfo.ForwardDelayTimer, gForwardDelay, FALSE /*Not periodic*/ );
  2117. }
  2118. else if( pAdapt->State == Learning )
  2119. {
  2120. LOCK_STATE LockState;
  2121. PADAPT anAdapt;
  2122. // Move to forwarding state
  2123. BrdgSTASetAdapterState( pAdapt, Forwarding );
  2124. // If we are the designated port on any link, we need to signal a topology change
  2125. // notification.
  2126. NdisAcquireReadWriteLock( &gAdapterListLock, FALSE/*Read-only*/, &LockState );
  2127. for( anAdapt = gAdapterList; anAdapt != NULL; anAdapt = anAdapt->Next )
  2128. {
  2129. if( anAdapt->bSTAInited )
  2130. {
  2131. if( BrdgSTABridgeIDCmp(anAdapt->STAInfo.DesignatedBridgeID, gOurID) == 0 )
  2132. {
  2133. bTransmitTCN = BrdgSTATopologyChangeDetected();
  2134. }
  2135. }
  2136. }
  2137. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  2138. }
  2139. NdisReleaseSpinLock( &gSTALock );
  2140. if( bTransmitTCN )
  2141. {
  2142. BrdgSTATransmitTCNPacket();
  2143. }
  2144. }
  2145. VOID
  2146. BrdgSTATopologyChangeNotificationTimerExpiry(
  2147. IN PVOID Unused
  2148. )
  2149. /*++
  2150. Routine Description:
  2151. Called when the Topology Change Notification Timer expires.
  2152. Transmits another TCN packet.
  2153. Arguments:
  2154. Unused
  2155. Return Value:
  2156. None
  2157. Locking Constraints:
  2158. ASSUMES the caller does NOT have gSTALock
  2159. --*/
  2160. {
  2161. if (BrdgFwdBridgingNetworks())
  2162. {
  2163. BrdgSTATransmitTCNPacket();
  2164. BrdgSTASetTimerWithSTATime( &gTopologyChangeNotificationTimer, DEFAULT_HELLO_TIME, FALSE /*Not periodic*/ );
  2165. }
  2166. }
  2167. VOID
  2168. BrdgSTATopologyChangeTimerExpiry(
  2169. IN PVOID Unused
  2170. )
  2171. /*++
  2172. Routine Description:
  2173. Called when the Topology Change Timer expires. Stops setting the TopologyChange
  2174. flag in outbound Config BPDUs.
  2175. Arguments:
  2176. Unused
  2177. Return Value:
  2178. None
  2179. Locking Constraints:
  2180. ASSUMES the caller does NOT have gSTALock
  2181. --*/
  2182. {
  2183. NdisAcquireSpinLock( &gSTALock );
  2184. gTopologyChangeDetected = FALSE;
  2185. BrdgSTAUpdateTopologyChange( FALSE );
  2186. NdisReleaseSpinLock( &gSTALock );
  2187. }
  2188. VOID
  2189. BrdgSTAHoldTimerExpiry(
  2190. IN PVOID Context
  2191. )
  2192. /*++
  2193. Routine Description:
  2194. Called when the Hold Timer expires. Sends a Config BPDU.
  2195. Arguments:
  2196. Context The adapter on which the timer expired
  2197. Return Value:
  2198. None
  2199. Locking Constraints:
  2200. ASSUMES the caller does NOT have gSTALock
  2201. --*/
  2202. {
  2203. PADAPT pAdapt = (PADAPT)Context;
  2204. NdisAcquireSpinLock( &gSTALock );
  2205. if( pAdapt->STAInfo.bConfigPending )
  2206. {
  2207. NdisReleaseSpinLock( &gSTALock );
  2208. BrdgSTATransmitConfig( pAdapt );
  2209. }
  2210. else
  2211. {
  2212. NdisReleaseSpinLock( &gSTALock );
  2213. }
  2214. }
  2215. VOID
  2216. BrdgSTACancelTimersGPO()
  2217. {
  2218. LOCK_STATE LockState;
  2219. PADAPT pAdapt = NULL;
  2220. //
  2221. // We need to cancel the general STA timers.
  2222. //
  2223. BrdgCancelTimer( &gTopologyChangeTimer );
  2224. BrdgCancelTimer( &gTopologyChangeNotificationTimer );
  2225. BrdgCancelTimer( &gHelloTimer );
  2226. //
  2227. // And the individual HoldTimers and MessageAgeTimers
  2228. //
  2229. NdisAcquireReadWriteLock( &gAdapterListLock, FALSE/*Read-only*/, &LockState );
  2230. for( pAdapt = gAdapterList; pAdapt != NULL; pAdapt = pAdapt->Next )
  2231. {
  2232. // This will only cancel the timer if it is running.
  2233. BrdgCancelTimer(&pAdapt->STAInfo.HoldTimer);
  2234. BrdgCancelTimer(&pAdapt->STAInfo.MessageAgeTimer);
  2235. }
  2236. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  2237. }
  2238. VOID
  2239. BrdgSTARestartTimersGPO()
  2240. {
  2241. BrdgSTASetTimerWithSTATime( &gHelloTimer, gHelloTime, TRUE );
  2242. }
  2243. VOID
  2244. BrdgSTAResetSTAInfoGPO()
  2245. {
  2246. BOOLEAN PortSelection = FALSE;
  2247. NdisAcquireSpinLock(&gSTALock);
  2248. PortSelection = BrdgSTAPortStateSelection();
  2249. // Release the spinlock before we send packets over the wire.
  2250. NdisReleaseSpinLock(&gSTALock);
  2251. BrdgSTASetTimerWithSTATime( &gTopologyChangeNotificationTimer, DEFAULT_HELLO_TIME, FALSE /*Not periodic*/ );
  2252. if (PortSelection)
  2253. {
  2254. BrdgSTATransmitTCNPacket();
  2255. }
  2256. if (!BrdgSTAWeAreRoot())
  2257. {
  2258. // Set the timer on the root adapter to expire immediately, this will force us to re-determine
  2259. // our state.
  2260. BrdgSTASetTimerWithSTATime( &gRootAdapter->STAInfo.MessageAgeTimer, 0, FALSE /*Not periodic*/ );
  2261. }
  2262. else
  2263. {
  2264. BrdgSTAGenerateConfigBPDUs();
  2265. }
  2266. BrdgSTARestartTimersGPO();
  2267. }