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