/*++ Copyright (c) 1996 Microsoft Corporation Module Name: arppkt.c - ATMARP Packet Routines. Abstract: Routines that build and parse ARP packets. Revision History: Who When What -------- -------- ---------------------------------------------- arvindm 07-29-96 Created Notes: --*/ #include #define _FILENUMBER 'TKPA' VOID AtmArpSendPacketOnVc( IN PATMARP_VC pVc LOCKIN NOLOCKOUT, IN PNDIS_PACKET pNdisPacket ) /*++ Routine Description: Send a packet on the specified VC. Apart from calling NDIS to do the job, we refresh the aging timer on this VC. Arguments: pVc - Pointer to ATMARP VC pNdisPacket - Pointer to packet to be sent. Return Value: None --*/ { NDIS_HANDLE NdisVcHandle; if (AA_IS_FLAG_SET( pVc->Flags, AA_VC_CALL_STATE_MASK, AA_VC_CALL_STATE_ACTIVE) && !AA_IS_VC_GOING_DOWN(pVc)) { // // A call is active on this VC, so send the packet. // AtmArpRefreshTimer(&(pVc->Timer)); NdisVcHandle = pVc->NdisVcHandle; #ifdef VC_REFS_ON_SENDS AtmArpReferenceVc(pVc); // SendPacketOnVc #endif // VC_REFS_ON_SENDS pVc->OutstandingSends++; // SendPacketOnVc AA_RELEASE_VC_LOCK(pVc); AADEBUGP(AAD_EXTRA_LOUD+50, ("SendPacketOnVc: pVc 0x%x, Pkt 0x%x, VcHandle 0x%x\n", pVc, pNdisPacket, NdisVcHandle)); #ifdef PERF AadLogSendUpdate(pNdisPacket); #endif // PERF NDIS_CO_SEND_PACKETS( NdisVcHandle, &pNdisPacket, 1 ); } else { if (!AA_IS_VC_GOING_DOWN(pVc)) { // // Call must be in progress. Queue this packet; it will // be sent as soon as the call is fully set up. // AtmArpQueuePacketOnVc(pVc, pNdisPacket); AA_RELEASE_VC_LOCK(pVc); } else { // // This VC is going down. Complete the send with a failure. // #ifdef VC_REFS_ON_SENDS AtmArpReferenceVc(pVc); // SendPacketOnVc2 #endif // VC_REFS_ON_SENDS pVc->OutstandingSends++; // SendPacketOnVc - failure completion AA_RELEASE_VC_LOCK(pVc); #if DBG #if DBG_CO_SEND { PULONG pContext; pContext = (PULONG)&(pNdisPacket->WrapperReserved[0]);; *pContext = 'AaAa'; } #endif #endif AtmArpCoSendCompleteHandler( NDIS_STATUS_FAILURE, (NDIS_HANDLE)pVc, pNdisPacket ); } } return; } PNDIS_PACKET AtmArpBuildARPPacket( IN USHORT OperationType, IN PATMARP_INTERFACE pInterface, IN PUCHAR * ppArpPacket, IN PAA_ARP_PKT_CONTENTS pArpContents ) /*++ Routine Description: Build a generic ARP packet with the given attributes. Arguments: OperationType - Op type (e.g. ARP Request, ARP Reply) pInterface - Pointer to ATMARP Interface ppArpPacket - Pointer to place to return start of packet pArpContents - Pointer to structure describing contents Return Value: Pointer to NDIS packet if successful, NULL otherwise. If successful, we also set *ppArpPacket to point to the first byte in the constructed ARP packet. --*/ { PNDIS_PACKET pNdisPacket; PNDIS_BUFFER pNdisBuffer; ULONG BufferLength; // Length of ARP packet ULONG Length; // Temp length PUCHAR pPkt; // Start of allocated packet PUCHAR pBuf; // Used to walk the packet PAA_ARP_PKT_HEADER pArpHeader; // ARP packet header // // Calculate the length of what we're about to build // BufferLength = AA_ARP_PKT_HEADER_LENGTH + (pArpContents->SrcAtmNumberTypeLen & ~AA_PKT_ATM_ADDRESS_BIT) + (pArpContents->SrcAtmSubaddrTypeLen & ~AA_PKT_ATM_ADDRESS_BIT) + (pArpContents->DstAtmNumberTypeLen & ~AA_PKT_ATM_ADDRESS_BIT) + (pArpContents->DstAtmSubaddrTypeLen & ~AA_PKT_ATM_ADDRESS_BIT) + 0; if (pArpContents->pSrcIPAddress != (PUCHAR)NULL) { BufferLength += AA_IPV4_ADDRESS_LENGTH; } if (pArpContents->pDstIPAddress != (PUCHAR)NULL) { BufferLength += AA_IPV4_ADDRESS_LENGTH; } pNdisPacket = AtmArpAllocatePacket(pInterface); if (pNdisPacket != (PNDIS_PACKET)NULL) { pNdisBuffer = AtmArpAllocateProtoBuffer( pInterface, BufferLength, &(pPkt) ); if (pNdisBuffer != (PNDIS_BUFFER)NULL) { // // Return value: // *ppArpPacket = pPkt; // // Initialize packet with all 0's // AA_SET_MEM(pPkt, 0, BufferLength); pArpHeader = (PAA_ARP_PKT_HEADER)pPkt; // // Fixed-location fields: // pArpHeader->LLCSNAPHeader = AtmArpLlcSnapHeader; pArpHeader->LLCSNAPHeader.EtherType = NET_SHORT(AA_PKT_ETHERTYPE_ARP); pArpHeader->hrd = NET_SHORT(AA_PKT_ATM_FORUM_AF); pArpHeader->pro = NET_SHORT(AA_PKT_PRO_IP); pArpHeader->op = NET_SHORT(OperationType); // // Now fill in the variable length fields // pBuf = pArpHeader->Variable; // // Source ATM Number // Length = (pArpContents->SrcAtmNumberTypeLen & ~AA_PKT_ATM_ADDRESS_BIT); if (Length > 0) { pArpHeader->shtl = pArpContents->SrcAtmNumberTypeLen; AA_COPY_MEM(pBuf, pArpContents->pSrcAtmNumber, Length); pBuf += Length; } // // Source ATM subaddress // Length = (pArpContents->SrcAtmSubaddrTypeLen & ~AA_PKT_ATM_ADDRESS_BIT); if (Length > 0) { pArpHeader->shtl = pArpContents->SrcAtmSubaddrTypeLen; AA_COPY_MEM(pBuf, pArpContents->pSrcAtmSubaddress, Length); pBuf += Length; } // // Source Protocol (IP) address // if (pArpContents->pSrcIPAddress != (PUCHAR)NULL) { pArpHeader->spln = AA_IPV4_ADDRESS_LENGTH; AA_COPY_MEM(pBuf, pArpContents->pSrcIPAddress, AA_IPV4_ADDRESS_LENGTH); pBuf += AA_IPV4_ADDRESS_LENGTH; } // // Target ATM Number // Length = (pArpContents->DstAtmNumberTypeLen & ~AA_PKT_ATM_ADDRESS_BIT); if (Length > 0) { pArpHeader->thtl = pArpContents->DstAtmNumberTypeLen; AA_COPY_MEM(pBuf, pArpContents->pDstAtmNumber, Length); pBuf += Length; } // // Target ATM subaddress // Length = (pArpContents->DstAtmSubaddrTypeLen & ~AA_PKT_ATM_ADDRESS_BIT); if (Length > 0) { pArpHeader->thtl = pArpContents->DstAtmSubaddrTypeLen; AA_COPY_MEM(pBuf, pArpContents->pDstAtmSubaddress, Length); pBuf += Length; } // // Target Protocol (IP) address // if (pArpContents->pDstIPAddress != (PUCHAR)NULL) { pArpHeader->tpln = AA_IPV4_ADDRESS_LENGTH; AA_COPY_MEM(pBuf, pArpContents->pDstIPAddress, AA_IPV4_ADDRESS_LENGTH); pBuf += AA_IPV4_ADDRESS_LENGTH; } NdisChainBufferAtFront(pNdisPacket, pNdisBuffer); } else { AtmArpFreePacket(pInterface, pNdisPacket); pNdisPacket = (PNDIS_PACKET)NULL; } } AADEBUGP(AAD_EXTRA_LOUD, ("BldArpPkt: pIf 0x%x, Op %d, NdisPkt 0x%x, NdisBuf 0x%x\n", pInterface, OperationType, pNdisPacket, pNdisBuffer)); return (pNdisPacket); } VOID AtmArpSendARPRequest( PATMARP_INTERFACE pInterface, IP_ADDRESS UNALIGNED * pSrcIPAddress, IP_ADDRESS UNALIGNED * pDstIPAddress ) /*++ Routine Description: Send an ARP Request to the server, for the given interface. Preconditions: the ATM interface is UP, and the AdminState for the interface is IF_STATUS_UP. We first build an ARP Request with the given parameters. Then, if a Best Effort VC to the server's ATM address exists, the packet is sent on this. Other possibilities: - the Best Effort VC to the server is being set up: queue it on the VC - No Best Effort VC to the server exists: Create a new VC on this ATM Entry, make a call with Best Effort flow specs, and queue the request on this VC. Arguments: pInterface - Pointer to ATMARP Interface structure pSrcIPAddress - Pointer to Source IP Address pDstIPAddress - Pointer to Destination IP Address (to be resolved) Return Value: None --*/ { PATMARP_ATM_ENTRY pAtmEntry; // Entry for the server's ATM address PATMARP_VC pVc; // VC to the server PNDIS_PACKET pNdisPacket; PATMARP_FLOW_SPEC pFlowSpec; PUCHAR pArpPacket; // Pointer to ARP packet being constructed AA_ARP_PKT_CONTENTS ArpContents;// Describes the packet we want to build NDIS_STATUS Status; AADEBUGP(AAD_INFO, ("Sending ARP Request on IF 0x%x for IP Addr: %d.%d.%d.%d\n", pInterface, ((PUCHAR)pDstIPAddress)[0], ((PUCHAR)pDstIPAddress)[1], ((PUCHAR)pDstIPAddress)[2], ((PUCHAR)pDstIPAddress)[3] )); AA_ASSERT(pInterface->pCurrentServer != NULL_PATMARP_SERVER_ENTRY); AA_ASSERT(pInterface->pCurrentServer->pAtmEntry != NULL_PATMARP_ATM_ENTRY); // // Prepare the ARP packet contents structure // AA_SET_MEM((PUCHAR)&ArpContents, 0, sizeof(AA_ARP_PKT_CONTENTS)); // // Source ATM Number // ArpContents.pSrcAtmNumber = pInterface->LocalAtmAddress.Address; ArpContents.SrcAtmNumberTypeLen = AA_PKT_ATM_ADDRESS_TO_TYPE_LEN(&(pInterface->LocalAtmAddress)); // // Source IP Address // ArpContents.pSrcIPAddress = (PUCHAR)pSrcIPAddress; // // Target IP Address // ArpContents.pDstIPAddress = (PUCHAR)pDstIPAddress; // // Build the ARP Request // pNdisPacket = AtmArpBuildARPPacket( AA_PKT_OP_TYPE_ARP_REQUEST, pInterface, &pArpPacket, &ArpContents ); if (pNdisPacket != (PNDIS_PACKET)NULL) { // // Find the ATM Entry for the in-use ATMARP Server: // AA_ACQUIRE_IF_LOCK(pInterface); pAtmEntry = pInterface->pCurrentServer->pAtmEntry; AA_RELEASE_IF_LOCK(pInterface); AA_ACQUIRE_AE_LOCK(pAtmEntry); // // Get at the Best Effort VC going to this ATM address: // pVc = pAtmEntry->pBestEffortVc; if (pVc != NULL_PATMARP_VC) { ULONG rc; AA_ACQUIRE_VC_LOCK_DPC(pVc); AtmArpReferenceVc(pVc); // temp ref AA_RELEASE_VC_LOCK_DPC(pVc); AA_RELEASE_AE_LOCK(pAtmEntry); // Not needed anymore // // A VC to the server exists; send this packet on the VC // AA_ACQUIRE_VC_LOCK(pVc); rc = AtmArpDereferenceVc(pVc); // temp ref if (rc != 0) { AtmArpSendPacketOnVc(pVc, pNdisPacket); // // The VC lock is released in SendPacketOnVc // } else { // // The VC has been deref'ed away! Set up pVc for the // check coming up. // pVc = NULL_PATMARP_VC; AA_ACQUIRE_AE_LOCK(pAtmEntry); } } if (pVc == NULL_PATMARP_VC) { // // We don't have an appropriate VC to the server, so create // one, and queue this packet for transmission as soon as // the call is made. // // AtmArpMakeCall needs the caller to hold the ATM Entry lock. // AA_GET_CONTROL_PACKET_SPECS(pInterface, &pFlowSpec); Status = AtmArpMakeCall( pInterface, pAtmEntry, pFlowSpec, pNdisPacket ); // // The AE lock is released within the above. // } } } VOID AtmArpSendInARPRequest( IN PATMARP_VC pVc ) /*++ Routine Description: Send an InATMARP Request on a VC. Arguments: pVc - Pointer to ATMARP VC on which we send the request Return Value: None --*/ { PATMARP_INTERFACE pInterface; PNDIS_PACKET pNdisPacket; PUCHAR pArpPacket; // Pointer to ARP packet being constructed AA_ARP_PKT_CONTENTS ArpContents;// Describes the packet we want to build // // Prepare the ARP packet contents structure // AA_SET_MEM((PUCHAR)&ArpContents, 0, sizeof(AA_ARP_PKT_CONTENTS)); pInterface = pVc->pInterface; // // Source IP Address // ArpContents.pSrcIPAddress = (PUCHAR)&(pInterface->LocalIPAddress.IPAddress); // // Source ATM number // ArpContents.pSrcAtmNumber = pInterface->LocalAtmAddress.Address; ArpContents.SrcAtmNumberTypeLen = AA_PKT_ATM_ADDRESS_TO_TYPE_LEN(&(pInterface->LocalAtmAddress)); // // Build the InATMARP Request packet // pNdisPacket = AtmArpBuildARPPacket( AA_PKT_OP_TYPE_INARP_REQUEST, pInterface, &pArpPacket, &ArpContents ); if (pNdisPacket != (PNDIS_PACKET)NULL) { #ifndef VC_REFS_ON_SENDS AA_ACQUIRE_VC_LOCK(pVc); #endif // VC_REFS_ON_SENDS AtmArpSendPacketOnVc(pVc, pNdisPacket); // // The VC lock is released by SendPacketOnVc // } else { #ifdef VC_REFS_ON_SENDS AA_RELEASE_VC_LOCK(pVc); #endif // VC_REFS_ON_SENDS } } UINT AtmArpCoReceivePacketHandler( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET pNdisPacket ) /*++ Routine Description: This is routine is called when a packet is received on a VC owned by the ATMARP module. If it is an ARP packet, we consume it ourselves. Otherwise, we pass it up to IP. In any case, we refresh the VC aging timer on this VC. Arguments: ProtocolBindingContext - Actually a pointer to our Adapter structure ProtocolVcContext - Actually a pointer to our VC structure pNdisPacket - NDIS packet being received. Return Value: 0 always, because we don't hold on to ARP packets, and we assume IP doesn't either. --*/ { PATMARP_INTERFACE pInterface; PATMARP_VC pVc; UINT TotalLength; // Total bytes in packet PNDIS_BUFFER pNdisBuffer; // Pointer to first buffer UINT BufferLength; UINT IsNonUnicast; // Is this to a non-unicast destn MAC addr? BOOLEAN Discarded; // Are we discarding this packet? PAA_PKT_LLC_SNAP_HEADER pPktHeader; // LLC/SNAP header UINT ReturnCount = 0; #if DBG pPktHeader = NULL; #endif pVc = (PATMARP_VC)ProtocolVcContext; AA_STRUCT_ASSERT(pVc, avc); pInterface = pVc->pInterface; Discarded = FALSE; IsNonUnicast = (UINT)FALSE; if (pInterface->AdminState == IF_STATUS_UP) { // // Refresh VC aging on this VC // AA_ACQUIRE_VC_LOCK(pVc); AtmArpRefreshTimer(&(pVc->Timer)); AA_RELEASE_VC_LOCK(pVc); NdisQueryPacket( pNdisPacket, NULL, NULL, &pNdisBuffer, &TotalLength ); // // We expect atleast the LLC/SNAP header to be present // Note: this precludes Null encapsulation. // if (TotalLength >= AA_PKT_LLC_SNAP_HEADER_LENGTH) { AA_IF_STAT_ADD(pInterface, InOctets, TotalLength); NdisQueryBuffer( pNdisBuffer, (PVOID *)&pPktHeader, &BufferLength ); AADEBUGP(AAD_EXTRA_LOUD, ("Rcv: VC 0x%x, NDISpkt 0x%x, NDISbuf 0x%x, Buflen %d, Totlen %d, Pkthdr 0x%x\n", pVc, pNdisPacket, pNdisBuffer, BufferLength, TotalLength, pPktHeader)); AADEBUGPDUMP(AAD_EXTRA_LOUD+20, pPktHeader, BufferLength); AA_ASSERT(BufferLength >= AA_PKT_LLC_SNAP_HEADER_LENGTH); if (AA_PKT_LLC_SNAP_HEADER_OK(pPktHeader)) { // // If the EtherType is IP, pass up this packet to // the IP layer // if (pPktHeader->EtherType == NET_SHORT(AA_PKT_ETHERTYPE_IP)) { AADEBUGP(AAD_EXTRA_LOUD, ("Rcv: VC 0x%x, NDISpkt 0x%x: EtherType is IP, passing up\n")); #if DBG if (AaDataDebugLevel & AAD_DATA_IN) { IP_ADDRESS IPAddress; if ((pVc->pAtmEntry != NULL_PATMARP_ATM_ENTRY) && (pVc->pAtmEntry->pIpEntryList != NULL_PATMARP_IP_ENTRY)) { IPAddress = pVc->pAtmEntry->pIpEntryList->IPAddress; } else { IPAddress = 0; } AADEBUGP(AAD_WARNING, ("%d <= %d.%d.%d.%d\n", TotalLength, ((PUCHAR)&IPAddress)[0], ((PUCHAR)&IPAddress)[1], ((PUCHAR)&IPAddress)[2], ((PUCHAR)&IPAddress)[3])); } #endif // DBG if (IsNonUnicast) { AA_IF_STAT_INCR(pInterface, InNonUnicastPkts); } else { AA_IF_STAT_INCR(pInterface, InUnicastPkts); } #ifdef _PNP_POWER_ if (NDIS_GET_PACKET_STATUS(pNdisPacket) != NDIS_STATUS_RESOURCES) { UINT HeaderSize; UINT DataSize; #define ATMARP_MIN_1ST_RECV_BUFSIZE 512 HeaderSize = NDIS_GET_PACKET_HEADER_SIZE(pNdisPacket); // // 2/8/1998 JosephJ // We set DataSize to the total payload size, // unless the first buffer is too small to // hold the IP header. In the latter case, // we set DataSize to be the size of the 1st buffer // (minus the LLS/SNAP header size). // // This is to work around a bug in tcpip. // // 2/25/1998 JosephJ // Unfortunately we have to back out YET AGAIN // because large pings (eg ping -l 4000) doesn't // work -- bug#297784 // Hence the "0" in "0 && DataSize" below. // Take out the "0" to put back the per fix. // DataSize = BufferLength - sizeof(AA_PKT_LLC_SNAP_HEADER); if (0 && DataSize >= ATMARP_MIN_1ST_RECV_BUFSIZE) { DataSize = TotalLength - sizeof(AA_PKT_LLC_SNAP_HEADER); } (pInterface->IPRcvPktHandler)( pInterface->IPContext, (PVOID)((PUCHAR)pPktHeader+sizeof(AA_PKT_LLC_SNAP_HEADER)), DataSize, TotalLength, (NDIS_HANDLE)pNdisPacket, sizeof(AA_PKT_LLC_SNAP_HEADER), IsNonUnicast, 0, pNdisBuffer, &ReturnCount #if P2MP ,NULL #endif //P2MP ); } else { (pInterface->IPRcvHandler)( pInterface->IPContext, (PVOID)((PUCHAR)pPktHeader+sizeof(AA_PKT_LLC_SNAP_HEADER)), BufferLength - sizeof(AA_PKT_LLC_SNAP_HEADER), TotalLength - sizeof(AA_PKT_LLC_SNAP_HEADER), (NDIS_HANDLE)pNdisPacket, sizeof(AA_PKT_LLC_SNAP_HEADER), IsNonUnicast #if P2MP ,NULL #endif //P2MP ); } #else // For Win98: (pInterface->IPRcvHandler)( pInterface->IPContext, (PVOID)((PUCHAR)pPktHeader+sizeof(AA_PKT_LLC_SNAP_HEADER)), BufferLength - sizeof(AA_PKT_LLC_SNAP_HEADER), TotalLength - sizeof(AA_PKT_LLC_SNAP_HEADER), (NDIS_HANDLE)pNdisPacket, sizeof(AA_PKT_LLC_SNAP_HEADER), IsNonUnicast #if P2MP ,NULL #endif //P2MP ); #endif // _PNP_POWER_ } else if (pPktHeader->EtherType == NET_SHORT(AA_PKT_ETHERTYPE_ARP)) { // // An ARP packet: we handle it ourselves // AA_ASSERT(BufferLength == TotalLength); AA_IF_STAT_INCR(pInterface, InUnicastPkts); AtmArpHandleARPPacket( pVc, pPktHeader, BufferLength ); } else { // // Discard packet -- bad EtherType // AADEBUGP(AAD_WARNING, ("VC: 0x%x, Pkt hdr 0x%x, bad EtherType 0x%x\n", pVc, pPktHeader, (ULONG)pPktHeader->EtherType)); Discarded = TRUE; AA_IF_STAT_INCR(pInterface, UnknownProtos); } } else { #ifdef IPMCAST Discarded = AtmArpMcProcessPacket( pVc, pNdisPacket, pNdisBuffer, pPktHeader, TotalLength, BufferLength ); #else // // Discard packet -- bad LLC/SNAP // AADEBUGP(AAD_WARNING, ("VC: 0x%x, Pkt hdr 0x%x, bad LLC/SNAP\n", pVc, pPktHeader)); Discarded = TRUE; #endif // IPMCAST } } else { // // Discard packet -- too short // AADEBUGP(AAD_WARNING, ("VC: 0x%x, Pkt hdr 0x%x, too short: %d\n", pVc, pPktHeader, TotalLength)); Discarded = TRUE; } } else { // // Discard packet -- IF down // AADEBUGP(AAD_WARNING, ("pInterface: 0x%x is down, discarding NDIS pkt 0x%x\n", pInterface, pNdisPacket)); Discarded = TRUE; } if (Discarded) { AA_IF_STAT_INCR(pInterface, InDiscards); } return (ReturnCount); } VOID AtmArpHandleARPPacket( IN PATMARP_VC pVc, IN PAA_PKT_LLC_SNAP_HEADER pPktHeader, IN ULONG PacketLength ) /*++ Routine Description: Process a received ARP packet. We complete most of the packet checks here, and then branch off to do different things based on the Op type in the packet. We do not hang on to the packet, i.e. when we return from here, the packet is free. Arguments: pVc - Pointer to ATMARP VC on which packet arrived pPktHeader - Pointer to start of packet (including LLC/SNAP) PacketLength - Length including LLC/SNAP header Return Value: None --*/ { PATMARP_INTERFACE pInterface; PAA_ARP_PKT_HEADER pArpHeader; NDIS_STATUS Status; // // For walking down the packet // UCHAR UNALIGNED * pPacket; // // For storing pointers to the packet contents. We'll need this // if we have to send a reply packet. // AA_ARP_PKT_CONTENTS ArpContents; BOOLEAN SrcAtmBelongsToUs; BOOLEAN SrcIPBelongsToUs; // // Initialize (Important: don't remove the zeroing of ArpContents) // AA_SET_MEM((PUCHAR)&ArpContents, 0, sizeof(AA_ARP_PKT_CONTENTS)); Status = NDIS_STATUS_SUCCESS; pInterface = pVc->pInterface; pArpHeader = STRUCT_OF(AA_ARP_PKT_HEADER, pPktHeader, LLCSNAPHeader); AADEBUGP(AAD_EXTRA_LOUD+10, ("HandleARPPkt: VC 0x%x, IF 0x%x, pPktHdr 0x%x, Len %d\n", pVc, pInterface, pPktHeader, PacketLength)); do { if (PacketLength < AA_ARP_PKT_HEADER_LENGTH) { AADEBUGP(AAD_WARNING, ("HandleARPPkt: IF 0x%x, PacketLength %d < HdrLen %d\n", pInterface, PacketLength, AA_ARP_PKT_HEADER_LENGTH)); Status = NDIS_STATUS_BUFFER_TOO_SHORT; break; } if ((pArpHeader->hrd != NET_SHORT(AA_PKT_HRD)) || (pArpHeader->pro != NET_SHORT(AA_PKT_PRO))) { AADEBUGP(AAD_WARNING, ("HandleARPPkt: IF 0x%x, Bad hdr (%d != %d) or pro (%d != %d)\n", pInterface, pArpHeader->hrd, AA_PKT_HRD, pArpHeader->pro, AA_PKT_PRO)); Status = NDIS_STATUS_NOT_RECOGNIZED; break; } // // Get at the variable part of the packet, and get pointers // to all addresses. // // TBD: add more checks on ATM address lengths and combinations // Note: we check for packet length later. // pPacket = pArpHeader->Variable; // // Source ATM Number // if (pArpHeader->shtl != 0) { ArpContents.SrcAtmNumberTypeLen = pArpHeader->shtl; ArpContents.pSrcAtmNumber = pPacket; pPacket += (pArpHeader->shtl & ~AA_PKT_ATM_ADDRESS_BIT); } // // Source ATM Subaddress // if (pArpHeader->sstl != 0) { ArpContents.SrcAtmSubaddrTypeLen = pArpHeader->sstl; ArpContents.pSrcAtmSubaddress = pPacket; pPacket += (pArpHeader->sstl & ~AA_PKT_ATM_ADDRESS_BIT); } // // Source IP Address. Older 1577 implementations may send an // IP address field filled with all 0's to denote an unspecified // IP address. // if (pArpHeader->spln != 0) { if (pArpHeader->spln != AA_IPV4_ADDRESS_LENGTH) { AADEBUGP(AAD_WARNING, ("HandleARPPkt: IF 0x%x, bad spln %d != %d\n", pInterface, pArpHeader->spln, AA_IPV4_ADDRESS_LENGTH)); Status = NDIS_STATUS_INVALID_ADDRESS; break; } if (!AtmArpIsZeroIPAddress(pPacket)) { ArpContents.pSrcIPAddress = pPacket; } pPacket += AA_IPV4_ADDRESS_LENGTH; } // // Target ATM Number // if (pArpHeader->thtl != 0) { ArpContents.DstAtmNumberTypeLen = pArpHeader->thtl; ArpContents.pDstAtmNumber = pPacket; pPacket += (pArpHeader->thtl & ~AA_PKT_ATM_ADDRESS_BIT); } // // Target ATM Subaddress // if (pArpHeader->tstl != 0) { ArpContents.DstAtmSubaddrTypeLen = pArpHeader->tstl; ArpContents.pDstAtmSubaddress = pPacket; pPacket += (pArpHeader->tstl & ~AA_PKT_ATM_ADDRESS_BIT); } // // Target IP Address [see comments for Source IP Address] // if (pArpHeader->tpln != 0) { if (pArpHeader->tpln != AA_IPV4_ADDRESS_LENGTH) { AADEBUGP(AAD_WARNING, ("HandleARPPkt: IF 0x%x, bad tpln %d != %d\n", pInterface, pArpHeader->tpln, AA_IPV4_ADDRESS_LENGTH)); Status = NDIS_STATUS_INVALID_ADDRESS; break; } if (!AtmArpIsZeroIPAddress(pPacket)) { ArpContents.pDstIPAddress = pPacket; } pPacket += AA_IPV4_ADDRESS_LENGTH; } // // // if ((ULONG)(pPacket - (PUCHAR)pArpHeader) > PacketLength) { AADEBUGP(AAD_WARNING, ("HandleARPPkt: IF 0x%x, pPktHdr 0x%x. Length %d TOO SMALL (want %d)\n", pInterface, pArpHeader, PacketLength, (pPacket - (PUCHAR)pArpHeader))); Status = NDIS_STATUS_BUFFER_TOO_SHORT; break; } // // If this is an ARP NAK packet, swap Source and Target // addresses, in preparation for what follows. This is // because, unlike any other Reply packet where the Source // and Target addresses get swapped, the ARP NAK // packet is a copy of the ARP Request, with only the // Op code changed. // if (NET_SHORT(pArpHeader->op) == AA_PKT_OP_TYPE_ARP_NAK) { UCHAR TypeLen; UCHAR UNALIGNED * pAddress; // // IP Addresses: // pAddress = ArpContents.pSrcIPAddress; ArpContents.pSrcIPAddress = ArpContents.pDstIPAddress; ArpContents.pDstIPAddress = pAddress; // // ATM Number: // TypeLen = ArpContents.SrcAtmNumberTypeLen; ArpContents.SrcAtmNumberTypeLen = ArpContents.DstAtmNumberTypeLen; ArpContents.DstAtmNumberTypeLen = TypeLen; pAddress = ArpContents.pSrcAtmNumber; ArpContents.pSrcAtmNumber = ArpContents.pDstAtmNumber; ArpContents.pDstAtmNumber = pAddress; // // ATM Subaddress: // TypeLen = ArpContents.SrcAtmSubaddrTypeLen; ArpContents.SrcAtmSubaddrTypeLen = ArpContents.DstAtmSubaddrTypeLen; ArpContents.DstAtmSubaddrTypeLen = TypeLen; pAddress = ArpContents.pSrcAtmSubaddress; ArpContents.pSrcAtmSubaddress = ArpContents.pDstAtmSubaddress; ArpContents.pDstAtmSubaddress = pAddress; } SrcIPBelongsToUs = AtmArpIsLocalIPAddress( pInterface, ArpContents.pSrcIPAddress ); SrcAtmBelongsToUs = AtmArpIsLocalAtmAddress( pInterface, ArpContents.pSrcAtmNumber, ArpContents.SrcAtmNumberTypeLen ); // // Check if someone else is claiming to be the owner // of "our" IP address: // if (SrcIPBelongsToUs && !SrcAtmBelongsToUs) { AADEBUGP(AAD_ERROR, ("Pkt 0x%x: src IP is ours, src ATM is bad!\n", pPktHeader)); AA_ACQUIRE_IF_LOCK(pInterface); pInterface->State = IF_STATUS_DOWN; pInterface->LastChangeTime = GetTimeTicks(); AA_RELEASE_IF_LOCK(pInterface); AtmArpStartRegistration(pInterface); Status = NDIS_STATUS_NOT_RECOGNIZED; break; } // // See if this is directed to someone else: if so, drop it. // // // Check if the Target IP address is ours. A null IP address is // acceptable (e.g. [In]ARP Request). // if ((ArpContents.pDstIPAddress != (PUCHAR)NULL) && !AtmArpIsLocalIPAddress(pInterface, ArpContents.pDstIPAddress)) { // // A target IP address is present, and it is not ours // AADEBUGP(AAD_WARNING, ("ArpPkt 0x%x has unknown target IP addr (%d.%d.%d.%d)\n", pPktHeader, ArpContents.pDstIPAddress[0], ArpContents.pDstIPAddress[1], ArpContents.pDstIPAddress[2], ArpContents.pDstIPAddress[3])); Status = NDIS_STATUS_NOT_RECOGNIZED; break; } // // If there is a Target ATM Number, check to see if it is ours. // if ((ArpContents.pDstAtmNumber != (PUCHAR)NULL) && (!AtmArpIsLocalAtmAddress( pInterface, ArpContents.pDstAtmNumber, ArpContents.DstAtmNumberTypeLen)) ) { // // A target ATM number is present, and it is not ours // AADEBUGP(AAD_WARNING, ("ArpPkt 0x%x has unknown target ATM addr (0x%x, 0x%x)\n", pPktHeader, ArpContents.DstAtmNumberTypeLen, ArpContents.pDstAtmNumber)); Status = NDIS_STATUS_NOT_RECOGNIZED; break; } // // Handle the various Op types // switch (NET_SHORT(pArpHeader->op)) { case AA_PKT_OP_TYPE_ARP_REQUEST: AtmArpHandleARPRequest( pVc, pInterface, pArpHeader, &ArpContents ); break; case AA_PKT_OP_TYPE_ARP_REPLY: AtmArpHandleARPReply( pVc, pInterface, pArpHeader, &ArpContents, SrcIPBelongsToUs, SrcAtmBelongsToUs ); break; case AA_PKT_OP_TYPE_ARP_NAK: AtmArpHandleARPNAK( pVc, pInterface, pArpHeader, &ArpContents ); break; case AA_PKT_OP_TYPE_INARP_REQUEST: AtmArpHandleInARPRequest( pVc, pInterface, pArpHeader, &ArpContents ); break; case AA_PKT_OP_TYPE_INARP_REPLY: AtmArpHandleInARPReply( pVc, pInterface, pArpHeader, &ArpContents ); break; default: AADEBUGP(AAD_WARNING, ("HandleARPPkt: IF 0x%x, pArpHdr 0x%x, Op %d not known\n", pInterface, pArpHeader, NET_SHORT(pArpHeader->op))); Status = NDIS_STATUS_NOT_RECOGNIZED; break; } } while (FALSE); return; } VOID AtmArpHandleARPRequest( IN PATMARP_VC pVc, IN PATMARP_INTERFACE pInterface, IN PAA_ARP_PKT_HEADER pArpHeader, IN PAA_ARP_PKT_CONTENTS pArpContents ) /*++ Routine Description: Process a received ATMARP Request. All we need to do is send an ATMARP Reply, since the calling routine has already verified that the Target IP address is ours. Arguments: pVc - Pointer to VC on which the request arrived pInterface - Pointer to ATMARP Interface containing this VC pArpHeader - Pointer to ARP Header for this packet pArpContents - Parsed contents of received ARP Request packet Return Value: None --*/ { // // Temp locations used for swapping fields // UCHAR UNALIGNED * pAddress; UCHAR Length; // // ARP Reply packet // PNDIS_PACKET pNdisPacket; PUCHAR pArpPacket; // // Swap source and target addresses, and fill in our ATM info // in the source ATM addresses fields. // // // IP Addresses // pAddress = pArpContents->pSrcIPAddress; pArpContents->pSrcIPAddress = pArpContents->pDstIPAddress; pArpContents->pDstIPAddress = pAddress; // // ATM Numbers: set the target ATM number to the source ATM // number, but set the source ATM number to the local ATM // address. // pArpContents->pDstAtmNumber = pArpContents->pSrcAtmNumber; pArpContents->DstAtmNumberTypeLen = pArpContents->SrcAtmNumberTypeLen; pArpContents->pSrcAtmNumber = (pInterface->LocalAtmAddress.Address); pArpContents->SrcAtmNumberTypeLen = AA_PKT_ATM_ADDRESS_TO_TYPE_LEN(&(pInterface->LocalAtmAddress)); // // ATM Subaddresses // pArpContents->pDstAtmSubaddress = pArpContents->pSrcAtmSubaddress; pArpContents->DstAtmSubaddrTypeLen = pArpContents->SrcAtmSubaddrTypeLen; pArpContents->pSrcAtmSubaddress = NULL; pArpContents->SrcAtmSubaddrTypeLen = 0; // // Build the ARP Reply packet // pNdisPacket = AtmArpBuildARPPacket( AA_PKT_OP_TYPE_ARP_REPLY, pInterface, &pArpPacket, pArpContents ); if (pNdisPacket != (PNDIS_PACKET)NULL) { // // And send it off. Since we are in the context of a receive // indication on this VC, we can safely access the VC now. // AA_ACQUIRE_VC_LOCK(pVc); AtmArpSendPacketOnVc(pVc, pNdisPacket); // // The VC lock is released by SendPacketOnVc // } } VOID AtmArpHandleARPReply( IN PATMARP_VC pVc, IN PATMARP_INTERFACE pInterface, IN PAA_ARP_PKT_HEADER pArpHeader, IN PAA_ARP_PKT_CONTENTS pArpContents, IN BOOLEAN SrcIPAddressIsOurs, IN BOOLEAN SrcAtmAddressIsOurs ) /*++ Routine Description: Process a received ATMARP Reply packet. There are two major cases here: (1) We were trying to register one of our IP addresses with the server. (2) We were trying to resolve a remote IP address. In case (1), if we just registered the first of possibly many IP addresses assigned to this interface, we register all the other IP addresses. In case (2), we set up an IP to ATM mapping and initiate a connection if necessary. Arguments: pVc - Pointer to VC on which the reply arrived pInterface - Pointer to ATMARP Interface containing this VC pArpHeader - Pointer to ARP Header for this packet pArpContents - Parsed contents of received ARP Request packet SrcIPAddressIsOurs - The source IP address is one of ours SrcAtmAddressIsOurs - The source ATM info is ours. Return Value: None --*/ { BOOLEAN TimerWasRunning; BOOLEAN IsFirstRegistration; PIP_ADDRESS_ENTRY pIPAddressEntry; ULONG rc; // Ref Count AADEBUGP(AAD_LOUD, ("Handle ARP Reply: pVc 0x%x, pIf 0x%x, IF Flags 0x%x, OurIP %d, OurATM %d\n", pVc, pInterface, pInterface->Flags, SrcIPAddressIsOurs, SrcAtmAddressIsOurs)); AA_ACQUIRE_IF_LOCK(pInterface); if (AA_IS_FLAG_SET( pInterface->Flags, AA_IF_SERVER_STATE_MASK, AA_IF_SERVER_REGISTERING)) { // // We just completed registering with the server. Since we don't // send ARP requests to resolve any other addresses while we // are registering, the Source IP address must be ours. // // // Stop the Registration timer // TimerWasRunning = AtmArpStopTimer(&(pInterface->Timer), pInterface); AA_ASSERT(TimerWasRunning == TRUE); if (TimerWasRunning) { rc = AtmArpDereferenceInterface(pInterface); // Timer reference AA_ASSERT(rc > 0); } // // We have already verified that the Target addresses are ours. // Check that the source addresses are ours, too. // if (!SrcIPAddressIsOurs || !SrcAtmAddressIsOurs) { // // Registration failure. Start recovery. // AtmArpHandleServerRegistrationFailure(pInterface, pVc); // // IF lock is released within the above. // } else { // // We registered an IP address successfully! // // Find the entry for the IP Address that we have registered, // and mark it as registered. // pIPAddressEntry = &(pInterface->LocalIPAddress); while (*((IP_ADDRESS UNALIGNED *)(pArpContents->pSrcIPAddress)) != pIPAddressEntry->IPAddress) { AA_ASSERT(pIPAddressEntry->pNext != (PIP_ADDRESS_ENTRY)NULL); pIPAddressEntry = pIPAddressEntry->pNext; } pIPAddressEntry->IsRegistered = TRUE; IsFirstRegistration = pIPAddressEntry->IsFirstRegistration; pIPAddressEntry->IsFirstRegistration = FALSE; AADEBUGP(AAD_INFO, ("**** Registered IP Addr: %d.%d.%d.%d on IF 0x%x\n", ((PUCHAR)&(pIPAddressEntry->IPAddress))[0], ((PUCHAR)&(pIPAddressEntry->IPAddress))[1], ((PUCHAR)&(pIPAddressEntry->IPAddress))[2], ((PUCHAR)&(pIPAddressEntry->IPAddress))[3], pInterface)); AA_SET_FLAG( pInterface->Flags, AA_IF_SERVER_STATE_MASK, AA_IF_SERVER_REGISTERED); pInterface->State = IF_STATUS_UP; pInterface->LastChangeTime = GetTimeTicks(); // // Start the Server refresh timer so that we send our ARP info // to the server every so often (default = 15 minutes). // AtmArpStartTimer( pInterface, &(pInterface->Timer), AtmArpServerRefreshTimeout, pInterface->ServerRefreshTimeout, (PVOID)pInterface // Context ); AtmArpReferenceInterface(pInterface); // Timer reference // // If we have any more addresses to register, do so now. // AtmArpRegisterOtherIPAddresses(pInterface); // // IF Lock is freed in the above // #ifdef ATMARP_WMI if (IsFirstRegistration) { // // Send a WMI event, which carries the list of IP Addresses // registered on this IF. We do this only if this is a new // IP address. // AtmArpWmiSendTCIfIndication( pInterface, AAGID_QOS_TC_INTERFACE_UP_INDICATION, 0 ); } #endif } } else { // // Resolved an IP to ATM address // AADEBUGP(AAD_INFO, ("ARP Reply: Resolved IP Addr: %d.%d.%d.%d\n", ((PUCHAR)(pArpContents->pSrcIPAddress))[0], ((PUCHAR)(pArpContents->pSrcIPAddress))[1], ((PUCHAR)(pArpContents->pSrcIPAddress))[2], ((PUCHAR)(pArpContents->pSrcIPAddress))[3] )); AA_RELEASE_IF_LOCK(pInterface); (VOID)AtmArpLearnIPToAtm( pInterface, (IP_ADDRESS *)pArpContents->pSrcIPAddress, pArpContents->SrcAtmNumberTypeLen, pArpContents->pSrcAtmNumber, pArpContents->SrcAtmSubaddrTypeLen, pArpContents->pSrcAtmSubaddress, FALSE // Not a static entry ); } return; } VOID AtmArpHandleARPNAK( IN PATMARP_VC pVc, IN PATMARP_INTERFACE pInterface, IN PAA_ARP_PKT_HEADER pArpHeader, IN PAA_ARP_PKT_CONTENTS pArpContents ) /*++ Routine Description: Process a received ARP-NAK packet. If this is in response to an ARP Request we had sent to register ourselves, then we close the VC to this ARP server, and try the next server in our list of servers, after waiting for a while. If we were trying to resolve a remote IP address, then we mark the ARP IP entry corresponding to this IP address as having received a NAK, and free any packets queued on this. We also make a timestamp on the Entry so that we don't send another ARP Request for the same IP address very soon. Arguments: pVc - Pointer to VC on which the NAK arrived pInterface - Pointer to ATMARP Interface containing this VC pArpHeader - Pointer to ARP Header for this packet pArpContents - Parsed contents of received ARP Request packet Return Value: None --*/ { BOOLEAN TimerWasRunning; ULONG rc; // Ref Count PATMARP_IP_ENTRY pIpEntry; PNDIS_PACKET PacketList; // Packets queued for sending #if !BINARY_COMPATIBLE #ifdef CUBDD SINGLE_LIST_ENTRY PendingIrpList; #endif // CUBDD #endif // !BINARY_COMPATIBLE AA_ACQUIRE_IF_LOCK(pInterface); if (AA_IS_FLAG_SET( pInterface->Flags, AA_IF_SERVER_STATE_MASK, AA_IF_SERVER_REGISTERING)) { AADEBUGP(AAD_WARNING, ("Rcvd ARP NAK while registering: pIf 0x%x\n", pInterface)); // // Registration was in progress, and it failed. Start recovery. // AtmArpHandleServerRegistrationFailure(pInterface, pVc); // // IF lock is released within the above. // } else { // // We were trying to resolve an IP address. Get the Address // IP Entry corresponding to this IP address. // AA_RELEASE_IF_LOCK(pInterface); AA_ACQUIRE_IF_TABLE_LOCK(pInterface); pIpEntry = AtmArpSearchForIPAddress( pInterface, (IP_ADDRESS *)pArpContents->pSrcIPAddress, IE_REFTYPE_TMP, FALSE, // this isn't multicast/broadcast FALSE // Don't create a new one ); AA_RELEASE_IF_TABLE_LOCK(pInterface); if (pIpEntry != NULL_PATMARP_IP_ENTRY) { AADEBUGP(AAD_INFO, ("Rcvd ARP NAK: pIf 0x%x, IP addr %d:%d:%d:%d\n", pInterface, ((PUCHAR)(&(pIpEntry->IPAddress)))[0], ((PUCHAR)(&(pIpEntry->IPAddress)))[1], ((PUCHAR)(&(pIpEntry->IPAddress)))[2], ((PUCHAR)(&(pIpEntry->IPAddress)))[3])); AA_ACQUIRE_IE_LOCK(pIpEntry); AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry)); // // AtmArpSerchForIPAddress addrefd pIpEntry for us -- we deref it // here now that we've locked it. // rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TMP); if (rc > 0) { #if !BINARY_COMPATIBLE #ifdef CUBDD // // Take out the list of pending IRPs on this IP Entry. // PendingIrpList = pIpEntry->PendingIrpList; pIpEntry->PendingIrpList.Next = (PSINGLE_LIST_ENTRY)NULL; #endif // CUBDD #endif // !BINARY_COMPATIBLE // // Take out all packets queued on this entry // PacketList = pIpEntry->PacketList; pIpEntry->PacketList = (PNDIS_PACKET)NULL; // // The Address resolution timer must be running on this Entry; // stop it. // TimerWasRunning = AtmArpStopTimer(&(pIpEntry->Timer), pInterface); if (TimerWasRunning) { rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer reference } else { rc = pIpEntry->RefCount; } } // // Continue only if the IP Entry hasn't gone away // if (rc > 0) { // // Set the IP entry's state so that we don't send any // address resolution traffic for this IP address for // some time. // AA_SET_FLAG(pIpEntry->Flags, AA_IP_ENTRY_STATE_MASK, AA_IP_ENTRY_SEEN_NAK); // // Start a NAK Delay timer: until this expires, we won't // send any ARP requests for this IP address. This makes // sure that we don't keep pounding on the server with // an unresolvable IP address. // AtmArpStartTimer( pInterface, &(pIpEntry->Timer), AtmArpNakDelayTimeout, pInterface->MinWaitAfterNak, (PVOID)pIpEntry // Context ); AA_REF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer ref AA_RELEASE_IE_LOCK(pIpEntry); } // else the IP Entry lock would have been released. // // Free any packets that were queued up. // if (PacketList != (PNDIS_PACKET)NULL) { AtmArpFreeSendPackets( pInterface, PacketList, FALSE // No headers on these ); } #if !BINARY_COMPATIBLE #ifdef CUBDD AtmArpCompleteArpIrpList( PendingIrpList, (PATM_ADDRESS)NULL ); #endif // CUBDD #endif // !BINARY_COMPATIBLE } else { // // No IP Address Entry matching the IP address being // ARP'ed for. Nothing to be done in this case. // } } return; } VOID AtmArpHandleInARPRequest( IN PATMARP_VC pVc, IN PATMARP_INTERFACE pInterface, IN PAA_ARP_PKT_HEADER pArpHeader, IN PAA_ARP_PKT_CONTENTS pArpContents ) /*++ Routine Description: Process an InARP Request. We send back an InARP Reply packet with our address information. In case this is a PVC we were trying to resolve, it is possible that we are waiting for an InARP Reply ourselves, and the remote station came up only now. To speed up the resolution process, we restart the InARP Wait timeout so that it expires soon, causing another InARP Request to be sent. Arguments: pVc - Pointer to VC on which the request arrived pInterface - Pointer to ATMARP Interface containing this VC pArpHeader - Pointer to ARP Header for this packet pArpContents - Parsed contents of received ARP Request packet Return Value: None --*/ { // // Temp locations used for swapping fields // UCHAR UNALIGNED * pAddress; UCHAR Length; // // ARP Reply packet // PNDIS_PACKET pNdisPacket; PUCHAR pArpPacket; // // Copy the Source address (IP+ATM) info into the Target address // fields, and fill in the Source info fields with our IP+ATM info. // // // IP Addresses: // pArpContents->pDstIPAddress = pArpContents->pSrcIPAddress; pArpContents->pSrcIPAddress = (PUCHAR)&(pInterface->LocalIPAddress.IPAddress); // // ATM Numbers: set the target ATM number to the source ATM // number, but set the source ATM number to the local ATM // address. // pArpContents->pDstAtmNumber = pArpContents->pSrcAtmNumber; pArpContents->DstAtmNumberTypeLen = pArpContents->SrcAtmNumberTypeLen; pArpContents->pSrcAtmNumber = (pInterface->LocalAtmAddress.Address); pArpContents->SrcAtmNumberTypeLen = AA_PKT_ATM_ADDRESS_TO_TYPE_LEN(&(pInterface->LocalAtmAddress)); // // ATM Subaddresses // pArpContents->pDstAtmSubaddress = pArpContents->pSrcAtmSubaddress; pArpContents->DstAtmSubaddrTypeLen = pArpContents->SrcAtmSubaddrTypeLen; pArpContents->pSrcAtmSubaddress = NULL; pArpContents->SrcAtmSubaddrTypeLen = 0; // // Build the InARP Reply packet // pNdisPacket = AtmArpBuildARPPacket( AA_PKT_OP_TYPE_INARP_REPLY, pInterface, &pArpPacket, pArpContents ); if (pNdisPacket != (PNDIS_PACKET)NULL) { // // Before we send it off, check if this is a PVC being InARP'ed. // If so, restart the InARP Wait timer so that it expires soon. // // It is also possible that this PVC was once resolved, but // the remote end had gone away long enough for us to age out // the corresponding IP entry. This packet might be due to the // remote end coming back up. Start off an Inverse ARP operation // to get our end of the PVC re-resolved. // AA_ACQUIRE_VC_LOCK(pVc); if (AA_IS_FLAG_SET( pVc->Flags, AA_VC_TYPE_MASK, AA_VC_TYPE_PVC) && (AA_IS_FLAG_SET( pVc->Flags, AA_VC_ARP_STATE_MASK, AA_VC_INARP_IN_PROGRESS) || ((pVc->pAtmEntry != NULL_PATMARP_ATM_ENTRY) && (pVc->pAtmEntry->pIpEntryList == NULL_PATMARP_IP_ENTRY)))) { BOOLEAN TimerWasRunning; #if DBG if ((pVc->pAtmEntry != NULL_PATMARP_ATM_ENTRY) && (pVc->pAtmEntry->pIpEntryList == NULL_PATMARP_IP_ENTRY)) { AADEBUGP(AAD_LOUD, ("InARPReq: PVC %p, AtmEntry %p has NULL IP Entry, will InARP again!\n", pVc, pVc->pAtmEntry)); } #endif AA_SET_FLAG(pVc->Flags, AA_VC_ARP_STATE_MASK, AA_VC_INARP_IN_PROGRESS); // // Stop the currently running InARP Wait timer // TimerWasRunning = AtmArpStopTimer(&(pVc->Timer), pInterface); // // Start it again, to fire in 1 second // AtmArpStartTimer( pInterface, &(pVc->Timer), AtmArpPVCInARPWaitTimeout, 1, (PVOID)pVc // Context ); if (!TimerWasRunning) { AtmArpReferenceVc(pVc); // Timer reference } } AtmArpSendPacketOnVc(pVc, pNdisPacket); // // The VC lock is released by SendPacketOnVc // } } VOID AtmArpHandleInARPReply( IN PATMARP_VC pVc, IN PATMARP_INTERFACE pInterface, IN PAA_ARP_PKT_HEADER pArpHeader, IN PAA_ARP_PKT_CONTENTS pArpContents ) /*++ Routine Description: Process an InARP Reply packet, which should be a response to an InARP Request we sent earlier. There are two circumstances under which we send InARP Requests: (1) To obtain the addresses at the other end of a PVC. (2) In the process of revalidating an IP Address, if we aren't able to contact the server AND a VC exists to this IP address, we send an InARP Request to revalidate the IP entry. In Case (1), we link the PVC to an ATM Address Entry. In Case (2), we mark the IP entry for this VC as being "resolved", and start data transfer to this IP address. Arguments: pVc - Pointer to ATMARP VC on which this packet arrived pInterface - Pointer to ATMARP Interface pArpHeader - Pointer to ARP Header for this packet pArpContents - Parsed contents of received ARP Request packet Return Value: None --*/ { PATMARP_ATM_ENTRY pAtmEntry; // ATM entry to which this VC is linked PATMARP_IP_ENTRY pIpEntry; // IP address entry BOOLEAN TimerWasRunning; PATMARP_VC * ppVc; // Used to unlink VC from unresolved list ULONG rc; // Ref Count PNDIS_PACKET PacketList; // Packets queued for sending BOOLEAN IsBroadcast; // Is the IP Addr a broadcast/Class D addr? if (pArpContents->pSrcIPAddress == NULL) { AADEBUGP(AAD_WARNING, ("HandleInARPReply: IF %x, Null source address, discarding pkt\n", pInterface)); return; } AADEBUGP(AAD_INFO, ("HandleInARPReply: IF %x, IP addr %d.%d.%d.%d\n", pInterface, ((PUCHAR)pArpContents->pSrcIPAddress)[0], ((PUCHAR)pArpContents->pSrcIPAddress)[1], ((PUCHAR)pArpContents->pSrcIPAddress)[2], ((PUCHAR)pArpContents->pSrcIPAddress)[3])); // // Update our ARP cache with this information (regardless of whether // this is a PVC or SVC). // pIpEntry = AtmArpLearnIPToAtm( pInterface, (PIP_ADDRESS)pArpContents->pSrcIPAddress, pArpContents->SrcAtmNumberTypeLen, pArpContents->pSrcAtmNumber, pArpContents->SrcAtmSubaddrTypeLen, pArpContents->pSrcAtmSubaddress, FALSE // Not a static entry ); // // Acquire the locks that we need, in an ordered fashion... // AA_ACQUIRE_IF_LOCK(pInterface); if (pIpEntry != NULL_PATMARP_IP_ENTRY) { AA_ACQUIRE_IE_LOCK_DPC(pIpEntry); AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry)); pAtmEntry = pIpEntry->pAtmEntry; if (pAtmEntry != NULL_PATMARP_ATM_ENTRY) { AA_ACQUIRE_AE_LOCK_DPC(pAtmEntry); } } else { pAtmEntry = NULL_PATMARP_ATM_ENTRY; } AA_ACQUIRE_VC_LOCK_DPC(pVc); if (AA_IS_FLAG_SET( pVc->Flags, AA_VC_TYPE_MASK, AA_VC_TYPE_PVC) && (pVc->pAtmEntry == NULL_PATMARP_ATM_ENTRY) ) { // // This is an unresolved PVC, whose remote address info // we were trying to InARP for. // // // Stop the InARP Wait timer running on this VC // TimerWasRunning = AtmArpStopTimer(&(pVc->Timer), pInterface); AA_ASSERT(TimerWasRunning == TRUE); if (TimerWasRunning) { rc = AtmArpDereferenceVc(pVc); // Timer reference } else { rc = pVc->RefCount; } // // Do the rest only if the VC hasn't gone away. // if (rc != 0) { AA_SET_FLAG( pVc->Flags, AA_VC_ARP_STATE_MASK, AA_VC_ARP_STATE_IDLE); if (pAtmEntry != NULL_PATMARP_ATM_ENTRY) { // // We are all set now. Take the VC out of the list of // unresolved VCs on this Interface, and put it in the // list of VCs attached to this ATM Entry. // // NOTE: we don't dereference the VC because we are just // moving it from one list (Unresolved VCs) to another // (ATM Entry's VC list). // ppVc = &(pInterface->pUnresolvedVcs); while (*ppVc != pVc) { AA_ASSERT(*ppVc != NULL_PATMARP_VC); ppVc = &((*ppVc)->pNextVc); } *ppVc = pVc->pNextVc; AtmArpLinkVcToAtmEntry(pVc, pAtmEntry); } else { // // No matching ATM Entry. // // We are really low on resources if we are here. // Start the InARP Wait timer; when it fires, we'll try to // send another InARP Request to resolve this VC. // AADEBUGP(AAD_FATAL, ("HandleInARPReply: no matching ATM entry: pInterface %x, pVc %x, pIpEntry %x\n", pInterface, pVc, pIpEntry)); AA_ASSERT(FALSE); AtmArpStartTimer( pInterface, &(pVc->Timer), AtmArpPVCInARPWaitTimeout, pInterface->InARPWaitTimeout, (PVOID)pVc // Context ); AtmArpReferenceVc(pVc); // InARP Timer ref } AA_RELEASE_VC_LOCK_DPC(pVc); } else { // // The VC went away while we were InARPing // } // // Release any locks that we still hold. // if (pIpEntry != NULL_PATMARP_IP_ENTRY) { if (pAtmEntry != NULL_PATMARP_ATM_ENTRY) { AA_RELEASE_AE_LOCK_DPC(pAtmEntry); } AA_RELEASE_IE_LOCK_DPC(pIpEntry); } AA_RELEASE_IF_LOCK(pInterface); } else { // // Revalidating on a PVC/SVC: case (2) in Routine Description // AA_SET_FLAG( pVc->Flags, AA_VC_ARP_STATE_MASK, AA_VC_ARP_STATE_IDLE); // // Stop the INARP timer, if it is running. // TimerWasRunning = AtmArpStopTimer(&pVc->Timer, pInterface); if (TimerWasRunning) { rc = AtmArpDereferenceVc(pVc); // InARP reply: stop InARP timer } else { rc = pVc->RefCount; } if (rc != 0) { AA_RELEASE_VC_LOCK_DPC(pVc); } // // Update the IP Entry we were revaldating. // if (pIpEntry != NULL_PATMARP_IP_ENTRY) { // // Stop the InARP timer running here // TimerWasRunning = AtmArpStopTimer(&(pIpEntry->Timer), pInterface); if (TimerWasRunning) { rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TIMER); // timer ref } else { rc = pIpEntry->RefCount; } // // Continue only if the IP Entry hasn't gone away. // if (rc > 0) { // // Update its state // AA_SET_FLAG( pIpEntry->Flags, AA_IP_ENTRY_STATE_MASK, AA_IP_ENTRY_RESOLVED ); AADEBUGP(AAD_INFO, ("InARP Reply: Revalidated pIpEntry 0x%x, IP Addr: %d.%d.%d.%d\n", pIpEntry, ((PUCHAR)(&(pIpEntry->IPAddress)))[0], ((PUCHAR)(&(pIpEntry->IPAddress)))[1], ((PUCHAR)(&(pIpEntry->IPAddress)))[2], ((PUCHAR)(&(pIpEntry->IPAddress)))[3] )); AA_ASSERT(pAtmEntry != NULL_PATMARP_ATM_ENTRY); // // Start the Aging timer. // AtmArpStartTimer( pInterface, &(pIpEntry->Timer), AtmArpIPEntryAgingTimeout, pInterface->ARPEntryAgingTimeout, (PVOID)pIpEntry ); AA_REF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer ref // // Take out the list of pending packets on this Entry // PacketList = pIpEntry->PacketList; pIpEntry->PacketList = (PNDIS_PACKET)NULL; IsBroadcast = AA_IS_FLAG_SET(pIpEntry->Flags, AA_IP_ENTRY_ADDR_TYPE_MASK, AA_IP_ENTRY_ADDR_TYPE_NUCAST); AA_RELEASE_AE_LOCK_DPC(pAtmEntry); AA_RELEASE_IE_LOCK_DPC(pIpEntry); AA_RELEASE_IF_LOCK(pInterface); // // Send out all these packets // AtmArpSendPacketListOnAtmEntry( pInterface, pAtmEntry, PacketList, IsBroadcast ); } else { // // the IP Entry is gone // AA_RELEASE_AE_LOCK_DPC(pAtmEntry); AA_RELEASE_IF_LOCK(pInterface); } } else { // // No matching IP Entry // AA_RELEASE_IF_LOCK(pInterface); } } return; }