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
;
35 ("Called. Context (0x%X) NdisPacket (0x%X) NdisStatus (0x%X)\n",
36 Context
, NdisPacket
, NdisStatus
));
38 if (NT_SUCCESS(NdisStatus
) && PrepareNextFragment(IFC
)) {
39 /* A fragment was prepared for transmission, so send it */
40 Status
= IPSendFragment(IFC
->NdisPacket
, IFC
->NCE
, IFC
);
41 if (!NT_SUCCESS(Status
))
43 FreeNdisPacket(IFC
->NdisPacket
);
44 IFC
->Complete(IFC
->Context
, IFC
->Datagram
, Status
);
45 ExFreePoolWithTag(IFC
, IFC_TAG
);
48 TI_DbgPrint(MAX_TRACE
, ("Calling completion handler.\n"));
50 /* There are no more fragments to transmit, so call completion handler */
51 FreeNdisPacket(IFC
->NdisPacket
);
52 IFC
->Complete(IFC
->Context
, IFC
->Datagram
, NdisStatus
);
53 ExFreePoolWithTag(IFC
, IFC_TAG
);
57 NTSTATUS
IPSendFragment(
58 PNDIS_PACKET NdisPacket
,
59 PNEIGHBOR_CACHE_ENTRY NCE
,
60 PIPFRAGMENT_CONTEXT IFC
)
62 * FUNCTION: Sends an IP datagram fragment to a neighbor
64 * NdisPacket = Pointer to an NDIS packet containing fragment
65 * NCE = Pointer to NCE for first hop to destination
69 * Lowest level IP send routine
72 TI_DbgPrint(MAX_TRACE
, ("Called. NdisPacket (0x%X) NCE (0x%X).\n", NdisPacket
, NCE
));
74 TI_DbgPrint(MAX_TRACE
, ("NCE->State = %d.\n", NCE
->State
));
75 return NBQueuePacket(NCE
, NdisPacket
, IPSendComplete
, IFC
);
78 BOOLEAN
PrepareNextFragment(
79 PIPFRAGMENT_CONTEXT IFC
)
81 * FUNCTION: Prepares the next fragment of an IP datagram for transmission
83 * IFC = Pointer to IP fragment context
85 * TRUE if a fragment was prepared for transmission, FALSE if
86 * there are no more fragments to send
92 BOOLEAN MoreFragments
;
95 TI_DbgPrint(MAX_TRACE
, ("Called. IFC (0x%X)\n", IFC
));
97 if (IFC
->BytesLeft
> 0) {
99 TI_DbgPrint(MAX_TRACE
, ("Preparing 1 fragment.\n"));
101 MaxData
= IFC
->PathMTU
- IFC
->HeaderSize
;
102 /* Make fragment a multiplum of 64bit */
103 MaxData
-= MaxData
% 8;
104 if (IFC
->BytesLeft
> MaxData
) {
106 MoreFragments
= TRUE
;
108 DataSize
= IFC
->BytesLeft
;
109 MoreFragments
= FALSE
;
112 TI_DbgPrint(MID_TRACE
,("Copying data from %x to %x (%d)\n",
113 IFC
->DatagramData
, IFC
->Data
, DataSize
));
115 RtlCopyMemory(IFC
->Data
, IFC
->DatagramData
, DataSize
); // SAFE
117 /* Fragment offset is in 8 byte blocks */
118 FragOfs
= (USHORT
)(IFC
->Position
/ 8);
121 FragOfs
|= IPv4_MF_MASK
;
123 FragOfs
&= ~IPv4_MF_MASK
;
125 Header
= IFC
->Header
;
126 Header
->FlagsFragOfs
= WH2N(FragOfs
);
127 Header
->TotalLength
= WH2N((USHORT
)(DataSize
+ IFC
->HeaderSize
));
129 /* FIXME: Handle options */
131 /* Calculate checksum of IP header */
132 Header
->Checksum
= 0;
133 Header
->Checksum
= (USHORT
)IPv4Checksum(Header
, IFC
->HeaderSize
, 0);
134 TI_DbgPrint(MID_TRACE
,("IP Check: %x\n", Header
->Checksum
));
136 /* Update pointers */
137 IFC
->DatagramData
= (PVOID
)((ULONG_PTR
)IFC
->DatagramData
+ DataSize
);
138 IFC
->Position
+= DataSize
;
139 IFC
->BytesLeft
-= DataSize
;
143 TI_DbgPrint(MAX_TRACE
, ("No more fragments.\n"));
148 NTSTATUS
SendFragments(
150 PNEIGHBOR_CACHE_ENTRY NCE
,
152 PIP_TRANSMIT_COMPLETE Complete
,
155 * FUNCTION: Fragments and sends the first fragment of an IP datagram
157 * IPPacket = Pointer to an IP packet
158 * NCE = Pointer to NCE for first hop to destination
159 * PathMTU = Size of Maximum Transmission Unit of path
161 * Status of operation
163 * IP datagram is larger than PathMTU when this is called
166 PIPFRAGMENT_CONTEXT IFC
;
167 NDIS_STATUS NdisStatus
;
169 UINT BufferSize
= PathMTU
, InSize
;
172 TI_DbgPrint(MAX_TRACE
, ("Called. IPPacket (0x%X) NCE (0x%X) PathMTU (%d).\n",
173 IPPacket
, NCE
, PathMTU
));
175 /* Make a smaller buffer if we will only send one fragment */
176 GetDataPtr( IPPacket
->NdisPacket
, 0, &InData
, &InSize
);
177 if( InSize
< BufferSize
) BufferSize
= InSize
;
179 TI_DbgPrint(MAX_TRACE
, ("Fragment buffer is %d bytes\n", BufferSize
));
181 IFC
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(IPFRAGMENT_CONTEXT
), IFC_TAG
);
183 return STATUS_INSUFFICIENT_RESOURCES
;
185 /* Allocate NDIS packet */
186 NdisStatus
= AllocatePacketWithBuffer
187 ( &IFC
->NdisPacket
, NULL
, BufferSize
);
189 if( !NT_SUCCESS(NdisStatus
) ) {
190 ExFreePoolWithTag( IFC
, IFC_TAG
);
194 GetDataPtr( IFC
->NdisPacket
, 0, (PCHAR
*)&Data
, &InSize
);
196 IFC
->Header
= ((PCHAR
)Data
);
197 IFC
->Datagram
= IPPacket
->NdisPacket
;
198 IFC
->DatagramData
= ((PCHAR
)IPPacket
->Header
) + IPPacket
->HeaderSize
;
199 IFC
->HeaderSize
= IPPacket
->HeaderSize
;
200 IFC
->PathMTU
= PathMTU
;
203 IFC
->BytesLeft
= IPPacket
->TotalSize
- IPPacket
->HeaderSize
;
204 IFC
->Data
= (PVOID
)((ULONG_PTR
)IFC
->Header
+ IPPacket
->HeaderSize
);
205 IFC
->Complete
= Complete
;
206 IFC
->Context
= Context
;
208 TI_DbgPrint(MID_TRACE
,("Copying header from %x to %x (%d)\n",
209 IPPacket
->Header
, IFC
->Header
,
210 IPPacket
->HeaderSize
));
212 RtlCopyMemory( IFC
->Header
, IPPacket
->Header
, IPPacket
->HeaderSize
);
214 /* Prepare next fragment for transmission and send it */
216 if (!PrepareNextFragment(IFC
)) {
217 FreeNdisPacket(IFC
->NdisPacket
);
218 ExFreePoolWithTag(IFC
, IFC_TAG
);
219 return NDIS_STATUS_FAILURE
;
222 if (!NT_SUCCESS((NdisStatus
= IPSendFragment(IFC
->NdisPacket
, NCE
, IFC
))))
224 FreeNdisPacket(IFC
->NdisPacket
);
225 ExFreePoolWithTag(IFC
, IFC_TAG
);
231 NTSTATUS
IPSendDatagram(PIP_PACKET IPPacket
, PNEIGHBOR_CACHE_ENTRY NCE
,
232 PIP_TRANSMIT_COMPLETE Complete
, PVOID Context
)
234 * FUNCTION: Sends an IP datagram to a remote address
236 * IPPacket = Pointer to an IP packet
237 * RCN = Pointer to route cache node
239 * Status of operation
241 * This is the highest level IP send routine. It possibly breaks the packet
242 * into two or more fragments before passing it on to the next lower level
243 * send routine (IPSendFragment)
248 TI_DbgPrint(MAX_TRACE
, ("Called. IPPacket (0x%X) NCE (0x%X)\n", IPPacket
, NCE
));
250 DISPLAY_IP_PACKET(IPPacket
);
251 /*OskitDumpBuffer( IPPacket->Header, IPPacket->TotalSize );*/
253 /* Fetch path MTU now, because it may change */
254 TI_DbgPrint(MID_TRACE
,("PathMTU: %d\n", NCE
->Interface
->MTU
));
256 NdisQueryPacket(IPPacket
->NdisPacket
,
262 NCE
->Interface
->Stats
.OutBytes
+= PacketSize
;
264 return SendFragments(IPPacket
, NCE
, NCE
->Interface
->MTU
,