810c4854337129e4110c6e83569bfd7017ccb5b3
[reactos.git] / 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 if (NT_SUCCESS(NdisStatus) && PrepareNextFragment(IFC)) {
38 /* A fragment was prepared for transmission, so send it */
39 IPSendFragment(IFC->NdisPacket, IFC->NCE, IFC);
40 } else {
41 TI_DbgPrint(MAX_TRACE, ("Calling completion handler.\n"));
42
43 /* There are no more fragments to transmit, so call completion handler */
44 FreeNdisPacket(IFC->NdisPacket);
45 IFC->Complete(IFC->Context, IFC->Datagram, NdisStatus);
46 exFreePool(IFC);
47 }
48 }
49
50 NTSTATUS IPSendFragment(
51 PNDIS_PACKET NdisPacket,
52 PNEIGHBOR_CACHE_ENTRY NCE,
53 PIPFRAGMENT_CONTEXT IFC)
54 /*
55 * FUNCTION: Sends an IP datagram fragment to a neighbor
56 * ARGUMENTS:
57 * NdisPacket = Pointer to an NDIS packet containing fragment
58 * NCE = Pointer to NCE for first hop to destination
59 * RETURNS:
60 * Status of operation
61 * NOTES:
62 * Lowest level IP send routine
63 */
64 {
65 TI_DbgPrint(MAX_TRACE, ("Called. NdisPacket (0x%X) NCE (0x%X).\n", NdisPacket, NCE));
66
67 TI_DbgPrint(MAX_TRACE, ("NCE->State = %d.\n", NCE->State));
68 return NBQueuePacket(NCE, NdisPacket, IPSendComplete, IFC);
69 }
70
71 BOOLEAN PrepareNextFragment(
72 PIPFRAGMENT_CONTEXT IFC)
73 /*
74 * FUNCTION: Prepares the next fragment of an IP datagram for transmission
75 * ARGUMENTS:
76 * IFC = Pointer to IP fragment context
77 * RETURNS:
78 * TRUE if a fragment was prepared for transmission, FALSE if
79 * there are no more fragments to send
80 */
81 {
82 UINT MaxData;
83 UINT DataSize;
84 PIPv4_HEADER Header;
85 BOOLEAN MoreFragments;
86 USHORT FragOfs;
87
88 TI_DbgPrint(MAX_TRACE, ("Called. IFC (0x%X)\n", IFC));
89
90 if (IFC->BytesLeft != 0) {
91
92 TI_DbgPrint(MAX_TRACE, ("Preparing 1 fragment.\n"));
93
94 MaxData = IFC->PathMTU - IFC->HeaderSize;
95 /* Make fragment a multiplum of 64bit */
96 MaxData -= MaxData % 8;
97 if (IFC->BytesLeft > MaxData) {
98 DataSize = MaxData;
99 MoreFragments = TRUE;
100 } else {
101 DataSize = IFC->BytesLeft;
102 MoreFragments = FALSE;
103 }
104
105 TI_DbgPrint(MID_TRACE,("Copying data from %x to %x (%d)\n",
106 IFC->DatagramData, IFC->Data, DataSize));
107
108 RtlCopyMemory(IFC->Data, IFC->DatagramData, DataSize); // SAFE
109
110 FragOfs = (USHORT)IFC->Position; // Swap?
111 if (MoreFragments)
112 FragOfs |= IPv4_MF_MASK;
113 else
114 FragOfs &= ~IPv4_MF_MASK;
115
116 Header = IFC->Header;
117 Header->FlagsFragOfs = FragOfs;
118
119 /* FIXME: Handle options */
120
121 /* Calculate checksum of IP header */
122 Header->Checksum = 0;
123 Header->Checksum = (USHORT)IPv4Checksum(Header, IFC->HeaderSize, 0);
124 TI_DbgPrint(MID_TRACE,("IP Check: %x\n", Header->Checksum));
125
126 /* Update pointers */
127 IFC->DatagramData = (PVOID)((ULONG_PTR)IFC->DatagramData + DataSize);
128 IFC->Position += DataSize;
129 IFC->BytesLeft -= DataSize;
130
131 return TRUE;
132 } else {
133 TI_DbgPrint(MAX_TRACE, ("No more fragments.\n"));
134 return FALSE;
135 }
136 }
137
138 NTSTATUS SendFragments(
139 PIP_PACKET IPPacket,
140 PNEIGHBOR_CACHE_ENTRY NCE,
141 UINT PathMTU,
142 PIP_TRANSMIT_COMPLETE Complete,
143 PVOID Context)
144 /*
145 * FUNCTION: Fragments and sends the first fragment of an IP datagram
146 * ARGUMENTS:
147 * IPPacket = Pointer to an IP packet
148 * NCE = Pointer to NCE for first hop to destination
149 * PathMTU = Size of Maximum Transmission Unit of path
150 * RETURNS:
151 * Status of operation
152 * NOTES:
153 * IP datagram is larger than PathMTU when this is called
154 */
155 {
156 PIPFRAGMENT_CONTEXT IFC;
157 NDIS_STATUS NdisStatus;
158 PVOID Data;
159 UINT BufferSize = MaxLLHeaderSize + PathMTU, InSize;
160 PCHAR InData;
161
162 TI_DbgPrint(MAX_TRACE, ("Called. IPPacket (0x%X) NCE (0x%X) PathMTU (%d).\n",
163 IPPacket, NCE, PathMTU));
164
165 /* Make a smaller buffer if we will only send one fragment */
166 GetDataPtr( IPPacket->NdisPacket, 0, &InData, &InSize );
167 if( InSize < BufferSize ) BufferSize = InSize;
168
169 TI_DbgPrint(MAX_TRACE, ("Fragment buffer is %d bytes\n", BufferSize));
170
171 IFC = exAllocatePool(NonPagedPool, sizeof(IPFRAGMENT_CONTEXT));
172 if (IFC == NULL)
173 return STATUS_INSUFFICIENT_RESOURCES;
174
175 /* Allocate NDIS packet */
176 NdisStatus = AllocatePacketWithBuffer
177 ( &IFC->NdisPacket, NULL, BufferSize );
178
179 if( !NT_SUCCESS(NdisStatus) ) {
180 exFreePool( IFC );
181 return NdisStatus;
182 }
183
184 GetDataPtr( IFC->NdisPacket, 0, (PCHAR *)&Data, &InSize );
185
186 IFC->Header = ((PCHAR)Data) + MaxLLHeaderSize;
187 IFC->Datagram = IPPacket->NdisPacket;
188 IFC->DatagramData = ((PCHAR)IPPacket->Header) + IPPacket->HeaderSize;
189 IFC->HeaderSize = IPPacket->HeaderSize;
190 IFC->PathMTU = PathMTU;
191 IFC->NCE = NCE;
192 IFC->Position = 0;
193 IFC->BytesLeft = IPPacket->TotalSize - IPPacket->HeaderSize;
194 IFC->Data = (PVOID)((ULONG_PTR)IFC->Header + IPPacket->HeaderSize);
195 IFC->Complete = Complete;
196 IFC->Context = Context;
197
198 TI_DbgPrint(MID_TRACE,("Copying header from %x to %x (%d)\n",
199 IPPacket->Header, IFC->Header,
200 IPPacket->HeaderSize));
201
202 RtlCopyMemory( IFC->Header, IPPacket->Header, IPPacket->HeaderSize );
203
204 /* Prepare next fragment for transmission and send it */
205
206 PrepareNextFragment(IFC);
207 return IPSendFragment(IFC->NdisPacket, NCE, IFC);
208 }
209
210 NTSTATUS IPSendDatagram(PIP_PACKET IPPacket, PNEIGHBOR_CACHE_ENTRY NCE,
211 PIP_TRANSMIT_COMPLETE Complete, PVOID Context)
212 /*
213 * FUNCTION: Sends an IP datagram to a remote address
214 * ARGUMENTS:
215 * IPPacket = Pointer to an IP packet
216 * RCN = Pointer to route cache node
217 * RETURNS:
218 * Status of operation
219 * NOTES:
220 * This is the highest level IP send routine. It possibly breaks the packet
221 * into two or more fragments before passing it on to the next lower level
222 * send routine (IPSendFragment)
223 */
224 {
225 TI_DbgPrint(MAX_TRACE, ("Called. IPPacket (0x%X) NCE (0x%X)\n", IPPacket, NCE));
226
227 DISPLAY_IP_PACKET(IPPacket);
228 /*OskitDumpBuffer( IPPacket->Header, IPPacket->TotalSize );*/
229
230 /* Fetch path MTU now, because it may change */
231 TI_DbgPrint(MID_TRACE,("PathMTU: %d\n", NCE->Interface->MTU));
232
233 if ((IPPacket->Flags & IP_PACKET_FLAG_RAW) == 0) {
234 /* Calculate checksum of IP header */
235 TI_DbgPrint(MID_TRACE,("-> not IP_PACKET_FLAG_RAW\n"));
236 ((PIPv4_HEADER)IPPacket->Header)->Checksum = 0;
237
238 ((PIPv4_HEADER)IPPacket->Header)->Checksum = (USHORT)
239 IPv4Checksum(IPPacket->Header, IPPacket->HeaderSize, 0);
240 TI_DbgPrint(MID_TRACE,("IP Check: %x\n", ((PIPv4_HEADER)IPPacket->Header)->Checksum));
241
242 TI_DbgPrint(MAX_TRACE, ("Sending packet (length is %d).\n",
243 WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength)));
244 } else {
245 TI_DbgPrint(MAX_TRACE, ("Sending raw packet (flags are 0x%X).\n",
246 IPPacket->Flags));
247 }
248
249 return SendFragments(IPPacket, NCE, NCE->Interface->MTU,
250 Complete, Context);
251 }
252
253 /* EOF */