- Fix timeout values
authorCameron Gutman <aicommander@gmail.com>
Sat, 10 Oct 2009 07:43:39 +0000 (07:43 +0000)
committerCameron Gutman <aicommander@gmail.com>
Sat, 10 Oct 2009 07:43:39 +0000 (07:43 +0000)
 - Don't reply to ARP requests unless they are address to us
 - We now reset the NCE timeout if we receive a packet from the neighbor
 - Fixes ARP flooding (bug 4879)

svn path=/trunk/; revision=43354

reactos/drivers/network/tcpip/include/arp.h
reactos/drivers/network/tcpip/include/neighbor.h
reactos/lib/drivers/ip/network/arp.c
reactos/lib/drivers/ip/network/ip.c
reactos/lib/drivers/ip/network/neighbor.c

index 95a2486..dd9f23a 100644 (file)
@@ -24,7 +24,7 @@ typedef struct ARP_HEADER {
 #define ARP_OPCODE_REPLY   WH2N(0x0002) /* ARP reply */
 
 
-BOOLEAN ARPTransmit(PIP_ADDRESS Address, PIP_INTERFACE Interface);
+BOOLEAN ARPTransmit(PIP_ADDRESS Address, PVOID LinkAddress, PIP_INTERFACE Interface);
 
 VOID ARPReceive(
     PVOID Context,
index f1a43b2..95ea1f9 100644 (file)
@@ -44,11 +44,14 @@ typedef struct NEIGHBOR_CACHE_ENTRY {
 #define NUD_PERMANENT  0x02
 #define NUD_STALE      0x04
 
+/* Number of seconds between ARP transmissions */
+#define ARP_RATE 900
+
 /* Number of seconds before the NCE times out */
-#define ARP_TIMEOUT 30
+#define ARP_TIMEOUT ARP_RATE + 15
 
-/* Number of seconds between ARP transmissions */
-#define ARP_RATE 10
+/* Number of seconds before retransmission */
+#define ARP_TIMEOUT_RETRANSMISSION 5
 
 extern NEIGHBOR_CACHE_TABLE NeighborCache[NB_HASHMASK + 1];
 
@@ -98,6 +101,9 @@ ULONG NBCopyNeighbors(
     PIP_INTERFACE Interface,
     PIPARP_ENTRY ArpTable);
 
+VOID NBResetNeighborTimeout(
+    PIP_ADDRESS Address);
+
 #endif /* __NEIGHBOR_H */
 
 /* EOF */
index d8c2f17..3a95612 100644 (file)
@@ -108,7 +108,8 @@ VOID ARPTransmitComplete(
 }
 
 
-BOOLEAN ARPTransmit(PIP_ADDRESS Address, PIP_INTERFACE Interface)
+BOOLEAN ARPTransmit(PIP_ADDRESS Address, PVOID LinkAddress,
+                    PIP_INTERFACE Interface)
 /*
  * FUNCTION: Creates an ARP request and transmits it on a network
  * ARGUMENTS:
@@ -152,7 +153,7 @@ BOOLEAN ARPTransmit(PIP_ADDRESS Address, PIP_INTERFACE Interface)
         (UCHAR)ProtoAddrLen,             /* Protocol address length */
         Interface->Address,              /* Sender's (local) hardware address */
         &Interface->Unicast.Address.IPv4Address,/* Sender's (local) protocol address */
-        NULL,                            /* Don't care */
+        LinkAddress,                     /* Target's (remote) hardware address */
         &Address->Address.IPv4Address,   /* Target's (remote) protocol address */
         ARP_OPCODE_REQUEST);             /* ARP request */
 
@@ -225,7 +226,8 @@ VOID ARPReceive(
             Header->HWAddrLen, 0, ARP_TIMEOUT);
     }
 
-    if (Header->Opcode != ARP_OPCODE_REQUEST)
+    if (Header->Opcode != ARP_OPCODE_REQUEST ||
+        !AddrIsEqual(&Address, &Interface->Unicast))
         return;
 
     /* This is a request for our address. Swap the addresses and
index a47d2ff..f13dd61 100644 (file)
@@ -93,10 +93,12 @@ VOID IPDispatchProtocol(
  */
 {
     UINT Protocol;
+    IP_ADDRESS SrcAddress;
 
     switch (IPPacket->Type) {
     case IP_ADDRESS_V4:
         Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
+        AddrInitIPv4(&SrcAddress, ((PIPv4_HEADER)(IPPacket->Header))->SrcAddr);
         break;
     case IP_ADDRESS_V6:
         /* FIXME: IPv6 adresses not supported */
@@ -107,6 +109,8 @@ VOID IPDispatchProtocol(
         return;
     }
 
+    NBResetNeighborTimeout(&SrcAddress);
+
     if (Protocol < IP_PROTOCOL_TABLE_SIZE)
     {
        /* Call the appropriate protocol handler */
@@ -219,7 +223,7 @@ VOID IPAddInterfaceRoute( PIP_INTERFACE IF ) {
     /* Send a gratuitous ARP packet to update the route caches of
      * other computers */
     if (IF != Loopback)
-       ARPTransmit(NULL, IF);
+       ARPTransmit(NULL, NULL, IF);
 }
 
 BOOLEAN IPRegisterInterface(
index 295ac90..941facc 100644 (file)
@@ -105,20 +105,35 @@ VOID NBTimeout(VOID)
         TcpipAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql);
 
         for (PrevNCE = &NeighborCache[i].Cache;
-             (NCE = *PrevNCE) != NULL;
-             PrevNCE = &NCE->Next) {
+             (NCE = *PrevNCE) != NULL;) {
             /* Check if event timer is running */
             if (NCE->EventTimer > 0)  {
                 ASSERT(!(NCE->State & NUD_PERMANENT));
                 NCE->EventCount++;
-                if (NCE->EventCount % ARP_RATE == 0)
+                if ((NCE->EventCount > ARP_RATE &&
+                     NCE->EventCount % ARP_TIMEOUT_RETRANSMISSION == 0) ||
+                    (NCE->EventCount == ARP_RATE))
+                {
+                    /* We haven't gotten a packet from them in
+                     * EventCount seconds so we mark them as stale
+                     * and solicit now */
+                    NCE->State |= NUD_STALE;
                     NBSendSolicit(NCE);
+                }
                 if (NCE->EventTimer - NCE->EventCount == 0) {
-                    NCE->State |= NUD_STALE;
+                    /* Solicit one last time */
+                    NBSendSolicit(NCE);
 
-                    NCE->EventCount = 0;
+                    /* Unlink and destroy the NCE */
+                    *PrevNCE = NCE->Next;
+
+                    NBFlushPacketQueue(NCE, NDIS_STATUS_REQUEST_ABORTED);
+                    exFreePool(NCE);
+
+                    continue;
                 }
             }
+            PrevNCE = &NCE->Next;
         }
 
         TcpipReleaseSpinLock(&NeighborCache[i].Lock, OldIrql);
@@ -188,7 +203,8 @@ VOID NBSendSolicit(PNEIGHBOR_CACHE_ENTRY NCE)
 {
     TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE));
 
-    ARPTransmit(&NCE->Address, NCE->Interface);
+    ARPTransmit(&NCE->Address, NCE->LinkAddress,
+                NCE->Interface);
 }
 
 PNEIGHBOR_CACHE_ENTRY NBAddNeighbor(
@@ -302,6 +318,37 @@ VOID NBUpdateNeighbor(
        NBSendPackets( NCE );
 }
 
+VOID
+NBResetNeighborTimeout(PIP_ADDRESS Address)
+{
+    KIRQL OldIrql;
+    UINT HashValue;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+
+    TI_DbgPrint(DEBUG_NCACHE, ("Resetting NCE timout for 0x%s\n", A2S(Address)));
+
+    HashValue  = *(PULONG)(&Address->Address);
+    HashValue ^= HashValue >> 16;
+    HashValue ^= HashValue >> 8;
+    HashValue ^= HashValue >> 4;
+    HashValue &= NB_HASHMASK;
+
+    TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);
+
+    for (NCE = NeighborCache[HashValue].Cache;
+         NCE != NULL;
+         NCE = NCE->Next)
+    {
+         if (AddrIsEqual(Address, &NCE->Address))
+         {
+             NCE->EventCount = 0;
+             break;
+         }
+    }
+
+    TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
+}
+
 PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor(
   PIP_ADDRESS Address)
 /*