BOOLEAN AddrReceiveMatch( PIP_ADDRESS LocalAddress, PIP_ADDRESS RemoteAddress) { if (AddrIsEqual(LocalAddress, RemoteAddress)) { /* Unicast address match */ return TRUE; } if (AddrIsBroadcastMatch(LocalAddress, RemoteAddress)) { /* Broadcast address match */ return TRUE; } if (AddrIsUnspecified(LocalAddress)) { /* Local address unspecified */ return TRUE; } if (AddrIsUnspecified(RemoteAddress)) { /* Remote address unspecified */ return TRUE; } return FALSE; }
BOOLEAN AddrIsBroadcastMatch( PIP_ADDRESS UnicastAddress, PIP_ADDRESS BroadcastAddress ) { IF_LIST_ITER(IF); ForEachInterface(IF) { if ((AddrIsUnspecified(UnicastAddress) || AddrIsEqual(&IF->Unicast, UnicastAddress)) && (AddrIsEqual(&IF->Broadcast, BroadcastAddress))) return TRUE; } EndFor(IF); return FALSE; }
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; }
/* * FUNCTION: Open an address file object * ARGUMENTS: * Request = Pointer to TDI request structure for this request * Address = Pointer to address to be opened * Protocol = Protocol on which to open the address * Shared = Specifies if the address is opened for shared access * Options = Pointer to option buffer * RETURNS: * Status of operation */ NTSTATUS FileOpenAddress( PTDI_REQUEST Request, PTA_IP_ADDRESS Address, USHORT Protocol, BOOLEAN Shared, PVOID Options) { PADDRESS_FILE AddrFile; TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol)); /* If it's shared and has a port specified, look for a match */ if ((Shared != FALSE) && (Address->Address[0].Address[0].sin_port != 0)) { AddrFile = AddrFindShared(NULL, Address->Address[0].Address[0].sin_port, Protocol); if (AddrFile != NULL) { Request->Handle.AddressHandle = AddrFile; return STATUS_SUCCESS; } } AddrFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(ADDRESS_FILE), ADDR_FILE_TAG); if (!AddrFile) { TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE)); AddrFile->RefCount = 1; AddrFile->Free = AddrFileFree; AddrFile->Sharers = 1; /* Set our default options */ AddrFile->TTL = 128; AddrFile->DF = 0; AddrFile->BCast = 1; AddrFile->HeaderIncl = 1; /* Make sure address is a local unicast address or 0 */ /* FIXME: IPv4 only */ AddrFile->Family = Address->Address[0].AddressType; AddrFile->Address.Address.IPv4Address = Address->Address[0].Address[0].in_addr; AddrFile->Address.Type = IP_ADDRESS_V4; if (!AddrIsUnspecified(&AddrFile->Address) && !AddrLocateInterface(&AddrFile->Address)) { TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", A2S(&AddrFile->Address))); ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG); return STATUS_INVALID_ADDRESS; } TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n", A2S(&AddrFile->Address), Protocol, IPPROTO_UDP)); /* Protocol specific handling */ switch (Protocol) { case IPPROTO_TCP: if (Address->Address[0].Address[0].sin_port) { /* The client specified an explicit port so we force a bind to this */ AddrFile->Port = TCPAllocatePort(Address->Address[0].Address[0].sin_port); /* Check for bind success */ if (AddrFile->Port == 0xffff) { ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG); return STATUS_ADDRESS_ALREADY_EXISTS; } /* Sanity check */ ASSERT(Address->Address[0].Address[0].sin_port == AddrFile->Port); } else if (!AddrIsUnspecified(&AddrFile->Address)) { /* The client is trying to bind to a local address so allocate a port now too */ AddrFile->Port = TCPAllocatePort(0); /* Check for bind success */ if (AddrFile->Port == 0xffff) { ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG); return STATUS_ADDRESS_ALREADY_EXISTS; } } else { /* The client wants an unspecified port with an unspecified address so we wait to see what the TCP library gives us */ AddrFile->Port = 0; } AddEntity(CO_TL_ENTITY, AddrFile, CO_TL_TCP); AddrFile->Send = NULL; /* TCPSendData */ break; case IPPROTO_UDP: TI_DbgPrint(MID_TRACE,("Allocating udp port\n")); AddrFile->Port = UDPAllocatePort(Address->Address[0].Address[0].sin_port); if ((Address->Address[0].Address[0].sin_port && AddrFile->Port != Address->Address[0].Address[0].sin_port) || AddrFile->Port == 0xffff) { ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG); return STATUS_ADDRESS_ALREADY_EXISTS; } TI_DbgPrint(MID_TRACE,("Setting port %d (wanted %d)\n", AddrFile->Port, Address->Address[0].Address[0].sin_port)); AddEntity(CL_TL_ENTITY, AddrFile, CL_TL_UDP); AddrFile->Send = UDPSendDatagram; break; case IPPROTO_ICMP: AddrFile->Port = 0; AddrFile->Send = ICMPSendDatagram; /* FIXME: Verify this */ AddEntity(ER_ENTITY, AddrFile, ER_ICMP); break; default: /* Use raw IP for all other protocols */ AddrFile->Port = 0; AddrFile->Send = RawIPSendDatagram; /* FIXME: Verify this */ AddEntity(CL_TL_ENTITY, AddrFile, 0); break; } TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n", Protocol)); TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n", WN2H(AddrFile->Port))); /* Set protocol */ AddrFile->Protocol = Protocol; /* Initialize receive and transmit queues */ InitializeListHead(&AddrFile->ReceiveQueue); InitializeListHead(&AddrFile->TransmitQueue); /* Initialize spin lock that protects the address file object */ KeInitializeSpinLock(&AddrFile->Lock); /* Return address file object */ Request->Handle.AddressHandle = AddrFile; /* Add address file to global list */ ExInterlockedInsertTailList( &AddressFileListHead, &AddrFile->ListEntry, &AddressFileListLock); TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); return STATUS_SUCCESS; }
NTSTATUS TCPConnect ( PCONNECTION_ENDPOINT Connection, PTDI_CONNECTION_INFORMATION ConnInfo, PTDI_CONNECTION_INFORMATION ReturnInfo, PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { NTSTATUS Status; struct ip_addr bindaddr, connaddr; IP_ADDRESS RemoteAddress; USHORT RemotePort; TA_IP_ADDRESS LocalAddress; PTDI_BUCKET Bucket; PNEIGHBOR_CACHE_ENTRY NCE; KIRQL OldIrql; TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Called\n")); Status = AddrBuildAddress ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress, &RemoteAddress, &RemotePort); if (!NT_SUCCESS(Status)) { TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n")); return Status; } /* Freed in TCPSocketState */ TI_DbgPrint(DEBUG_TCP, ("Connecting to address %x:%x\n", RemoteAddress.Address.IPv4Address, RemotePort)); LockObject(Connection, &OldIrql); if (!Connection->AddressFile) { UnlockObject(Connection, OldIrql); return STATUS_INVALID_PARAMETER; } if (AddrIsUnspecified(&Connection->AddressFile->Address)) { if (!(NCE = RouteGetRouteToDestination(&RemoteAddress))) { UnlockObject(Connection, OldIrql); return STATUS_NETWORK_UNREACHABLE; } bindaddr.addr = NCE->Interface->Unicast.Address.IPv4Address; } else { bindaddr.addr = Connection->AddressFile->Address.Address.IPv4Address; } Status = TCPTranslateError(LibTCPBind(Connection, &bindaddr, Connection->AddressFile->Port)); if (NT_SUCCESS(Status)) { /* Check if we had an unspecified port */ if (!Connection->AddressFile->Port) { /* We did, so we need to copy back the port */ Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE); if (NT_SUCCESS(Status)) { /* Allocate the port in the port bitmap */ Connection->AddressFile->Port = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port); /* This should never fail */ ASSERT(Connection->AddressFile->Port != 0xFFFF); } } if (NT_SUCCESS(Status)) { connaddr.addr = RemoteAddress.Address.IPv4Address; Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList); if (!Bucket) { UnlockObject(Connection, OldIrql); return STATUS_NO_MEMORY; } Bucket->Request.RequestNotifyObject = (PVOID)Complete; Bucket->Request.RequestContext = Context; InsertTailList( &Connection->ConnectRequest, &Bucket->Entry ); Status = TCPTranslateError(LibTCPConnect(Connection, &connaddr, RemotePort)); } } UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Leaving. Status = 0x%x\n", Status)); return Status; }
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; }