#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];
PIP_INTERFACE Interface,
PIPARP_ENTRY ArpTable);
+VOID NBResetNeighborTimeout(
+ PIP_ADDRESS Address);
+
#endif /* __NEIGHBOR_H */
/* EOF */
}
-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:
(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 */
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
*/
{
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 */
return;
}
+ NBResetNeighborTimeout(&SrcAddress);
+
if (Protocol < IP_PROTOCOL_TABLE_SIZE)
{
/* Call the appropriate protocol handler */
/* 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(
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);
{
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(
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)
/*