drivers/lib => lib/drivers
[reactos.git] / reactos / lib / drivers / ip / network / transmit.c
1 /*
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)
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10
11 #include "precomp.h"
12
13 BOOLEAN PrepareNextFragment(PIPFRAGMENT_CONTEXT IFC);
14 NTSTATUS IPSendFragment(PNDIS_PACKET NdisPacket,
15 PNEIGHBOR_CACHE_ENTRY NCE,
16 PIPFRAGMENT_CONTEXT IFC);
17
18 VOID IPSendComplete
19 (PVOID Context, PNDIS_PACKET NdisPacket, NDIS_STATUS NdisStatus)
20 /*
21 * FUNCTION: IP datagram fragment send completion handler
22 * ARGUMENTS:
23 * Context = Pointer to context information (IP_INTERFACE)
24 * Packet = Pointer to NDIS packet that was sent
25 * NdisStatus = NDIS status of operation
26 * NOTES:
27 * This routine is called when an IP datagram fragment has been sent
28 */
29 {
30 PIPFRAGMENT_CONTEXT IFC = (PIPFRAGMENT_CONTEXT)Context;
31
32 TI_DbgPrint
33 (MAX_TRACE,
34 ("Called. Context (0x%X) NdisPacket (0x%X) NdisStatus (0x%X)\n",
35 Context, NdisPacket, NdisStatus));
36
37 /* FIXME: Stop sending fragments and cleanup datagram buffers if
38 there was an error */
39
40 if (PrepareNextFragment(IFC)) {
41 /* A fragment was prepared for transmission, so send it */
42 IPSendFragment(IFC->NdisPacket, IFC->NCE, IFC);
43 } else {
44 TI_DbgPrint(MAX_TRACE, ("Calling completion handler.\n"));
45
46 /* There are no more fragments to transmit, so call completion handler */
47 FreeNdisPacket(IFC->NdisPacket);
48 IFC->Complete(IFC->Context, IFC->Datagram, NdisStatus);
49 exFreePool(IFC);
50 }
51 }
52
53 NTSTATUS IPSendFragment(
54 PNDIS_PACKET NdisPacket,
55 PNEIGHBOR_CACHE_ENTRY NCE,
56 PIPFRAGMENT_CONTEXT IFC)
57 /*
58 * FUNCTION: Sends an IP datagram fragment to a neighbor
59 * ARGUMENTS:
60 * NdisPacket = Pointer to an NDIS packet containing fragment
61 * NCE = Pointer to NCE for first hop to destination
62 * RETURNS:
63 * Status of operation
64 * NOTES:
65 * Lowest level IP send routine
66 */
67 {
68 TI_DbgPrint(MAX_TRACE, ("Called. NdisPacket (0x%X) NCE (0x%X).\n", NdisPacket, NCE));
69
70 TI_DbgPrint(MAX_TRACE, ("NCE->State = %d.\n", NCE->State));
71 return NBQueuePacket(NCE, NdisPacket, IPSendComplete, IFC);
72 }
73
74 BOOLEAN PrepareNextFragment(
75 PIPFRAGMENT_CONTEXT IFC)
76 /*
77 * FUNCTION: Prepares the next fragment of an IP datagram for transmission
78 * ARGUMENTS:
79 * IFC = Pointer to IP fragment context
80 * RETURNS:
81 * TRUE if a fragment was prepared for transmission, FALSE if
82 * there are no more fragments to send
83 */
84 {
85 UINT MaxData;
86 UINT DataSize;
87 PIPv4_HEADER Header;
88 BOOLEAN MoreFragments;
89 USHORT FragOfs;
90
91 TI_DbgPrint(MAX_TRACE, ("Called. IFC (0x%X)\n", IFC));
92
93 if (IFC->BytesLeft != 0) {
94
95 TI_DbgPrint(MAX_TRACE, ("Preparing 1 fragment.\n"));
96
97 MaxData = IFC->PathMTU - IFC->HeaderSize;
98 /* Make fragment a multiplum of 64bit */
99 MaxData -= MaxData % 8;
100 if (IFC->BytesLeft > MaxData) {
101 DataSize = MaxData;
102 MoreFragments = TRUE;
103 } else {
104 DataSize = IFC->BytesLeft;
105 MoreFragments = FALSE;
106 }
107
108 TI_DbgPrint(MID_TRACE,("Copying data from %x to %x (%d)\n",
109 IFC->DatagramData, IFC->Data, DataSize));
110
111 RtlCopyMemory(IFC->Data, IFC->DatagramData, DataSize); // SAFE
112
113 FragOfs = (USHORT)IFC->Position; // Swap?
114 if (MoreFragments)
115 FragOfs |= IPv4_MF_MASK;
116 else
117 FragOfs &= ~IPv4_MF_MASK;
118
119 Header = IFC->Header;
120 Header->FlagsFragOfs = FragOfs;
121
122 /* FIXME: Handle options */
123
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));
128
129 /* Update pointers */
130 IFC->DatagramData = (PVOID)((ULONG_PTR)IFC->DatagramData + DataSize);
131 IFC->Position += DataSize;
132 IFC->BytesLeft -= DataSize;
133
134 return TRUE;
135 } else {
136 TI_DbgPrint(MAX_TRACE, ("No more fragments.\n"));
137 return FALSE;
138 }
139 }
140
141 NTSTATUS SendFragments(
142 PIP_PACKET IPPacket,
143 PNEIGHBOR_CACHE_ENTRY NCE,
144 UINT PathMTU,
145 PIP_TRANSMIT_COMPLETE Complete,
146 PVOID Context)
147 /*
148 * FUNCTION: Fragments and sends the first fragment of an IP datagram
149 * ARGUMENTS:
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
153 * RETURNS:
154 * Status of operation
155 * NOTES:
156 * IP datagram is larger than PathMTU when this is called
157 */
158 {
159 PIPFRAGMENT_CONTEXT IFC;
160 NDIS_STATUS NdisStatus;
161 PVOID Data;
162 UINT BufferSize = MaxLLHeaderSize + PathMTU, InSize;
163 PCHAR InData;
164
165 TI_DbgPrint(MAX_TRACE, ("Called. IPPacket (0x%X) NCE (0x%X) PathMTU (%d).\n",
166 IPPacket, NCE, PathMTU));
167
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;
171
172 TI_DbgPrint(MAX_TRACE, ("Fragment buffer is %d bytes\n", BufferSize));
173
174 IFC = exAllocatePool(NonPagedPool, sizeof(IPFRAGMENT_CONTEXT));
175 if (IFC == NULL)
176 return STATUS_INSUFFICIENT_RESOURCES;
177
178 /* Allocate NDIS packet */
179 NdisStatus = AllocatePacketWithBuffer
180 ( &IFC->NdisPacket, NULL, BufferSize );
181
182 if( !NT_SUCCESS(NdisStatus) ) {
183 exFreePool( IFC );
184 return NdisStatus;
185 }
186
187 GetDataPtr( IFC->NdisPacket, 0, (PCHAR *)&Data, &InSize );
188
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;
194 IFC->NCE = NCE;
195 IFC->Position = 0;
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;
200
201 TI_DbgPrint(MID_TRACE,("Copying header from %x to %x (%d)\n",
202 IPPacket->Header, IFC->Header,
203 IPPacket->HeaderSize));
204
205 RtlCopyMemory( IFC->Header, IPPacket->Header, IPPacket->HeaderSize );
206
207 /* Prepare next fragment for transmission and send it */
208
209 PrepareNextFragment(IFC);
210 IPSendFragment(IFC->NdisPacket, NCE, IFC);
211
212 return STATUS_SUCCESS;
213 }
214
215 NTSTATUS IPSendDatagram(PIP_PACKET IPPacket, PNEIGHBOR_CACHE_ENTRY NCE,
216 PIP_TRANSMIT_COMPLETE Complete, PVOID Context)
217 /*
218 * FUNCTION: Sends an IP datagram to a remote address
219 * ARGUMENTS:
220 * IPPacket = Pointer to an IP packet
221 * RCN = Pointer to route cache node
222 * RETURNS:
223 * Status of operation
224 * NOTES:
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)
228 */
229 {
230 TI_DbgPrint(MAX_TRACE, ("Called. IPPacket (0x%X) NCE (0x%X)\n", IPPacket, NCE));
231
232 DISPLAY_IP_PACKET(IPPacket);
233 /*OskitDumpBuffer( IPPacket->Header, IPPacket->TotalSize );*/
234
235 /* Fetch path MTU now, because it may change */
236 TI_DbgPrint(MID_TRACE,("PathMTU: %d\n", NCE->Interface->MTU));
237
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;
242
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));
246
247 TI_DbgPrint(MAX_TRACE, ("Sending packet (length is %d).\n",
248 WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength)));
249 } else {
250 TI_DbgPrint(MAX_TRACE, ("Sending raw packet (flags are 0x%X).\n",
251 IPPacket->Flags));
252 }
253
254 return SendFragments(IPPacket, NCE, NCE->Interface->MTU,
255 Complete, Context);
256 }
257
258 /* EOF */