err_t TCPSendDataCallback(struct netif *netif, struct pbuf *p, struct ip_addr *dest) { NDIS_STATUS NdisStatus; PNEIGHBOR_CACHE_ENTRY NCE; IP_PACKET Packet = { 0 }; IP_ADDRESS RemoteAddress, LocalAddress; PIPv4_HEADER Header; UINT i; struct pbuf *p1; /* The caller frees the pbuf struct */ if (((*(u8_t*)p->payload) & 0xF0) == 0x40) { Header = p->payload; LocalAddress.Type = IP_ADDRESS_V4; LocalAddress.Address.IPv4Address = Header->SrcAddr; RemoteAddress.Type = IP_ADDRESS_V4; RemoteAddress.Address.IPv4Address = Header->DstAddr; } else { return ERR_IF; } if (!(NCE = RouteGetRouteToDestination(&RemoteAddress))) { return ERR_RTE; } NdisStatus = AllocatePacketWithBuffer(&Packet.NdisPacket, NULL, p->tot_len); if (NdisStatus != NDIS_STATUS_SUCCESS) { return ERR_MEM; } GetDataPtr(Packet.NdisPacket, 0, (PCHAR*)&Packet.Header, &Packet.ContigSize); for (i = 0, p1 = p; i < p->tot_len; i += p1->len, p1 = p1->next) { ASSERT(p1); RtlCopyMemory(((PUCHAR)Packet.Header) + i, p1->payload, p1->len); } Packet.HeaderSize = sizeof(IPv4_HEADER); Packet.TotalSize = p->tot_len; Packet.SrcAddr = LocalAddress; Packet.DstAddr = RemoteAddress; if (!NT_SUCCESS(IPSendDatagram(&Packet, NCE, TCPPacketSendComplete, NULL))) { FreeNdisPacket(Packet.NdisPacket); return ERR_IF; } return 0; }
PNDIS_PACKET PrepareARPPacket( PIP_INTERFACE IF, USHORT HardwareType, USHORT ProtocolType, UCHAR LinkAddressLength, UCHAR ProtoAddressLength, PVOID SenderLinkAddress, PVOID SenderProtoAddress, PVOID TargetLinkAddress, PVOID TargetProtoAddress, USHORT Opcode) /* * FUNCTION: Prepares an ARP packet * ARGUMENTS: * HardwareType = Hardware type (in network byte order) * ProtocolType = Protocol type (in network byte order) * LinkAddressLength = Length of link address fields * ProtoAddressLength = Length of protocol address fields * SenderLinkAddress = Sender's link address * SenderProtoAddress = Sender's protocol address * TargetLinkAddress = Target's link address (NULL if don't care) * TargetProtoAddress = Target's protocol address * Opcode = ARP opcode (in network byte order) * RETURNS: * Pointer to NDIS packet, NULL if there is not enough free resources */ { PNDIS_PACKET NdisPacket; NDIS_STATUS NdisStatus; PARP_HEADER Header; PVOID DataBuffer; ULONG Size, Contig; TI_DbgPrint(DEBUG_ARP, ("Called.\n")); /* Prepare ARP packet */ Size = sizeof(ARP_HEADER) + 2 * LinkAddressLength + /* Hardware address length */ 2 * ProtoAddressLength; /* Protocol address length */ Size = MAX(Size, IF->MinFrameSize - IF->HeaderSize); NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Size ); if( !NT_SUCCESS(NdisStatus) ) return NULL; GetDataPtr( NdisPacket, 0, (PCHAR *)&DataBuffer, (PUINT)&Contig ); ASSERT(DataBuffer); RtlZeroMemory(DataBuffer, Size); Header = (PARP_HEADER)((ULONG_PTR)DataBuffer); Header->HWType = HardwareType; Header->ProtoType = ProtocolType; Header->HWAddrLen = LinkAddressLength; Header->ProtoAddrLen = ProtoAddressLength; Header->Opcode = Opcode; /* Already swapped */ DataBuffer = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER)); /* Our hardware address */ RtlCopyMemory(DataBuffer, SenderLinkAddress, LinkAddressLength); DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + LinkAddressLength); /* Our protocol address */ RtlCopyMemory(DataBuffer, SenderProtoAddress, ProtoAddressLength); if (TargetLinkAddress) { DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + ProtoAddressLength); /* Target hardware address */ RtlCopyMemory(DataBuffer, TargetLinkAddress, LinkAddressLength); DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + LinkAddressLength); } else /* Don't care about target hardware address */ DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + ProtoAddressLength + LinkAddressLength); /* Target protocol address */ RtlCopyMemory(DataBuffer, TargetProtoAddress, ProtoAddressLength); return NdisPacket; }
BOOLEAN PrepareICMPPacket( PADDRESS_FILE AddrFile, PIP_INTERFACE Interface, PIP_PACKET IPPacket, PIP_ADDRESS Destination, PCHAR Data, UINT DataSize) /* * FUNCTION: Prepares an ICMP packet * ARGUMENTS: * NTE = Pointer to net table entry to use * Destination = Pointer to destination address * DataSize = Size of dataarea * RETURNS: * Pointer to IP packet, NULL if there is not enough free resources */ { PNDIS_PACKET NdisPacket; NDIS_STATUS NdisStatus; PIPv4_HEADER IPHeader; ULONG Size; TI_DbgPrint(DEBUG_ICMP, ("Called. DataSize (%d).\n", DataSize)); IPInitializePacket(IPPacket, IP_ADDRESS_V4); /* No special flags */ IPPacket->Flags = 0; Size = sizeof(IPv4_HEADER) + DataSize; /* Allocate NDIS packet */ NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Size ); if( !NT_SUCCESS(NdisStatus) ) return FALSE; IPPacket->NdisPacket = NdisPacket; IPPacket->MappedHeader = TRUE; GetDataPtr( IPPacket->NdisPacket, 0, (PCHAR *)&IPPacket->Header, &IPPacket->TotalSize ); ASSERT(IPPacket->TotalSize == Size); TI_DbgPrint(DEBUG_ICMP, ("Size (%d). Data at (0x%X).\n", Size, Data)); TI_DbgPrint(DEBUG_ICMP, ("NdisPacket at (0x%X).\n", NdisPacket)); IPPacket->HeaderSize = sizeof(IPv4_HEADER); IPPacket->Data = ((PCHAR)IPPacket->Header) + IPPacket->HeaderSize; TI_DbgPrint(DEBUG_ICMP, ("Copying Address: %x -> %x\n", &IPPacket->DstAddr, Destination)); RtlCopyMemory(&IPPacket->DstAddr, Destination, sizeof(IP_ADDRESS)); RtlCopyMemory(IPPacket->Data, Data, DataSize); /* Build IPv4 header. FIXME: IPv4 only */ IPHeader = (PIPv4_HEADER)IPPacket->Header; /* Version = 4, Length = 5 DWORDs */ IPHeader->VerIHL = 0x45; /* Normal Type-of-Service */ IPHeader->Tos = 0; /* Length of data and header */ IPHeader->TotalLength = WH2N((USHORT)DataSize + sizeof(IPv4_HEADER)); /* Identification */ IPHeader->Id = (USHORT)Random(); /* One fragment at offset 0 */ IPHeader->FlagsFragOfs = 0; /* Set TTL */ if (AddrFile) IPHeader->Ttl = AddrFile->TTL; else IPHeader->Ttl = 128; /* Internet Control Message Protocol */ IPHeader->Protocol = IPPROTO_ICMP; /* Checksum is 0 (for later calculation of this) */ IPHeader->Checksum = 0; /* Source address */ IPHeader->SrcAddr = Interface->Unicast.Address.IPv4Address; /* Destination address */ IPHeader->DstAddr = Destination->Address.IPv4Address; TI_DbgPrint(MID_TRACE,("Leaving\n")); return TRUE; }
NTSTATUS SendFragments( PIP_PACKET IPPacket, PNEIGHBOR_CACHE_ENTRY NCE, UINT PathMTU, PIP_TRANSMIT_COMPLETE Complete, PVOID Context) /* * FUNCTION: Fragments and sends the first fragment of an IP datagram * ARGUMENTS: * IPPacket = Pointer to an IP packet * NCE = Pointer to NCE for first hop to destination * PathMTU = Size of Maximum Transmission Unit of path * RETURNS: * Status of operation * NOTES: * IP datagram is larger than PathMTU when this is called */ { PIPFRAGMENT_CONTEXT IFC; NDIS_STATUS NdisStatus; PVOID Data; UINT BufferSize = PathMTU, InSize; PCHAR InData; TI_DbgPrint(MAX_TRACE, ("Called. IPPacket (0x%X) NCE (0x%X) PathMTU (%d).\n", IPPacket, NCE, PathMTU)); /* Make a smaller buffer if we will only send one fragment */ GetDataPtr( IPPacket->NdisPacket, 0, &InData, &InSize ); if( InSize < BufferSize ) BufferSize = InSize; TI_DbgPrint(MAX_TRACE, ("Fragment buffer is %d bytes\n", BufferSize)); IFC = ExAllocatePoolWithTag(NonPagedPool, sizeof(IPFRAGMENT_CONTEXT), IFC_TAG); if (IFC == NULL) return STATUS_INSUFFICIENT_RESOURCES; /* Allocate NDIS packet */ NdisStatus = AllocatePacketWithBuffer ( &IFC->NdisPacket, NULL, BufferSize ); if( !NT_SUCCESS(NdisStatus) ) { ExFreePoolWithTag( IFC, IFC_TAG ); return NdisStatus; } GetDataPtr( IFC->NdisPacket, 0, (PCHAR *)&Data, &InSize ); IFC->Header = ((PCHAR)Data); IFC->Datagram = IPPacket->NdisPacket; IFC->DatagramData = ((PCHAR)IPPacket->Header) + IPPacket->HeaderSize; IFC->HeaderSize = IPPacket->HeaderSize; IFC->PathMTU = PathMTU; IFC->NCE = NCE; IFC->Position = 0; IFC->BytesLeft = IPPacket->TotalSize - IPPacket->HeaderSize; IFC->Data = (PVOID)((ULONG_PTR)IFC->Header + IPPacket->HeaderSize); IFC->Complete = Complete; IFC->Context = Context; TI_DbgPrint(MID_TRACE,("Copying header from %x to %x (%d)\n", IPPacket->Header, IFC->Header, IPPacket->HeaderSize)); RtlCopyMemory( IFC->Header, IPPacket->Header, IPPacket->HeaderSize ); /* Prepare next fragment for transmission and send it */ if (!PrepareNextFragment(IFC)) { FreeNdisPacket(IFC->NdisPacket); ExFreePoolWithTag(IFC, IFC_TAG); return NDIS_STATUS_FAILURE; } if (!NT_SUCCESS((NdisStatus = IPSendFragment(IFC->NdisPacket, NCE, IFC)))) { FreeNdisPacket(IFC->NdisPacket); ExFreePoolWithTag(IFC, IFC_TAG); } return NdisStatus; }