Jelajahi Sumber

Move join of IGMP all nodes multicast group.

Joining the all nodes multicast group used to happen implicitly within
IGMP when a link joined its first multicast group. As netcore needs to
keep track of a link's multicast groups now, do it expliciting whenever
a new link comes online.
Chris Stevens 6 tahun lalu
induk
melakukan
55ced27379

+ 12 - 162
drivers/net/netcore/ipv4/igmp.c

@@ -103,12 +103,6 @@ Environment:
 
 #define IGMP_MAX_GROUP_RECORD_COUNT MAX_USHORT
 
-//
-// Define the IPv4 address to which all IGMP general query messages are sent.
-//
-
-#define IGMP_ALL_SYSTEMS_ADDRESS CPU_TO_NETWORK32(0xE0000001)
-
 //
 // Define the IPv4 address to which all IGMPv2 leave messages are sent.
 //
@@ -3238,14 +3232,12 @@ Return Value:
     ULONG Index;
     PNET_PACKET_SIZE_INFORMATION LinkSizeInformation;
     ULONG MaxPacketSize;
-    PIGMP_MULTICAST_GROUP NewGroup;
     PIGMP_LINK NewIgmpLink;
     IGMP_LINK SearchLink;
     KSTATUS Status;
     BOOL TreeLockHeld;
 
     IgmpLink = NULL;
-    NewGroup = NULL;
     NewIgmpLink = NULL;
     TreeLockHeld = FALSE;
 
@@ -3330,46 +3322,6 @@ Return Value:
         }
     }
 
-    //
-    // All multicast hosts are supposed to join the all systems group (but
-    // never report the membership). This is supposed to be done on
-    // initialization, but opt to do it the first indication that multicast
-    // is being used. This saves the system from processing multicast queries
-    // where there is nothing to report.
-    //
-
-    NewGroup = NetpIgmpCreateGroup(NewIgmpLink, IGMP_ALL_SYSTEMS_ADDRESS);
-    if (NewGroup == NULL) {
-        Status = STATUS_INSUFFICIENT_RESOURCES;
-        goto CreateOrLookupLinkEnd;
-    }
-
-    //
-    // The group now has a reference on the IGMP link. Destroying the group
-    // will destroy the link. Prevent cleanup from releasing a link reference.
-    //
-
-    IgmpLink = NewIgmpLink;
-    NewIgmpLink = NULL;
-
-    //
-    // The group must be inserted directly, before the link is added to the
-    // tree. It cannot go through the normal join path for two reasons. 1) The
-    // normal join path updates the link's address filters. At this point, two
-    // threads may be racing to create the IGMP link; the address filters
-    // should not be updated until one is a clear winner. 2) If the all systems
-    // group creation/join were to happen after the new link wins the insert
-    // race, it may still fail, which would break IGMP link dereference. The
-    // dereference path is carefully implemented to synchronously remove the
-    // all systems group and assumes that the last group to remain is the all
-    // systems group. If the all systems group never got added but another
-    // group did, then asserts would fire.
-    //
-
-    INSERT_BEFORE(&(NewGroup->ListEntry), &(IgmpLink->MulticastGroupList));
-    IgmpLink->MulticastGroupCount = 1;
-    NewGroup->JoinCount = 1;
-
     //
     // Attempt to insert the new IGMP link into the tree. If an existing link
     // is found, use that one and destroy the new one.
