/* * FUNCTION: Opens a connection file object * ARGUMENTS: * Request = Pointer to TDI request structure for this request * ClientContext = Pointer to client context information * RETURNS: * Status of operation */ NTSTATUS FileOpenConnection( PTDI_REQUEST Request, PVOID ClientContext) { NTSTATUS Status; PCONNECTION_ENDPOINT Connection; TI_DbgPrint(MID_TRACE, ("Called.\n")); Connection = TCPAllocateConnectionEndpoint( ClientContext ); if( !Connection ) return STATUS_NO_MEMORY; Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP ); if( !NT_SUCCESS(Status) ) { DereferenceObject( Connection ); return Status; } /* Return connection endpoint file object */ Request->Handle.ConnectionContext = Connection; TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); return STATUS_SUCCESS; }
VOID ICMPTransmit( PIP_PACKET IPPacket, PIP_TRANSMIT_COMPLETE Complete, PVOID Context) /* * FUNCTION: Transmits an ICMP packet * ARGUMENTS: * NTE = Pointer to net table entry to use (NULL if don't care) * IPPacket = Pointer to IP packet to transmit */ { PNEIGHBOR_CACHE_ENTRY NCE; TI_DbgPrint(DEBUG_ICMP, ("Called.\n")); /* Calculate checksum of ICMP header and data */ ((PICMP_HEADER)IPPacket->Data)->Checksum = (USHORT) IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0); /* Get a route to the destination address */ if ((NCE = RouteGetRouteToDestination(&IPPacket->DstAddr))) { /* Send the packet */ IPSendDatagram(IPPacket, NCE); } else { /* No route to destination (or no free resources) */ TI_DbgPrint(DEBUG_ICMP, ("No route to destination address 0x%X.\n", IPPacket->DstAddr.Address.IPv4Address)); IPPacket->Free(IPPacket); } }
TDI_STATUS InfoTdiSetRoute(PIP_INTERFACE IF, PVOID Buffer, UINT BufferSize) { IP_ADDRESS Address, Netmask, Router; PIPROUTE_ENTRY Route = Buffer; AddrInitIPv4( &Address, Route->Dest ); AddrInitIPv4( &Netmask, Route->Mask ); AddrInitIPv4( &Router, Route->Gw ); if (!Buffer || BufferSize < sizeof(IPROUTE_ENTRY)) return TDI_INVALID_PARAMETER; if (IF == Loopback) { DbgPrint("Failing attempt to add route to loopback adapter\n"); return TDI_INVALID_PARAMETER; } if( Route->Type == IP_ROUTE_TYPE_ADD ) { /* Add the route */ TI_DbgPrint(DEBUG_INFO,("Adding route (%s)\n", A2S(&Address))); if (!RouterCreateRoute( &Address, &Netmask, &Router, IF, Route->Metric1)) return TDI_NO_RESOURCES; return TDI_SUCCESS; } else if( Route->Type == IP_ROUTE_TYPE_DEL ) { TI_DbgPrint(DEBUG_INFO,("Removing route (%s)\n", A2S(&Address))); if (NT_SUCCESS(RouterRemoveRoute( &Address, &Router ))) return TDI_SUCCESS; else return TDI_INVALID_PARAMETER; } return TDI_INVALID_REQUEST; }
TDI_STATUS InfoTdiQueryGetATInfo( TDIEntityID ID, PIP_INTERFACE Interface, PNDIS_BUFFER Buffer, PUINT BufferSize) { ULONG ATInfo[2]; TDI_STATUS Status; TI_DbgPrint(DEBUG_INFO, ("Called.\n")); if (!Interface) return TDI_INVALID_PARAMETER; if (*BufferSize < sizeof(ATInfo)) return STATUS_BUFFER_TOO_SMALL; /* FIXME: I have no idea what the first field should contain... */ ATInfo[0] = 0; ATInfo[1] = Interface->Index; Status = InfoCopyOut((PCHAR)ATInfo, sizeof(ATInfo), Buffer, BufferSize); TI_DbgPrint(DEBUG_INFO, ("Returning %08x\n", Status)); return Status; }
VOID FreeNdisPacket ( PNDIS_PACKET Packet ) /* * FUNCTION: Frees an NDIS packet * ARGUMENTS: * Packet = Pointer to NDIS packet to be freed */ { PNDIS_BUFFER Buffer, NextBuffer; TI_DbgPrint(DEBUG_PBUFFER, ("Packet (0x%X)\n", Packet)); /* Free all the buffers in the packet first */ NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL); for (; Buffer != NULL; Buffer = NextBuffer) { PVOID Data; UINT Length; NdisGetNextBuffer(Buffer, &NextBuffer); NdisQueryBuffer(Buffer, &Data, &Length); TI_DbgPrint(DEBUG_PBUFFER, ("Freeing ndis buffer (0x%X)\n", Buffer)); NdisFreeBuffer(Buffer); TI_DbgPrint(DEBUG_PBUFFER, ("Freeing exal buffer (0x%X)\n", Data)); ExFreePoolWithTag(Data, PACKET_BUFFER_TAG); } /* Finally free the NDIS packet discriptor */ NdisFreePacket(Packet); }
VOID DispDataRequestComplete( PVOID Context, NTSTATUS Status, ULONG Count) /* * FUNCTION: Completes a send/receive IRP * ARGUMENTS: * Context = Pointer to context information (IRP) * Status = Status of the request * Count = Number of bytes sent or received */ { PIRP Irp = Context; TI_DbgPrint(DEBUG_IRP, ("Called for irp %x (%x, %d).\n", Irp, Status, Count)); Irp->IoStatus.Status = Status; Irp->IoStatus.Information = Count; TI_DbgPrint(MID_TRACE, ("Irp->IoStatus.Status = %x\n", Irp->IoStatus.Status)); TI_DbgPrint(MID_TRACE, ("Irp->IoStatus.Information = %d\n", Irp->IoStatus.Information)); TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); IRPFinish(Irp, Status); TI_DbgPrint(DEBUG_IRP, ("Done Completing IRP\n")); }
UINT CopyBufferChainToBuffer( PCHAR DstData, PNDIS_BUFFER SrcBuffer, UINT SrcOffset, UINT Length) /* * FUNCTION: Copies data from an NDIS buffer chain to a buffer * ARGUMENTS: * DstData = Pointer to destination buffer * SrcBuffer = Pointer to source NDIS buffer * SrcOffset = Source start offset * Length = Number of bytes to copy * RETURNS: * Number of bytes copied to destination buffer * NOTES: * The number of bytes copied may be limited by the source * buffer size */ { UINT BytesCopied, BytesToCopy, SrcSize; PCHAR SrcData; TI_DbgPrint(DEBUG_PBUFFER, ("DstData 0x%X SrcBuffer 0x%X SrcOffset 0x%X Length %d\n",DstData,SrcBuffer, SrcOffset, Length)); /* Skip SrcOffset bytes in the source buffer chain */ if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1) return 0; /* Start copying the data */ BytesCopied = 0; for (;;) { BytesToCopy = MIN(SrcSize, Length); TI_DbgPrint(DEBUG_PBUFFER, ("Copying (%d) bytes from 0x%X to 0x%X\n", BytesToCopy, SrcData, DstData)); RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy); BytesCopied += BytesToCopy; DstData = (PCHAR)((ULONG_PTR)DstData + BytesToCopy); Length -= BytesToCopy; if (Length == 0) break; SrcSize -= BytesToCopy; if (SrcSize == 0) { /* No more bytes in source buffer. Proceed to the next buffer in the source buffer chain */ NdisGetNextBuffer(SrcBuffer, &SrcBuffer); if (!SrcBuffer) break; NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize); } } return BytesCopied; }
NTSTATUS RouterRemoveRoute(PIP_ADDRESS Target, PIP_ADDRESS Router) /* * FUNCTION: Removes a route from the Forward Information Base (FIB) * ARGUMENTS: * Target: The machine or network targeted by the route * Router: The router used to pass the packet to the destination * * Searches the FIB and removes a route matching the indicated parameters. */ { KIRQL OldIrql; PLIST_ENTRY CurrentEntry; PLIST_ENTRY NextEntry; PFIB_ENTRY Current; BOOLEAN Found = FALSE; PNEIGHBOR_CACHE_ENTRY NCE; TI_DbgPrint(DEBUG_ROUTER, ("Called\n")); TI_DbgPrint(DEBUG_ROUTER, ("Deleting Route From: %s\n", A2S(Router))); TI_DbgPrint(DEBUG_ROUTER, (" To: %s\n", A2S(Target))); TcpipAcquireSpinLock(&FIBLock, &OldIrql); RouterDumpRoutes(); CurrentEntry = FIBListHead.Flink; while (CurrentEntry != &FIBListHead) { NextEntry = CurrentEntry->Flink; Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); NCE = Current->Router; if( AddrIsEqual( &Current->NetworkAddress, Target ) && AddrIsEqual( &NCE->Address, Router ) ) { Found = TRUE; break; } Current = NULL; CurrentEntry = NextEntry; } if( Found ) { TI_DbgPrint(DEBUG_ROUTER, ("Deleting route\n")); DestroyFIBE( Current ); } RouterDumpRoutes(); TcpipReleaseSpinLock(&FIBLock, OldIrql); TI_DbgPrint(DEBUG_ROUTER, ("Leaving\n")); return Found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; }
VOID NBCompleteSend( PVOID Context, PNDIS_PACKET NdisPacket, NDIS_STATUS Status ) { PNEIGHBOR_PACKET Packet = (PNEIGHBOR_PACKET)Context; TI_DbgPrint(MID_TRACE, ("Called\n")); ASSERT_KM_POINTER(Packet); ASSERT_KM_POINTER(Packet->Complete); Packet->Complete( Packet->Context, Packet->Packet, Status ); TI_DbgPrint(MID_TRACE, ("Completed\n")); ExFreePoolWithTag( Packet, NEIGHBOR_PACKET_TAG ); TI_DbgPrint(MID_TRACE, ("Freed\n")); }
NTSTATUS TCPReceiveData ( PCONNECTION_ENDPOINT Connection, PNDIS_BUFFER Buffer, ULONG ReceiveLength, PULONG BytesReceived, ULONG ReceiveFlags, PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { PTDI_BUCKET Bucket; PUCHAR DataBuffer; UINT DataLen, Received; NTSTATUS Status; TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Called for %d bytes (on socket %x)\n", ReceiveLength, Connection->SocketContext)); NdisQueryBuffer(Buffer, &DataBuffer, &DataLen); Status = LibTCPGetDataFromConnectionQueue(Connection, DataBuffer, DataLen, &Received); if (Status == STATUS_PENDING) { Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList); if (!Bucket) { TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Failed to allocate bucket\n")); return STATUS_NO_MEMORY; } Bucket->Request.RequestNotifyObject = Complete; Bucket->Request.RequestContext = Context; ExInterlockedInsertTailList( &Connection->ReceiveRequest, &Bucket->Entry, &Connection->Lock ); TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Queued read irp\n")); TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Leaving. Status = STATUS_PENDING\n")); (*BytesReceived) = 0; } else { (*BytesReceived) = Received; } return Status; }
PFIB_ENTRY RouterAddRoute( PIP_ADDRESS NetworkAddress, PIP_ADDRESS Netmask, PNEIGHBOR_CACHE_ENTRY Router, UINT Metric) /* * FUNCTION: Adds a route to the Forward Information Base (FIB) * ARGUMENTS: * NetworkAddress = Pointer to address of network * Netmask = Pointer to netmask of network * Router = Pointer to NCE of router to use * Metric = Cost of this route * RETURNS: * Pointer to FIB entry if the route was added, NULL if not * NOTES: * The FIB entry references the NetworkAddress, Netmask and * the NCE of the router. The caller is responsible for providing * these references */ { PFIB_ENTRY FIBE; TI_DbgPrint(DEBUG_ROUTER, ("Called. NetworkAddress (0x%X) Netmask (0x%X) " "Router (0x%X) Metric (%d).\n", NetworkAddress, Netmask, Router, Metric)); TI_DbgPrint(DEBUG_ROUTER, ("NetworkAddress (%s) Netmask (%s) Router (%s).\n", A2S(NetworkAddress), A2S(Netmask), A2S(&Router->Address))); FIBE = ExAllocatePoolWithTag(NonPagedPool, sizeof(FIB_ENTRY), FIB_TAG); if (!FIBE) { TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); return NULL; } RtlCopyMemory( &FIBE->NetworkAddress, NetworkAddress, sizeof(FIBE->NetworkAddress) ); RtlCopyMemory( &FIBE->Netmask, Netmask, sizeof(FIBE->Netmask) ); FIBE->Router = Router; FIBE->Metric = Metric; /* Add FIB to the forward information base */ TcpipInterlockedInsertTailList(&FIBListHead, &FIBE->ListEntry, &FIBLock); return FIBE; }
PVOID AdjustPacket( PNDIS_PACKET Packet, UINT Available, UINT Needed) /* * FUNCTION: Adjusts the amount of unused space at the beginning of the packet * ARGUMENTS: * Packet = Pointer to packet * Available = Number of bytes available at start of first buffer * Needed = Number of bytes needed for the header * RETURNS: * Pointer to start of packet */ { PNDIS_BUFFER NdisBuffer; INT Adjust; TI_DbgPrint(DEBUG_PBUFFER, ("Available = %d, Needed = %d.\n", Available, Needed)); Adjust = Available - Needed; NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL); /* If Adjust is zero there is no need to adjust this packet as there is no additional space at start the of first buffer */ if (Adjust != 0) { NdisBuffer->MappedSystemVa = (PVOID) ((ULONG_PTR)(NdisBuffer->MappedSystemVa) + Adjust); NdisBuffer->ByteOffset += Adjust; NdisBuffer->ByteCount -= Adjust; } return NdisBuffer->MappedSystemVa; }
/* Must be called with table lock acquired */ VOID NBFlushPacketQueue( PNEIGHBOR_CACHE_ENTRY NCE, NTSTATUS ErrorCode ) { PLIST_ENTRY PacketEntry; PNEIGHBOR_PACKET Packet; while( !IsListEmpty(&NCE->PacketQueue) ) { PacketEntry = RemoveHeadList(&NCE->PacketQueue); Packet = CONTAINING_RECORD ( PacketEntry, NEIGHBOR_PACKET, Next ); ASSERT_KM_POINTER(Packet); TI_DbgPrint (MID_TRACE, ("PacketEntry: %x, NdisPacket %x\n", PacketEntry, Packet->Packet)); ASSERT_KM_POINTER(Packet->Complete); Packet->Complete( Packet->Context, Packet->Packet, ErrorCode ); ExFreePoolWithTag( Packet, NEIGHBOR_PACKET_TAG ); } }
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); }
VOID NBSendPackets( PNEIGHBOR_CACHE_ENTRY NCE ) { PLIST_ENTRY PacketEntry; PNEIGHBOR_PACKET Packet; UINT HashValue; ASSERT(!(NCE->State & NUD_INCOMPLETE)); HashValue = *(PULONG)(&NCE->Address.Address); HashValue ^= HashValue >> 16; HashValue ^= HashValue >> 8; HashValue ^= HashValue >> 4; HashValue &= NB_HASHMASK; /* Send any waiting packets */ while ((PacketEntry = ExInterlockedRemoveHeadList(&NCE->PacketQueue, &NeighborCache[HashValue].Lock)) != NULL) { Packet = CONTAINING_RECORD( PacketEntry, NEIGHBOR_PACKET, Next ); TI_DbgPrint (MID_TRACE, ("PacketEntry: %x, NdisPacket %x\n", PacketEntry, Packet->Packet)); PC(Packet->Packet)->DLComplete = NBCompleteSend; PC(Packet->Packet)->Context = Packet; NCE->Interface->Transmit ( NCE->Interface->Context, Packet->Packet, 0, NCE->LinkAddress, LAN_PROTO_IPv4 ); } }
VOID FreeNdisPacketX ( PNDIS_PACKET Packet, PCHAR File, UINT Line ) /* * FUNCTION: Frees an NDIS packet * ARGUMENTS: * Packet = Pointer to NDIS packet to be freed */ { PNDIS_BUFFER Buffer, NextBuffer; TI_DbgPrint(DEBUG_PBUFFER, ("Packet (0x%X)\n", Packet)); /* Free all the buffers in the packet first */ NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL); for (; Buffer != NULL; Buffer = NextBuffer) { PVOID Data; UINT Length; NdisGetNextBuffer(Buffer, &NextBuffer); XNdisQueryBuffer(Buffer, &Data, &Length); UntrackFL(File,Line,Buffer); NdisFreeBuffer(Buffer); exFreePool(Data); } /* Finally free the NDIS packet descriptor */ UntrackFL(File,Line,Packet); NdisFreePacket(Packet); }
VOID ICMPReply( PIP_INTERFACE Interface, PIP_PACKET IPPacket, UCHAR Type, UCHAR Code) /* * FUNCTION: Transmits an ICMP packet in response to an incoming packet * ARGUMENTS: * NTE = Pointer to net table entry to use * IPPacket = Pointer to IP packet that was received * Type = ICMP message type * Code = ICMP message code * NOTES: * We have received a packet from someone and is unable to * process it due to error(s) in the packet or we have run out * of resources. We transmit an ICMP message to the host to * notify him of the problem */ { UINT DataSize; IP_PACKET NewPacket; TI_DbgPrint(DEBUG_ICMP, ("Called. Type (%d) Code (%d).\n", Type, Code)); DataSize = IPPacket->TotalSize - IPPacket->HeaderSize; if( !PrepareICMPPacket(NULL, Interface, &NewPacket, &IPPacket->SrcAddr, IPPacket->Data, DataSize) ) return; ((PICMP_HEADER)NewPacket.Data)->Type = Type; ((PICMP_HEADER)NewPacket.Data)->Code = Code; ((PICMP_HEADER)NewPacket.Data)->Checksum = 0; ICMPTransmit(&NewPacket, NULL, NULL); }
UINT CopyPacketToBuffer( PCHAR DstData, PNDIS_PACKET SrcPacket, UINT SrcOffset, UINT Length) /* * FUNCTION: Copies data from an NDIS packet to a buffer * ARGUMENTS: * DstData = Pointer to destination buffer * SrcPacket = Pointer to source NDIS packet * SrcOffset = Source start offset * Length = Number of bytes to copy * RETURNS: * Number of bytes copied to destination buffer * NOTES: * The number of bytes copied may be limited by the source * buffer size */ { PNDIS_BUFFER FirstBuffer; PVOID Address; UINT FirstLength; UINT TotalLength; TI_DbgPrint(DEBUG_PBUFFER, ("DstData (0x%X) SrcPacket (0x%X) SrcOffset (0x%X) Length (%d)\n", DstData, SrcPacket, SrcOffset, Length)); NdisGetFirstBufferFromPacket(SrcPacket, &FirstBuffer, &Address, &FirstLength, &TotalLength); return CopyBufferChainToBuffer(DstData, FirstBuffer, SrcOffset, Length); }
/* * FUNCTION: Closes an address file object * ARGUMENTS: * Request = Pointer to TDI request structure for this request * RETURNS: * Status of operation */ NTSTATUS FileCloseAddress( PTDI_REQUEST Request) { PADDRESS_FILE AddrFile = Request->Handle.AddressHandle; KIRQL OldIrql; if (!Request->Handle.AddressHandle) return STATUS_INVALID_PARAMETER; LockObject(AddrFile, &OldIrql); if (InterlockedDecrement(&AddrFile->Sharers) != 0) { /* Still other guys have open handles to this, so keep it around */ UnlockObject(AddrFile, OldIrql); return STATUS_SUCCESS; } /* We have to close this listener because we started it */ if( AddrFile->Listener ) { TCPClose( AddrFile->Listener ); } UnlockObject(AddrFile, OldIrql); DereferenceObject(AddrFile); TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); return STATUS_SUCCESS; }
UINT CommonPrefixLength( PIP_ADDRESS Address1, PIP_ADDRESS Address2) /* * FUNCTION: Computes the length of the longest prefix common to two addresses * ARGUMENTS: * Address1 = Pointer to first address * Address2 = Pointer to second address * NOTES: * The two addresses must be of the same type * RETURNS: * Length of longest common prefix */ { PUCHAR Addr1, Addr2; UINT Size; UINT i, j; UINT Bitmask; TI_DbgPrint(DEBUG_ROUTER, ("Called. Address1 (0x%X) Address2 (0x%X).\n", Address1, Address2)); /*TI_DbgPrint(DEBUG_ROUTER, ("Target (%s) \n", A2S(Address1)));*/ /*TI_DbgPrint(DEBUG_ROUTER, ("Adapter (%s).\n", A2S(Address2)));*/ if (Address1->Type == IP_ADDRESS_V4) Size = sizeof(IPv4_RAW_ADDRESS); else Size = sizeof(IPv6_RAW_ADDRESS); Addr1 = (PUCHAR)&Address1->Address.IPv4Address; Addr2 = (PUCHAR)&Address2->Address.IPv4Address; /* Find first non-matching byte */ for (i = 0; i < Size && Addr1[i] == Addr2[i]; i++); if( i == Size ) return 8 * i; /* Find first non-matching bit */ Bitmask = 0x80; for (j = 0; (Addr1[i] & Bitmask) == (Addr2[i] & Bitmask); j++) Bitmask >>= 1; TI_DbgPrint(DEBUG_ROUTER, ("Returning %d\n", 8 * i + j)); return 8 * i + j; }
NTSTATUS DispPrepareIrpForCancel( PTRANSPORT_CONTEXT Context, PIRP Irp, PDRIVER_CANCEL CancelRoutine) /* * FUNCTION: Prepare an IRP for cancellation * ARGUMENTS: * Context = Pointer to context information * Irp = Pointer to an I/O request packet * CancelRoutine = Routine to be called when I/O request is cancelled * RETURNS: * Status of operation */ { KIRQL OldIrql; PIO_STACK_LOCATION IrpSp; PTRANSPORT_CONTEXT TransContext; TI_DbgPrint(DEBUG_IRP, ("Called.\n")); IrpSp = IoGetCurrentIrpStackLocation(Irp); TransContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; IoAcquireCancelSpinLock(&OldIrql); if (!Irp->Cancel && !TransContext->CancelIrps) { (void)IoSetCancelRoutine(Irp, CancelRoutine); IoReleaseCancelSpinLock(OldIrql); TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP at 0x%X can now be cancelled).\n", Irp)); return STATUS_SUCCESS; } /* IRP has already been cancelled */ IoReleaseCancelSpinLock(OldIrql); Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP was already cancelled).\n")); return Irp->IoStatus.Status; }
PFIB_ENTRY RouterCreateRoute( PIP_ADDRESS NetworkAddress, PIP_ADDRESS Netmask, PIP_ADDRESS RouterAddress, PIP_INTERFACE Interface, UINT Metric) /* * FUNCTION: Creates a route with IPv4 addresses as parameters * ARGUMENTS: * NetworkAddress = Address of network * Netmask = Netmask of network * RouterAddress = Address of router to use * NTE = Pointer to NTE to use * Metric = Cost of this route * RETURNS: * Pointer to FIB entry if the route was created, NULL if not. * The FIB entry references the NTE. The caller is responsible * for providing this reference */ { KIRQL OldIrql; PLIST_ENTRY CurrentEntry; PLIST_ENTRY NextEntry; PFIB_ENTRY Current; PNEIGHBOR_CACHE_ENTRY NCE; TcpipAcquireSpinLock(&FIBLock, &OldIrql); CurrentEntry = FIBListHead.Flink; while (CurrentEntry != &FIBListHead) { NextEntry = CurrentEntry->Flink; Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); NCE = Current->Router; if( AddrIsEqual(NetworkAddress, &Current->NetworkAddress) && AddrIsEqual(Netmask, &Current->Netmask) ) { TI_DbgPrint(DEBUG_ROUTER,("Attempting to add duplicate route to %s\n", A2S(NetworkAddress))); TcpipReleaseSpinLock(&FIBLock, OldIrql); return NULL; } CurrentEntry = NextEntry; } TcpipReleaseSpinLock(&FIBLock, OldIrql); /* The NCE references RouterAddress. The NCE is referenced for us */ NCE = NBFindOrCreateNeighbor(Interface, RouterAddress); if (!NCE) { /* Not enough free resources */ return NULL; } return RouterAddRoute(NetworkAddress, Netmask, NCE, Metric); }
TDI_STATUS InfoTdiQueryGetAddrTable(TDIEntityID ID, PNDIS_BUFFER Buffer, PUINT BufferSize) { KIRQL OldIrql; PIPADDR_ENTRY IPEntry; PIP_INTERFACE CurrentIF; UINT i; TI_DbgPrint(DEBUG_INFO, ("Called.\n")); TcpipAcquireSpinLock(&EntityListLock, &OldIrql); for (i = 0; i < EntityCount; i++) { if (EntityList[i].tei_entity == ID.tei_entity && EntityList[i].tei_instance == ID.tei_instance) break; } if (i == EntityCount) { TcpipReleaseSpinLock(&EntityListLock, OldIrql); return TDI_INVALID_PARAMETER; } IPEntry = ExAllocatePool(NonPagedPool, sizeof(IPADDR_ENTRY)); if (!IPEntry) { TcpipReleaseSpinLock(&EntityListLock, OldIrql); return TDI_NO_RESOURCES; } CurrentIF = EntityList[i].context; IPEntry->Index = CurrentIF->Index; GetInterfaceIPv4Address(CurrentIF, ADE_UNICAST, &IPEntry->Addr); GetInterfaceIPv4Address(CurrentIF, ADE_ADDRMASK, &IPEntry->Mask); GetInterfaceIPv4Address(CurrentIF, ADE_BROADCAST, &IPEntry->BcastAddr); TcpipReleaseSpinLock(&EntityListLock, OldIrql); InfoCopyOut((PCHAR)IPEntry, sizeof(IPADDR_ENTRY), Buffer, BufferSize); ExFreePool(IPEntry); return TDI_SUCCESS; }
/* * FUNCTION: Closes an connection file object * ARGUMENTS: * Request = Pointer to TDI request structure for this request * RETURNS: * Status of operation */ NTSTATUS FileCloseConnection( PTDI_REQUEST Request) { PCONNECTION_ENDPOINT Connection; TI_DbgPrint(MID_TRACE, ("Called.\n")); Connection = Request->Handle.ConnectionContext; if (!Connection) return STATUS_INVALID_PARAMETER; TCPClose( Connection ); Request->Handle.ConnectionContext = NULL; TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); return STATUS_SUCCESS; }
VOID NTAPI DispCancelListenRequest( PDEVICE_OBJECT Device, PIRP Irp) /* * FUNCTION: Cancels a listen IRP * ARGUMENTS: * Device = Pointer to device object * Irp = Pointer to an I/O request packet */ { PIO_STACK_LOCATION IrpSp; PTRANSPORT_CONTEXT TranContext; PFILE_OBJECT FileObject; PCONNECTION_ENDPOINT Connection; IoReleaseCancelSpinLock(Irp->CancelIrql); TI_DbgPrint(DEBUG_IRP, ("Called.\n")); IrpSp = IoGetCurrentIrpStackLocation(Irp); FileObject = IrpSp->FileObject; TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext; ASSERT( TDI_LISTEN == IrpSp->MinorFunction); TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X).\n", Irp)); #if DBG if (!Irp->Cancel) TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n")); #endif /* Try canceling the request */ Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext; if (TCPAbortListenForSocket(Connection->AddressFile->Listener, Connection)) { Irp->IoStatus.Information = 0; IRPFinish(Irp, STATUS_CANCELLED); } TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); }
UINT CopyBufferToBufferChain( PNDIS_BUFFER DstBuffer, UINT DstOffset, PCHAR SrcData, UINT Length) /* * FUNCTION: Copies data from a buffer to an NDIS buffer chain * ARGUMENTS: * DstBuffer = Pointer to destination NDIS buffer * DstOffset = Destination start offset * SrcData = Pointer to source buffer * Length = Number of bytes to copy * RETURNS: * Number of bytes copied to destination buffer * NOTES: * The number of bytes copied may be limited by the destination * buffer size */ { UINT BytesCopied, BytesToCopy, DstSize; PCHAR DstData; TI_DbgPrint(DEBUG_PBUFFER, ("DstBuffer (0x%X) DstOffset (0x%X) SrcData (0x%X) Length (%d)\n", DstBuffer, DstOffset, SrcData, Length)); /* Skip DstOffset bytes in the destination buffer chain */ if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1) return 0; /* Start copying the data */ BytesCopied = 0; for (;;) { BytesToCopy = MIN(DstSize, Length); RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy); BytesCopied += BytesToCopy; SrcData = (PCHAR)((ULONG_PTR)SrcData + BytesToCopy); Length -= BytesToCopy; if (Length == 0) break; DstSize -= BytesToCopy; if (DstSize == 0) { /* No more bytes in desination buffer. Proceed to the next buffer in the destination buffer chain */ NdisGetNextBuffer(DstBuffer, &DstBuffer); if (!DstBuffer) break; NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize); } } return BytesCopied; }
NTSTATUS IPSendFragment( PNDIS_PACKET NdisPacket, PNEIGHBOR_CACHE_ENTRY NCE, PIPFRAGMENT_CONTEXT IFC) /* * FUNCTION: Sends an IP datagram fragment to a neighbor * ARGUMENTS: * NdisPacket = Pointer to an NDIS packet containing fragment * NCE = Pointer to NCE for first hop to destination * RETURNS: * Status of operation * NOTES: * Lowest level IP send routine */ { TI_DbgPrint(MAX_TRACE, ("Called. NdisPacket (0x%X) NCE (0x%X).\n", NdisPacket, NCE)); TI_DbgPrint(MAX_TRACE, ("NCE->State = %d.\n", NCE->State)); return NBQueuePacket(NCE, NdisPacket, IPSendComplete, IFC); }
VOID ICMPReceive( PIP_INTERFACE Interface, PIP_PACKET IPPacket) /* * FUNCTION: Receives an ICMP packet * ARGUMENTS: * NTE = Pointer to net table entry which the packet was received on * IPPacket = Pointer to an IP packet that was received */ { PICMP_HEADER ICMPHeader; TI_DbgPrint(DEBUG_ICMP, ("Called.\n")); ICMPHeader = (PICMP_HEADER)IPPacket->Data; TI_DbgPrint(DEBUG_ICMP, ("Size (%d).\n", IPPacket->TotalSize)); TI_DbgPrint(DEBUG_ICMP, ("HeaderSize (%d).\n", IPPacket->HeaderSize)); TI_DbgPrint(DEBUG_ICMP, ("Type (%d).\n", ICMPHeader->Type)); TI_DbgPrint(DEBUG_ICMP, ("Code (%d).\n", ICMPHeader->Code)); TI_DbgPrint(DEBUG_ICMP, ("Checksum (0x%X).\n", ICMPHeader->Checksum)); /* Checksum ICMP header and data */ if (!IPv4CorrectChecksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize)) { TI_DbgPrint(DEBUG_ICMP, ("Bad ICMP checksum.\n")); /* Discard packet */ return; } RawIpReceive(Interface, IPPacket); switch (ICMPHeader->Type) { case ICMP_TYPE_ECHO_REQUEST: ICMPReply( Interface, IPPacket, ICMP_TYPE_ECHO_REPLY, 0 ); break; case ICMP_TYPE_ECHO_REPLY: break; default: TI_DbgPrint(DEBUG_ICMP, ("Discarded ICMP datagram of unknown type %d.\n", ICMPHeader->Type)); /* Discard packet */ break; } }
PNEIGHBOR_CACHE_ENTRY RouteGetRouteToDestination(PIP_ADDRESS Destination) /* * FUNCTION: Locates an RCN describing a route to a destination address * ARGUMENTS: * Destination = Pointer to destination address to find route to * RCN = Address of pointer to an RCN * RETURNS: * Status of operation * NOTES: * The RCN is referenced for the caller. The caller is responsible * for dereferencing it after use */ { PNEIGHBOR_CACHE_ENTRY NCE = NULL; PIP_INTERFACE Interface; TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X)\n", Destination)); TI_DbgPrint(DEBUG_RCACHE, ("Destination (%s)\n", A2S(Destination))); #if 0 TI_DbgPrint(MIN_TRACE, ("Displaying tree (before).\n")); PrintTree(RouteCache); #endif /* Check if the destination is on-link */ Interface = FindOnLinkInterface(Destination); if (Interface) { /* The destination address is on-link. Check our neighbor cache */ NCE = NBFindOrCreateNeighbor(Interface, Destination); } else { /* Destination is not on any subnets we're on. Find a router to use */ NCE = RouterGetRoute(Destination); } if( NCE ) TI_DbgPrint(DEBUG_ROUTER,("Interface->MTU: %d\n", NCE->Interface->MTU)); return NCE; }
NTSTATUS TCPSendData ( PCONNECTION_ENDPOINT Connection, PCHAR BufferData, ULONG SendLength, PULONG BytesSent, ULONG Flags, PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { NTSTATUS Status; PTDI_BUCKET Bucket; KIRQL OldIrql; LockObject(Connection, &OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Called for %d bytes (on socket %x)\n", SendLength, Connection->SocketContext)); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection = %x\n", Connection)); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection->SocketContext = %x\n", Connection->SocketContext)); Status = TCPTranslateError(LibTCPSend(Connection, BufferData, SendLength, BytesSent, FALSE)); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Send: %x, %d\n", Status, SendLength)); /* Keep this request around ... there was no data yet */ if (Status == STATUS_PENDING) { /* Freed in TCPSocketState */ Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList); if (!Bucket) { UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Failed to allocate bucket\n")); return STATUS_NO_MEMORY; } Bucket->Request.RequestNotifyObject = Complete; Bucket->Request.RequestContext = Context; InsertTailList( &Connection->SendRequest, &Bucket->Entry ); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n")); } UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP, ("[IP, TCPSendData] Leaving. Status = %x\n", Status)); return Status; }