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 IFC
->Status
= NdisStatus
;
38 KeSetEvent(&IFC
->Event
, 0, FALSE
);
41 NTSTATUS
IPSendFragment(
42 PNDIS_PACKET NdisPacket
,
43 PNEIGHBOR_CACHE_ENTRY NCE
,
44 PIPFRAGMENT_CONTEXT IFC
)
46 * FUNCTION: Sends an IP datagram fragment to a neighbor
48 * NdisPacket = Pointer to an NDIS packet containing fragment
49 * NCE = Pointer to NCE for first hop to destination
53 * Lowest level IP send routine
56 TI_DbgPrint(MAX_TRACE
, ("Called. NdisPacket (0x%X) NCE (0x%X).\n", NdisPacket
, NCE
));
58 TI_DbgPrint(MAX_TRACE
, ("NCE->State = %d.\n", NCE
->State
));
59 return NBQueuePacket(NCE
, NdisPacket
, IPSendComplete
, IFC
);
62 BOOLEAN
PrepareNextFragment(
63 PIPFRAGMENT_CONTEXT IFC
)
65 * FUNCTION: Prepares the next fragment of an IP datagram for transmission
67 * IFC = Pointer to IP fragment context
69 * TRUE if a fragment was prepared for transmission, FALSE if
70 * there are no more fragments to send
76 BOOLEAN MoreFragments
;
79 TI_DbgPrint(MAX_TRACE
, ("Called. IFC (0x%X)\n", IFC
));
81 if (IFC
->BytesLeft
> 0) {
83 TI_DbgPrint(MAX_TRACE
, ("Preparing 1 fragment.\n"));
85 MaxData
= IFC
->PathMTU
- IFC
->HeaderSize
;
86 /* Make fragment a multiplum of 64bit */
87 MaxData
-= MaxData
% 8;
88 if (IFC
->BytesLeft
> MaxData
) {
92 DataSize
= IFC
->BytesLeft
;
93 MoreFragments
= FALSE
;
96 TI_DbgPrint(MID_TRACE
,("Copying data from %x to %x (%d)\n",
97 IFC
->DatagramData
, IFC
->Data
, DataSize
));
99 RtlCopyMemory(IFC
->Data
, IFC
->DatagramData
, DataSize
); // SAFE
101 /* Fragment offset is in 8 byte blocks */
102 FragOfs
= (USHORT
)(IFC
->Position
/ 8);
105 FragOfs
|= IPv4_MF_MASK
;
107 FragOfs
&= ~IPv4_MF_MASK
;
109 Header
= IFC
->Header
;
110 Header
->FlagsFragOfs
= WH2N(FragOfs
);
111 Header
->TotalLength
= WH2N((USHORT
)(DataSize
+ IFC
->HeaderSize
));
113 /* FIXME: Handle options */
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
));
120 /* Update pointers */
121 IFC
->DatagramData
= (PVOID
)((ULONG_PTR
)IFC
->DatagramData
+ DataSize
);
122 IFC
->Position
+= DataSize
;
123 IFC
->BytesLeft
-= DataSize
;
127 TI_DbgPrint(MAX_TRACE
, ("No more fragments.\n"));
132 NTSTATUS
SendFragments(
134 PNEIGHBOR_CACHE_ENTRY NCE
,
137 * FUNCTION: Fragments and sends the first fragment of an IP datagram
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
143 * Status of operation
145 * IP datagram is larger than PathMTU when this is called
148 PIPFRAGMENT_CONTEXT IFC
;
149 NDIS_STATUS NdisStatus
;
151 UINT BufferSize
= PathMTU
, InSize
;
154 TI_DbgPrint(MAX_TRACE
, ("Called. IPPacket (0x%X) NCE (0x%X) PathMTU (%d).\n",
155 IPPacket
, NCE
, PathMTU
));
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
;
161 TI_DbgPrint(MAX_TRACE
, ("Fragment buffer is %d bytes\n", BufferSize
));
163 IFC
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(IPFRAGMENT_CONTEXT
), IFC_TAG
);
166 IPPacket
->Free(IPPacket
);
167 return STATUS_INSUFFICIENT_RESOURCES
;
170 /* Allocate NDIS packet */
171 NdisStatus
= AllocatePacketWithBuffer
172 ( &IFC
->NdisPacket
, NULL
, BufferSize
);
174 if( !NT_SUCCESS(NdisStatus
) ) {
175 IPPacket
->Free(IPPacket
);
176 ExFreePoolWithTag( IFC
, IFC_TAG
);
180 GetDataPtr( IFC
->NdisPacket
, 0, (PCHAR
*)&Data
, &InSize
);
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
;
189 IFC
->BytesLeft
= IPPacket
->TotalSize
- IPPacket
->HeaderSize
;
190 IFC
->Data
= (PVOID
)((ULONG_PTR
)IFC
->Header
+ IPPacket
->HeaderSize
);
191 KeInitializeEvent(&IFC
->Event
, NotificationEvent
, FALSE
);
193 TI_DbgPrint(MID_TRACE
,("Copying header from %x to %x (%d)\n",
194 IPPacket
->Header
, IFC
->Header
,
195 IPPacket
->HeaderSize
));
197 RtlCopyMemory( IFC
->Header
, IPPacket
->Header
, IPPacket
->HeaderSize
);
199 while (PrepareNextFragment(IFC
))
201 NdisStatus
= IPSendFragment(IFC
->NdisPacket
, NCE
, IFC
);
202 if (NT_SUCCESS(NdisStatus
))
204 KeWaitForSingleObject(&IFC
->Event
,
209 NdisStatus
= IFC
->Status
;
212 if (!NT_SUCCESS(NdisStatus
))
216 FreeNdisPacket(IFC
->NdisPacket
);
217 ExFreePoolWithTag(IFC
, IFC_TAG
);
218 IPPacket
->Free(IPPacket
);
223 NTSTATUS
IPSendDatagram(PIP_PACKET IPPacket
, PNEIGHBOR_CACHE_ENTRY NCE
)
225 * FUNCTION: Sends an IP datagram to a remote address
227 * IPPacket = Pointer to an IP packet
228 * RCN = Pointer to route cache node
230 * Status of operation
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)
237 TI_DbgPrint(MAX_TRACE
, ("Called. IPPacket (0x%X) NCE (0x%X)\n", IPPacket
, NCE
));
239 DISPLAY_IP_PACKET(IPPacket
);
241 /* Fetch path MTU now, because it may change */
242 TI_DbgPrint(MID_TRACE
,("PathMTU: %d\n", NCE
->Interface
->MTU
));
244 return SendFragments(IPPacket
, NCE
, NCE
->Interface
->MTU
);