@@ -3380,28 +3332,9 @@ Return Value:
     TreeLockHeld = TRUE;
     FoundNode = RtlRedBlackTreeSearch(&NetIgmpLinkTree, &(SearchLink.Node));
     if (FoundNode == NULL) {
-
-        //
-        // Before this IGMP link hits the tree and another group can take a
-        // reference on it, make sure the all systems group gets set in the
-        // hardware filter. This is necessary in case the first group being
-        // joined is the all systems group. That join request would be the
-        // second request and would not update the filters.
-        //
-
-        KeAcquireQueuedLock(IgmpLink->Lock);
-        Status = NetpIgmpUpdateAddressFilters(IgmpLink);
-        KeReleaseQueuedLock(IgmpLink->Lock);
-        if (!KSUCCESS(Status)) {
-            LIST_REMOVE(&(NewGroup->ListEntry));
-            NewGroup->JoinCount = 0;
-            IgmpLink->MulticastGroupCount = 0;
-            IgmpLink = NULL;
-            goto CreateOrLookupLinkEnd;
-        }
-
-        RtlRedBlackTreeInsert(&NetIgmpLinkTree, &(IgmpLink->Node));
-        NewGroup = NULL;
+        RtlRedBlackTreeInsert(&NetIgmpLinkTree, &(NewIgmpLink->Node));
+        IgmpLink = NewIgmpLink;
+        NewIgmpLink = NULL;
 
     } else {
         IgmpLink = RED_BLACK_TREE_VALUE(FoundNode, IGMP_LINK, Node);
@@ -3410,17 +3343,12 @@ Return Value:
     NetpIgmpLinkAddReference(IgmpLink);
     KeReleaseSharedExclusiveLockExclusive(NetIgmpLinkLock);
     TreeLockHeld = FALSE;
-    Status = STATUS_SUCCESS;
 
 CreateOrLookupLinkEnd:
     if (TreeLockHeld != FALSE) {
         KeReleaseSharedExclusiveLockExclusive(NetIgmpLinkLock);
     }
 
-    if (NewGroup != NULL) {
-        NetpIgmpGroupReleaseReference(NewGroup);
-    }
-
     if (NewIgmpLink != NULL) {
         NetpIgmpLinkReleaseReference(NewIgmpLink);
     }
@@ -3570,15 +3498,12 @@ Return Value:
 
 {
 
-    PIGMP_MULTICAST_GROUP Group;
     ULONG OldReferenceCount;
-    KSTATUS Status;
 
     //
     // Acquire the tree lock exclusively before decrementing the reference
     // count. This is necessary to make the decrement and removal from the tree
-    // atomic. The link is removed from the tree when its reference count
-    // reaches 2 and the all systems group has a join count of 1.
+    // atomic.
     //
 
     KeAcquireSharedExclusiveLockExclusive(NetIgmpLinkLock);
@@ -3587,94 +3512,19 @@ Return Value:
     ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
 
     //
-    // If the third reference was just released, then the last two references
-    // are from the all systems group and from creation. No other multicast
-    // groups have a reference on the link and as the tree lock is held
-    // exclusively, no other thread has a reference on the link. Therefore, if
-    // the all systems group is only around due to the implicit join, then the
-    // link can be removed from the tree and the all systems group can be
-    // destroyed.
-    //
-
-    if (OldReferenceCount == 3) {
-        Group = LIST_VALUE(IgmpLink->MulticastGroupList.Next,
-                           IGMP_MULTICAST_GROUP,
-                           ListEntry);
-
-        //
-        // This better be the only group and be the all systems group. And
-        // since no other thread should have access to the IGMP link, the lock
-        // should not be held - meaning the join count won't be changing.
-        //
-
-        ASSERT(IgmpLink->MulticastGroupCount == 1);
-        ASSERT(Group->Address == IGMP_ALL_SYSTEMS_ADDRESS);
-        ASSERT(KeIsQueuedLockHeld(IgmpLink->Lock) == FALSE);
-
-        //
-        // If only the implicit join is left, remove the group from the link
-        // and update the address filters. On success, the link should have no
-        // more multicast filters set. Remove it from the tree. On failure,
-        // act like nothing happened and leave the group and link alone.
-        //
-
-        if (Group->JoinCount == 1) {
-            KeAcquireQueuedLock(IgmpLink->Lock);
-            LIST_REMOVE(&(Group->ListEntry));
-            IgmpLink->MulticastGroupCount -= 1;
-            Status = NetpIgmpUpdateAddressFilters(IgmpLink);
-            if (!KSUCCESS(Status)) {
-                INSERT_BEFORE(&(Group->ListEntry),
-                              &(IgmpLink->MulticastGroupList));
-
-                IgmpLink->MulticastGroupCount += 1;
-                Group = NULL;
-
-            } else {
-
-                ASSERT(IgmpLink->MulticastGroupCount == 0);
-
-                RtlRedBlackTreeRemove(&NetIgmpLinkTree, &(IgmpLink->Node));
-                IgmpLink->Node.Parent = NULL;
-                Group->JoinCount -= 1;
-            }
-
-            KeReleaseQueuedLock(IgmpLink->Lock);
-
-        //
-        // Otherwise the all systems group is still in use. When the group is
-        // left, the link will be looked up, bumping the reference count to 3.
-        // Then the group will be left and the link will be dereferenced,
-        // invoking this code path again, but with the group's join count at 1.
-        //
-
-        } else {
-            Group = NULL;
-        }
-
-        KeReleaseSharedExclusiveLockExclusive(NetIgmpLinkLock);
-
-        //
-        // If the group and link got removed, destroy the group. This should
-        // release the 2nd to last reference on the link.
-        //
-
-        if (Group != NULL) {
-            NetpIgmpGroupReleaseReference(Group);
-        }
-
-    //
-    // If this is the second to last reference, then the only remaining
-    // reference is the one added by creation. No multicast groups have a
-    // reference on the link and it should have already been removed from the
-    // link tree.
+    // If the second reference was just released, then the last references is
+    // from creation. No multicast groups have a reference on the link and as
+    // the tree lock is held exclusively, no other threads have references on
+    // the link. Therefore, the link can be removed from the tree.
     //
 
-    } else if (OldReferenceCount == 2) {
+    if (OldReferenceCount == 2) {
 
+        ASSERT(LIST_EMPTY(&(IgmpLink->MulticastGroupList)) != FALSE);
         ASSERT(IgmpLink->MulticastGroupCount == 0);
-        ASSERT(IgmpLink->Node.Parent == NULL);
 
+        RtlRedBlackTreeRemove(&NetIgmpLinkTree, &(IgmpLink->Node));
+        IgmpLink->Node.Parent = NULL;
         KeReleaseSharedExclusiveLockExclusive(NetIgmpLinkLock);
         NetpIgmpLinkReleaseReference(IgmpLink);
 

+ 16 - 0
drivers/net/netcore/ipv4/ip4.c

@@ -453,6 +453,7 @@ Return Value:
 
     PNET_LINK_ADDRESS_ENTRY AddressEntry;
     IP4_ADDRESS InitialAddress;
+    IP4_ADDRESS MulticastAddress;
     KSTATUS Status;
 
     //
@@ -475,6 +476,21 @@ Return Value:
         goto Ip4InitializeLinkEnd;
     }
 
+    //
+    // Every IPv4 node should join the all systems multicast group.
+    //
+
+    RtlZeroMemory(&MulticastAddress, sizeof(IP4_ADDRESS));
+    MulticastAddress.Domain = NetDomainIp4;
+    MulticastAddress.Address = IGMP_ALL_SYSTEMS_ADDRESS;
+    Status = NetJoinLinkMulticastGroup(Link,
+                                       AddressEntry,
+                                       (PNETWORK_ADDRESS)&MulticastAddress);
+
+    if (!KSUCCESS(Status)) {
+        goto Ip4InitializeLinkEnd;
+    }
+
 Ip4InitializeLinkEnd:
     if (!KSUCCESS(Status)) {
         if (AddressEntry != NULL) {

+ 15 - 13
drivers/net/netcore/mcast.c

@@ -182,9 +182,9 @@ Return Value:
                            ListEntry);
 
         LIST_REMOVE(&(Group->ListEntry));
-        NetpLeaveLinkMulticastGroup(Group->Link,
-                                    Group->LinkAddress,
-                                    &(Group->MulticastAddress));
+        NetLeaveLinkMulticastGroup(Group->Link,
+                                   Group->LinkAddress,
+                                   &(Group->MulticastAddress));
 
         NetpDestroySocketMulticastGroup(Group);
     }
@@ -292,9 +292,9 @@ Return Value:
     // leave requests.
     //
 
-    Status = NetpJoinLinkMulticastGroup(LinkResult.Link,
-                                        LinkResult.LinkAddress,
-                                        &(Request->MulticastAddress));
+    Status = NetJoinLinkMulticastGroup(LinkResult.Link,
+                                       LinkResult.LinkAddress,
+                                       &(Request->MulticastAddress));
 
     if (!KSUCCESS(Status)) {
         goto SocketJoinMulticastGroupEnd;
@@ -351,9 +351,9 @@ Return Value:
 {
 
     PNET_SOCKET_MULTICAST_GROUP Group;
-    PNET_NETWORK_ENTRY Network;
     NET_LINK_LOCAL_ADDRESS LinkResult;
     BOOL LockHeld;
+    PNET_NETWORK_ENTRY Network;
     KSTATUS Status;
 
     Group = NULL;
@@ -411,9 +411,9 @@ Return Value:
     // individual socket's lock.
     //
 
-    Status = NetpLeaveLinkMulticastGroup(Group->Link,
-                                         Group->LinkAddress,
-                                         &(Group->MulticastAddress));
+    Status = NetLeaveLinkMulticastGroup(Group->Link,
+                                        Group->LinkAddress,
+                                        &(Group->MulticastAddress));
 
     if (!KSUCCESS(Status)) {
         goto SocketLeaveMulticastGroupEnd;
@@ -585,8 +585,9 @@ GetSocketMulticastInterface:
     return Status;
 }
 
+NET_API
 KSTATUS
-NetpJoinLinkMulticastGroup (
+NetJoinLinkMulticastGroup (
     PNET_LINK Link,
     PNET_LINK_ADDRESS_ENTRY LinkAddress,
     PNETWORK_ADDRESS MulticastAddress
@@ -718,7 +719,7 @@ Return Value:
     Request.MulticastAddress = MulticastAddress;
     Status = Network->Interface.JoinLeaveMulticastGroup(&Request, TRUE);
     if (!KSUCCESS(Status)) {
-        NetpLeaveLinkMulticastGroup(Link, LinkAddress, MulticastAddress);
+        NetLeaveLinkMulticastGroup(Link, LinkAddress, MulticastAddress);
         goto LinkJoinMulticastGroupEnd;
     }
 
@@ -734,8 +735,9 @@ LinkJoinMulticastGroupEnd:
     return Status;
 }
 
+NET_API
 KSTATUS
-NetpLeaveLinkMulticastGroup (
+NetLeaveLinkMulticastGroup (
     PNET_LINK Link,
     PNET_LINK_ADDRESS_ENTRY LinkAddress,
     PNETWORK_ADDRESS MulticastAddress

+ 0 - 65
drivers/net/netcore/netcore.h

@@ -268,71 +268,6 @@ Return Value:
 
 --*/
 
-KSTATUS
-NetpJoinLinkMulticastGroup (
-    PNET_LINK Link,
-    PNET_LINK_ADDRESS_ENTRY LinkAddress,
-    PNETWORK_ADDRESS MulticastAddress
-    );
-
-/*++
-
-Routine Description:
-
-    This routine joins the multicast group on a link. If this is the first
-    request to join the supplied multicast group on the link, then the hardware
-    is reprogrammed to include messages to the multicast group's physical layer
-    address and the network is invoked to announce the join via a
-    network-specific protocol.
-
-Arguments:
-
-    Link - Supplies a pointer to the network link joining the multicast group.
-
-    LinkAddress - Supplies a pointer to the link address entry via which the
-        link will join the group.
-
-    MulticastAddress - Supplies a pointer to the multicast address of the group
-        to join.
-
-Return Value:
-
-    Status code.
-
---*/
-
-KSTATUS
-NetpLeaveLinkMulticastGroup (
-    PNET_LINK Link,
-    PNET_LINK_ADDRESS_ENTRY LinkAddress,
-    PNETWORK_ADDRESS MulticastAddress
-    );
-
-/*++
-
-Routine Description:
-
-    This routine removes a link from a multicast. If this is the last request
-    to leave a multicast group on the link, then the hardware is reprogrammed
-    to filter out messages to the multicast group and a network-specific
-    protocol is invoked to announce the link is leaving the group.
-
-Arguments:
-
-    Link - Supplies a pointer to the network link leaving the multicast group.
-
-    LinkAddress - Supplies a pointer to the link address entry via which the
-        link will leave the group.
-
-    MulticastAddress - Supplies a pointer to the multicast address of the group
-        to leave.
-
-Return Value:
-
-    Status code.
-
---*/
-
 //
 // Prototypes to the entry points for built in protocols.
 //

+ 6 - 0
include/minoca/net/igmp.h

@@ -33,6 +33,12 @@ Author:
 // ---------------------------------------------------------------- Definitions
 //
 
+//
+// Define the IPv4 address to which all IGMP general query messages are sent.
+//
+
+#define IGMP_ALL_SYSTEMS_ADDRESS CPU_TO_NETWORK32(0xE0000001)
+
 //
 // ------------------------------------------------------ Data Type Definitions
 //

+ 67 - 0
include/minoca/net/netdrv.h

@@ -3865,6 +3865,73 @@ Return Value:
 
 --*/
 
+NET_API
+KSTATUS
+NetJoinLinkMulticastGroup (
+    PNET_LINK Link,
+    PNET_LINK_ADDRESS_ENTRY LinkAddress,
+    PNETWORK_ADDRESS MulticastAddress
+    );
+
+/*++
+
+Routine Description:
+
+    This routine joins the multicast group on a link. If this is the first
+    request to join the supplied multicast group on the link, then the hardware
+    is reprogrammed to include messages to the multicast group's physical layer
+    address and the network is invoked to announce the join via a
+    network-specific protocol.
+
+Arguments:
+
+    Link - Supplies a pointer to the network link joining the multicast group.
+
+    LinkAddress - Supplies a pointer to the link address entry via which the
+        link will join the group.
+
+    MulticastAddress - Supplies a pointer to the multicast address of the group
+        to join.
+
+Return Value:
+
+    Status code.
+
+--*/
+
+NET_API
+KSTATUS
+NetLeaveLinkMulticastGroup (
+    PNET_LINK Link,
+    PNET_LINK_ADDRESS_ENTRY LinkAddress,
+    PNETWORK_ADDRESS MulticastAddress
+    );
+
+/*++
+
+Routine Description:
+
+    This routine removes a link from a multicast. If this is the last request
+    to leave a multicast group on the link, then the hardware is reprogrammed
+    to filter out messages to the multicast group and a network-specific
+    protocol is invoked to announce the link is leaving the group.
+
+Arguments:
+
+    Link - Supplies a pointer to the network link leaving the multicast group.
+
+    LinkAddress - Supplies a pointer to the link address entry via which the
+        link will leave the group.
+
+    MulticastAddress - Supplies a pointer to the multicast address of the group
+        to leave.
+
+Return Value:
+
+    Status code.
+
+--*/
+
 //
 // Link-specific definitions.
 //