PNEIGHBOR_CACHE_ENTRY NBFindOrCreateNeighbor( PIP_INTERFACE Interface, PIP_ADDRESS Address, BOOLEAN NoTimeout) /* * FUNCTION: Tries to find a neighbor and if unsuccesful, creates a new NCE * ARGUMENTS: * Interface = Pointer to interface to use (in case NCE is not found) * Address = Pointer to IP address * RETURNS: * Pointer to NCE, NULL if there is not enough free resources * NOTES: * The NCE is referenced if found or created. The caller is * responsible for dereferencing it again after use */ { PNEIGHBOR_CACHE_ENTRY NCE; TI_DbgPrint(DEBUG_NCACHE, ("Called. Interface (0x%X) Address (0x%X).\n", Interface, Address)); NCE = NBLocateNeighbor(Address, Interface); if (NCE == NULL) { TI_DbgPrint(MID_TRACE,("BCAST: %s\n", A2S(&Interface->Broadcast))); if( AddrIsEqual(Address, &Interface->Broadcast) || AddrIsUnspecified(Address) ) { TI_DbgPrint(MID_TRACE,("Packet targeted at broadcast addr\n")); NCE = NBAddNeighbor(Interface, Address, NULL, Interface->AddressLength, NUD_PERMANENT, 0); } else { NCE = NBAddNeighbor(Interface, Address, NULL, Interface->AddressLength, NUD_INCOMPLETE, NoTimeout ? 0 : ARP_INCOMPLETE_TIMEOUT); if (!NCE) return NULL; NBSendSolicit(NCE); } } return NCE; }
TDI_STATUS InfoTdiSetArptableMIB(PIP_INTERFACE IF, PVOID Buffer, UINT BufferSize) { PIPARP_ENTRY ArpEntry = Buffer; IP_ADDRESS Address; PNEIGHBOR_CACHE_ENTRY NCE; if (!Buffer || BufferSize < sizeof(IPARP_ENTRY)) return TDI_INVALID_PARAMETER; AddrInitIPv4(&Address, ArpEntry->LogAddr); if ((NCE = NBLocateNeighbor(&Address, IF))) NBRemoveNeighbor(NCE); if (NBAddNeighbor(IF, &Address, ArpEntry->PhysAddr, ArpEntry->AddrSize, NUD_PERMANENT, 0)) return TDI_SUCCESS; else return TDI_INVALID_PARAMETER; }
NTSTATUS ICMPSendDatagram( PADDRESS_FILE AddrFile, PTDI_CONNECTION_INFORMATION ConnInfo, PCHAR BufferData, ULONG DataSize, PULONG DataUsed ) /* * FUNCTION: Sends an ICMP datagram to a remote address * ARGUMENTS: * Request = Pointer to TDI request * ConnInfo = Pointer to connection information * Buffer = Pointer to NDIS buffer with data * DataSize = Size in bytes of data to be sent * RETURNS: * Status of operation */ { IP_PACKET Packet; PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress; IP_ADDRESS RemoteAddress, LocalAddress; NTSTATUS Status; PNEIGHBOR_CACHE_ENTRY NCE; KIRQL OldIrql; TI_DbgPrint(MID_TRACE,("Sending Datagram(%x %x %x %d)\n", AddrFile, ConnInfo, BufferData, DataSize)); TI_DbgPrint(MID_TRACE,("RemoteAddressTa: %x\n", RemoteAddressTa)); switch( RemoteAddressTa->Address[0].AddressType ) { case TDI_ADDRESS_TYPE_IP: RemoteAddress.Type = IP_ADDRESS_V4; RemoteAddress.Address.IPv4Address = RemoteAddressTa->Address[0].Address[0].in_addr; break; default: return STATUS_UNSUCCESSFUL; } TI_DbgPrint(MID_TRACE,("About to get route to destination\n")); LockObject(AddrFile, &OldIrql); LocalAddress = AddrFile->Address; if (AddrIsUnspecified(&LocalAddress)) { /* If the local address is unspecified (0), * then use the unicast address of the * interface we're sending over */ if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) { UnlockObject(AddrFile, OldIrql); return STATUS_NETWORK_UNREACHABLE; } LocalAddress = NCE->Interface->Unicast; } else { if(!(NCE = NBLocateNeighbor( &LocalAddress, NULL ))) { UnlockObject(AddrFile, OldIrql); return STATUS_INVALID_PARAMETER; } } Status = PrepareICMPPacket( AddrFile, NCE->Interface, &Packet, &RemoteAddress, BufferData, DataSize ); UnlockObject(AddrFile, OldIrql); if( !NT_SUCCESS(Status) ) return Status; TI_DbgPrint(MID_TRACE,("About to send datagram\n")); Status = IPSendDatagram(&Packet, NCE); if (!NT_SUCCESS(Status)) return Status; *DataUsed = DataSize; TI_DbgPrint(MID_TRACE,("Leaving\n")); return STATUS_SUCCESS; }
VOID ARPReceive( PVOID Context, PIP_PACKET Packet) /* * FUNCTION: Receives an ARP packet * ARGUMENTS: * Context = Pointer to context information (IP_INTERFACE) * Packet = Pointer to packet */ { PARP_HEADER Header; IP_ADDRESS SrcAddress; IP_ADDRESS DstAddress; PCHAR SenderHWAddress, SenderProtoAddress, TargetProtoAddress; PNEIGHBOR_CACHE_ENTRY NCE; PNDIS_PACKET NdisPacket; PIP_INTERFACE Interface = (PIP_INTERFACE)Context; ULONG BytesCopied, DataSize; PCHAR DataBuffer; PAGED_CODE(); TI_DbgPrint(DEBUG_ARP, ("Called.\n")); Packet->Header = ExAllocatePoolWithTag(PagedPool, sizeof(ARP_HEADER), PACKET_BUFFER_TAG); if (!Packet->Header) { TI_DbgPrint(DEBUG_ARP, ("Unable to allocate header buffer\n")); Packet->Free(Packet); return; } Packet->MappedHeader = FALSE; BytesCopied = CopyPacketToBuffer((PCHAR)Packet->Header, Packet->NdisPacket, Packet->Position, sizeof(ARP_HEADER)); if (BytesCopied != sizeof(ARP_HEADER)) { TI_DbgPrint(DEBUG_ARP, ("Unable to copy in header buffer\n")); Packet->Free(Packet); return; } Header = (PARP_HEADER)Packet->Header; /* FIXME: Ethernet only */ if (WN2H(Header->HWType) != 1) { TI_DbgPrint(DEBUG_ARP, ("Unknown ARP hardware type (0x%X).\n", WN2H(Header->HWType))); Packet->Free(Packet); return; } /* Check protocol type */ if (Header->ProtoType != ETYPE_IPv4) { TI_DbgPrint(DEBUG_ARP, ("Unknown ARP protocol type (0x%X).\n", WN2H(Header->ProtoType))); Packet->Free(Packet); return; } DataSize = (2 * Header->HWAddrLen) + (2 * Header->ProtoAddrLen); DataBuffer = ExAllocatePool(PagedPool, DataSize); if (!DataBuffer) { TI_DbgPrint(DEBUG_ARP, ("Unable to allocate data buffer\n")); Packet->Free(Packet); return; } BytesCopied = CopyPacketToBuffer(DataBuffer, Packet->NdisPacket, Packet->Position + sizeof(ARP_HEADER), DataSize); if (BytesCopied != DataSize) { TI_DbgPrint(DEBUG_ARP, ("Unable to copy in data buffer\n")); ExFreePool(DataBuffer); Packet->Free(Packet); return; } SenderHWAddress = (PVOID)(DataBuffer); SenderProtoAddress = (PVOID)(SenderHWAddress + Header->HWAddrLen); TargetProtoAddress = (PVOID)(SenderProtoAddress + Header->ProtoAddrLen + Header->HWAddrLen); AddrInitIPv4(&DstAddress, *((PULONG)TargetProtoAddress)); if (!AddrIsEqual(&DstAddress, &Interface->Unicast)) { ExFreePool(DataBuffer); Packet->Free(Packet); return; } AddrInitIPv4(&SrcAddress, *((PULONG)SenderProtoAddress)); /* Check if we know the sender */ NCE = NBLocateNeighbor(&SrcAddress, Interface); if (NCE) { /* We know the sender. Update the hardware address and state in our neighbor address cache */ NBUpdateNeighbor(NCE, SenderHWAddress, 0); } else { /* The packet had our protocol address as target. The sender may want to communicate with us soon, so add his address to our address cache */ NBAddNeighbor(Interface, &SrcAddress, SenderHWAddress, Header->HWAddrLen, 0, ARP_COMPLETE_TIMEOUT); } if (Header->Opcode != ARP_OPCODE_REQUEST) { ExFreePool(DataBuffer); Packet->Free(Packet); return; } /* This is a request for our address. Swap the addresses and send an ARP reply back to the sender */ NdisPacket = PrepareARPPacket( Interface, Header->HWType, /* Hardware type */ Header->ProtoType, /* Protocol type */ (UCHAR)Interface->AddressLength, /* Hardware address length */ (UCHAR)Header->ProtoAddrLen, /* Protocol address length */ Interface->Address, /* Sender's (local) hardware address */ &Interface->Unicast.Address.IPv4Address,/* Sender's (local) protocol address */ SenderHWAddress, /* Target's (remote) hardware address */ SenderProtoAddress, /* Target's (remote) protocol address */ ARP_OPCODE_REPLY); /* ARP reply */ if (NdisPacket) { PC(NdisPacket)->DLComplete = ARPTransmitComplete; (*Interface->Transmit)(Interface->Context, NdisPacket, 0, SenderHWAddress, LAN_PROTO_ARP); } ExFreePool(DataBuffer); Packet->Free(Packet); }