2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: network/transmit.c
5 * PURPOSE: Internet Protocol transmit routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
13 BOOLEAN
PrepareNextFragment(PIPFRAGMENT_CONTEXT IFC
);
14 NTSTATUS
IPSendFragment(PNDIS_PACKET NdisPacket
,
15 PNEIGHBOR_CACHE_ENTRY NCE
,
16 PIPFRAGMENT_CONTEXT IFC
);
19 (PVOID Context
, PNDIS_PACKET NdisPacket
, NDIS_STATUS NdisStatus
)
21 * FUNCTION: IP datagram fragment send completion handler
23 * Context = Pointer to context information (IP_INTERFACE)
24 * Packet = Pointer to NDIS packet that was sent
25 * NdisStatus = NDIS status of operation
27 * This routine is called when an IP datagram fragment has been sent
30 PIPFRAGMENT_CONTEXT IFC
= (PIPFRAGMENT_CONTEXT
)Context
;
34 ("Called. Context (0x%X) NdisPacket (0x%X) NdisStatus (0x%X)\n",
35 Context
, NdisPacket
, NdisStatus
));
37 /* FIXME: Stop sending fragments and cleanup datagram buffers if
40 if (PrepareNextFragment(IFC
)) {
41 /* A fragment was prepared for transmission, so send it */
42 IPSendFragment(IFC
->NdisPacket
, IFC
->NCE
, IFC
);
44 TI_DbgPrint(MAX_TRACE
, ("Calling completion handler.\n"));
46 /* There are no more fragments to transmit, so call completion handler */
47 FreeNdisPacket(IFC
->NdisPacket
);
48 IFC
->Complete(IFC
->Context
, IFC
->Datagram
, NdisStatus
);
53 NTSTATUS
IPSendFragment(
54 PNDIS_PACKET NdisPacket
,
55 PNEIGHBOR_CACHE_ENTRY NCE
,
56 PIPFRAGMENT_CONTEXT IFC
)
58 * FUNCTION: Sends an IP datagram fragment to a neighbor
60 * NdisPacket = Pointer to an NDIS packet containing fragment
61 * NCE = Pointer to NCE for first hop to destination
65 * Lowest level IP send routine
68 TI_DbgPrint(MAX_TRACE
, ("Called. NdisPacket (0x%X) NCE (0x%X).\n", NdisPacket
, NCE
));
70 TI_DbgPrint(MAX_TRACE
, ("NCE->State = %d.\n", NCE
->State
));
71 return NBQueuePacket(NCE
, NdisPacket
, IPSendComplete
, IFC
);
74 BOOLEAN
PrepareNextFragment(
75 PIPFRAGMENT_CONTEXT IFC
)
77 * FUNCTION: Prepares the next fragment of an IP datagram for transmission
79 * IFC = Pointer to IP fragment context
81 * TRUE if a fragment was prepared for transmission, FALSE if
82 * there are no more fragments to send
88 BOOLEAN MoreFragments
;
91 TI_DbgPrint(MAX_TRACE
, ("Called. IFC (0x%X)\n", IFC
));
93 if (IFC
->BytesLeft
!= 0) {
95 TI_DbgPrint(MAX_TRACE
, ("Preparing 1 fragment.\n"));
97 MaxData
= IFC
->PathMTU
- IFC
->HeaderSize
;
98 /* Make fragment a multiplum of 64bit */
99 MaxData
-= MaxData
% 8;
100 if (IFC
->BytesLeft
> MaxData
) {
102 MoreFragments
= TRUE
;
104 DataSize
= IFC
->BytesLeft
;
105 MoreFragments
= FALSE
;
108 TI_DbgPrint(MID_TRACE
,("Copying data from %x to %x (%d)\n",
109 IFC
->DatagramData
, IFC
->Data
, DataSize
));
111 RtlCopyMemory(IFC
->Data
, IFC
->DatagramData
, DataSize
); // SAFE
113 FragOfs
= (USHORT
)IFC
->Position
; // Swap?
115 FragOfs
|= IPv4_MF_MASK
;
117 FragOfs
&= ~IPv4_MF_MASK
;
119 Header
= IFC
->Header
;
120 Header
->FlagsFragOfs
= FragOfs
;
122 /* FIXME: Handle options */
124 /* Calculate checksum of IP header */
125 Header
->Checksum
= 0;
126 Header
->Checksum
= (USHORT
)IPv4Checksum(Header
, IFC
->HeaderSize
, 0);
127 TI_DbgPrint(MID_TRACE
,("IP Check: %x\n", Header
->Checksum
));
129 /* Update pointers */
130 IFC
->DatagramData
= (PVOID
)((ULONG_PTR
)IFC
->DatagramData
+ DataSize
);
131 IFC
->Position
+= DataSize
;
132 IFC
->BytesLeft
-= DataSize
;
136 TI_DbgPrint(MAX_TRACE
, ("No more fragments.\n"));
141 NTSTATUS
SendFragments(
143 PNEIGHBOR_CACHE_ENTRY NCE
,
145 PIP_TRANSMIT_COMPLETE Complete
,
148 * FUNCTION: Fragments and sends the first fragment of an IP datagram
150 * IPPacket = Pointer to an IP packet
151 * NCE = Pointer to NCE for first hop to destination
152 * PathMTU = Size of Maximum Transmission Unit of path
154 * Status of operation
156 * IP datagram is larger than PathMTU when this is called
159 PIPFRAGMENT_CONTEXT IFC
;
160 NDIS_STATUS NdisStatus
;
162 UINT BufferSize
= MaxLLHeaderSize
+ PathMTU
, InSize
;
165 TI_DbgPrint(MAX_TRACE
, ("Called. IPPacket (0x%X) NCE (0x%X) PathMTU (%d).\n",
166 IPPacket
, NCE
, PathMTU
));
168 /* Make a smaller buffer if we will only send one fragment */
169 GetDataPtr( IPPacket
->NdisPacket
, 0, &InData
, &InSize
);
170 if( InSize
< BufferSize
) BufferSize
= InSize
;
172 TI_DbgPrint(MAX_TRACE
, ("Fragment buffer is %d bytes\n", BufferSize
));
174 IFC
= exAllocatePool(NonPagedPool
, sizeof(IPFRAGMENT_CONTEXT
));
176 return STATUS_INSUFFICIENT_RESOURCES
;
178 /* Allocate NDIS packet */
179 NdisStatus
= AllocatePacketWithBuffer
180 ( &IFC
->NdisPacket
, NULL
, BufferSize
);
182 if( !NT_SUCCESS(NdisStatus
) ) {
187 GetDataPtr( IFC
->NdisPacket
, 0, (PCHAR
*)&Data
, &InSize
);
189 IFC
->Header
= ((PCHAR
)Data
) + MaxLLHeaderSize
;
190 IFC
->Datagram
= IPPacket
->NdisPacket
;
191 IFC
->DatagramData
= ((PCHAR
)IPPacket
->Header
) + IPPacket
->HeaderSize
;
192 IFC
->HeaderSize
= IPPacket
->HeaderSize
;
193 IFC
->PathMTU
= PathMTU
;
196 IFC
->BytesLeft
= IPPacket
->TotalSize
- IPPacket
->HeaderSize
;
197 IFC
->Data
= (PVOID
)((ULONG_PTR
)IFC
->Header
+ IPPacket
->HeaderSize
);
198 IFC
->Complete
= Complete
;
199 IFC
->Context
= Context
;
201 TI_DbgPrint(MID_TRACE
,("Copying header from %x to %x (%d)\n",
202 IPPacket
->Header
, IFC
->Header
,
203 IPPacket
->HeaderSize
));
205 RtlCopyMemory( IFC
->Header
, IPPacket
->Header
, IPPacket
->HeaderSize
);
207 /* Prepare next fragment for transmission and send it */
209 PrepareNextFragment(IFC
);
210 IPSendFragment(IFC
->NdisPacket
, NCE
, IFC
);
212 return STATUS_SUCCESS
;
215 NTSTATUS
IPSendDatagram(PIP_PACKET IPPacket
, PNEIGHBOR_CACHE_ENTRY NCE
,
216 PIP_TRANSMIT_COMPLETE Complete
, PVOID Context
)
218 * FUNCTION: Sends an IP datagram to a remote address
220 * IPPacket = Pointer to an IP packet
221 * RCN = Pointer to route cache node
223 * Status of operation
225 * This is the highest level IP send routine. It possibly breaks the packet
226 * into two or more fragments before passing it on to the next lower level
227 * send routine (IPSendFragment)
230 TI_DbgPrint(MAX_TRACE
, ("Called. IPPacket (0x%X) NCE (0x%X)\n", IPPacket
, NCE
));
232 DISPLAY_IP_PACKET(IPPacket
);
233 /*OskitDumpBuffer( IPPacket->Header, IPPacket->TotalSize );*/
235 /* Fetch path MTU now, because it may change */
236 TI_DbgPrint(MID_TRACE
,("PathMTU: %d\n", NCE
->Interface
->MTU
));
238 if ((IPPacket
->Flags
& IP_PACKET_FLAG_RAW
) == 0) {
239 /* Calculate checksum of IP header */
240 TI_DbgPrint(MID_TRACE
,("-> not IP_PACKET_FLAG_RAW\n"));
241 ((PIPv4_HEADER
)IPPacket
->Header
)->Checksum
= 0;
243 ((PIPv4_HEADER
)IPPacket
->Header
)->Checksum
= (USHORT
)
244 IPv4Checksum(IPPacket
->Header
, IPPacket
->HeaderSize
, 0);
245 TI_DbgPrint(MID_TRACE
,("IP Check: %x\n", ((PIPv4_HEADER
)IPPacket
->Header
)->Checksum
));
247 TI_DbgPrint(MAX_TRACE
, ("Sending packet (length is %d).\n",
248 WN2H(((PIPv4_HEADER
)IPPacket
->Header
)->TotalLength
)));
250 TI_DbgPrint(MAX_TRACE
, ("Sending raw packet (flags are 0x%X).\n",
254 return SendFragments(IPPacket
, NCE
, NCE
->Interface
->MTU
,