2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: transport/tcp/tcp.c
5 * PURPOSE: Transmission Control Protocol
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
17 BOOLEAN TCPInitialized = FALSE;
20 NTSTATUS TCPiAddHeaderIPv4(
21 PDATAGRAM_SEND_REQUEST SendRequest,
22 PIP_ADDRESS LocalAddress,
26 * FUNCTION: Adds an IPv4 and TCP header to an IP packet
28 * SendRequest = Pointer to send request
29 * LocalAddress = Pointer to our local address
30 * LocalPort = The port we send this segment from
31 * IPPacket = Pointer to IP packet
36 PIPv4_HEADER IPHeader;
37 PTCP_HEADER TCPHeader;
40 NDIS_STATUS NdisStatus;
41 PNDIS_BUFFER HeaderBuffer;
43 BufferSize = MaxLLHeaderSize + sizeof(IPv4_HEADER) + sizeof(TCP_HEADER);
44 Header = ExAllocatePool(NonPagedPool, BufferSize);
46 return STATUS_INSUFFICIENT_RESOURCES;
48 TI_DbgPrint(MAX_TRACE, ("Allocated %d bytes for headers at 0x%X.\n", BufferSize, Header));
50 /* Allocate NDIS buffer for maximum Link level, IP and TCP header */
51 NdisAllocateBuffer(&NdisStatus,
56 if (NdisStatus != NDIS_STATUS_SUCCESS) {
58 return STATUS_INSUFFICIENT_RESOURCES;
61 /* Chain header at front of NDIS packet */
62 NdisChainBufferAtFront(IPPacket->NdisPacket, HeaderBuffer);
64 IPPacket->Header = (PVOID)((ULONG_PTR)Header + MaxLLHeaderSize);
65 IPPacket->HeaderSize = 20;
67 /* Build IPv4 header */
68 IPHeader = (PIPv4_HEADER)IPPacket->Header;
69 /* Version = 4, Length = 5 DWORDs */
70 IPHeader->VerIHL = 0x45;
71 /* Normal Type-of-Service */
73 /* Length of header and data */
74 IPHeader->TotalLength = WH2N((USHORT)IPPacket->TotalSize);
77 /* One fragment at offset 0 */
78 IPHeader->FlagsFragOfs = 0;
79 /* Time-to-Live is 128 */
81 /* Transmission Control Protocol */
82 IPHeader->Protocol = IPPROTO_TCP;
83 /* Checksum is 0 (for later calculation of this) */
84 IPHeader->Checksum = 0;
86 IPHeader->SrcAddr = LocalAddress->Address.IPv4Address;
87 /* Destination address. FIXME: IPv4 only */
88 IPHeader->DstAddr = SendRequest->RemoteAddress->Address.IPv4Address;
90 /* Build TCP header */
91 TCPHeader = (PTCP_HEADER)((ULONG_PTR)IPHeader + sizeof(IPv4_HEADER));
92 /* Port values are already big-endian values */
93 TCPHeader->SourcePort = LocalPort;
94 TCPHeader->DestPort = SendRequest->RemotePort;
95 TCPHeader->SeqNum = 0;
96 TCPHeader->AckNum = 0;
97 TCPHeader->DataOfs = 0;
98 TCPHeader->Flags = SendRequest->Flags;
99 TCPHeader->Window = 0;
100 /* FIXME: Calculate TCP checksum and put it in TCP header */
101 TCPHeader->Checksum = 0;
102 TCPHeader->Urgent = 0;
104 return STATUS_SUCCESS;
108 NTSTATUS TCPiBuildPacket(
110 PIP_ADDRESS LocalAddress,
112 PIP_PACKET *IPPacket)
114 * FUNCTION: Builds a TCP packet
116 * Context = Pointer to context information (DATAGRAM_SEND_REQUEST)
117 * LocalAddress = Pointer to our local address
118 * LocalPort = The port we send this segment from
119 * IPPacket = Address of pointer to IP packet
121 * Status of operation
123 * The ProcotolContext field in the send request structure (pointed to
124 * by the Context field) contains a pointer to the CONNECTION_ENDPOINT
125 * structure for the connection
130 NDIS_STATUS NdisStatus;
131 PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context;
133 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
137 /* FIXME: Assumes IPv4*/
138 Packet = IPCreatePacket(IP_ADDRESS_V4);
140 return STATUS_INSUFFICIENT_RESOURCES;
142 Packet->TotalSize = sizeof(IPv4_HEADER) +
144 SendRequest->BufferSize;
146 /* Allocate NDIS packet */
147 NdisAllocatePacket(&NdisStatus, &Packet->NdisPacket, GlobalPacketPool);
148 if (NdisStatus != NDIS_STATUS_SUCCESS) {
149 (*Packet->Free)(Packet);
150 return STATUS_INSUFFICIENT_RESOURCES;
153 switch (SendRequest->RemoteAddress->Type) {
155 Status = TCPiAddHeaderIPv4(SendRequest, LocalAddress, LocalPort, Packet);
158 /* FIXME: Support IPv6 */
159 TI_DbgPrint(MIN_TRACE, ("IPv6 TCP segments are not supported.\n"));
161 Status = STATUS_UNSUCCESSFUL;
164 if (!NT_SUCCESS(Status)) {
165 TI_DbgPrint(MIN_TRACE, ("Cannot add TCP header. Status (0x%X)\n", Status));
166 NdisFreePacket(Packet->NdisPacket);
167 (*Packet->Free)(Packet);
171 /* Chain data after header */
172 NdisChainBufferAtBack(Packet->NdisPacket, SendRequest->Buffer);
174 //DISPLAY_IP_PACKET(Packet);
178 return STATUS_SUCCESS;
182 VOID TCPiSendRequestComplete(
187 * FUNCTION: Completion routine for datagram send requests
189 * Context = Pointer to context information (TCP_SEND_REQUEST)
190 * Status = Status of the request
191 * Count = Number of bytes sent or received
194 DATAGRAM_COMPLETION_ROUTINE Complete;
195 PVOID CompleteContext;
196 PTCP_SEND_REQUEST SendRequest = (PTCP_SEND_REQUEST)Context;
198 Complete = SendRequest->Complete;
199 CompleteContext = SendRequest->Context;
200 ExFreePool(SendRequest);
202 TI_DbgPrint(MAX_TRACE, ("Calling completion routine.\n"));
204 /* Call upper level completion routine */
205 (*Complete)(CompleteContext, Status, Count);
207 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
211 VOID TCPTimeout(VOID)
213 * FUNCTION: Transmission Control Protocol timeout handler
215 * This routine is called by IPTimeout to perform several
222 inline NTSTATUS TCPBuildSendRequest(
223 PTCP_SEND_REQUEST *SendRequest,
224 PDATAGRAM_SEND_REQUEST *DGSendRequest,
225 PCONNECTION_ENDPOINT Connection,
226 DATAGRAM_COMPLETION_ROUTINE Complete,
232 * FUNCTION: Allocates and intializes a TCP send request
234 * SendRequest = TCP send request
235 * DGSendRequest = Datagram send request (optional)
236 * Connection = Connection endpoint
237 * Complete = Completion routine
238 * Context = Pointer to context information
239 * Buffer = Pointer to NDIS buffer to send
240 * BufferSize = Size of Buffer
241 * Flags = Protocol specific flags
243 * Status of operation
246 PDATAGRAM_SEND_REQUEST DGSendReq;
249 Status = BuildTCPSendRequest(
254 if (!NT_SUCCESS(Status))
257 Status = BuildDatagramSendRequest(
258 &DGSendReq, /* Datagram send request */
259 Connection->RemoteAddress, /* Address of remote peer */
260 Connection->RemotePort, /* Port of remote peer */
262 BufferSize, /* Size of buffer */
263 TCPiSendRequestComplete, /* Completion function */
264 *SendRequest, /* Context for completion function */
265 TCPiBuildPacket, /* Packet build function */
266 Flags); /* Protocol specific flags */
267 if (!NT_SUCCESS(Status)) {
268 ExFreePool(*SendRequest);
273 *DGSendRequest = DGSendReq;
275 return STATUS_SUCCESS;
279 inline NTSTATUS TCPBuildAndTransmitSendRequest(
280 PCONNECTION_ENDPOINT Connection,
281 DATAGRAM_COMPLETION_ROUTINE Complete,
287 * FUNCTION: Allocates and intializes a TCP send request
289 * Connection = Connection endpoint
290 * Complete = Completion routine
291 * Context = Pointer to context information
292 * Buffer = Pointer to NDIS buffer to send
293 * BufferSize = Size of Buffer
294 * Flags = Protocol specific flags
296 * Status of operation
299 PDATAGRAM_SEND_REQUEST DGSendRequest;
300 PTCP_SEND_REQUEST TCPSendRequest;
303 Status = TCPBuildSendRequest(
306 Connection, /* Connection endpoint */
307 Complete, /* Completion routine */
308 Context, /* Completion routine context */
310 BufferSize, /* Size of buffer */
311 Flags); /* Protocol specific flags */
312 if (!NT_SUCCESS(Status))
316 Connection->AddressFile,
318 if (!NT_SUCCESS(Status)) {
319 ExFreePool(DGSendRequest);
320 ExFreePool(TCPSendRequest);
324 return STATUS_SUCCESS;
329 PTDI_REQUEST Request,
330 PTDI_CONNECTION_INFORMATION ConnInfo,
331 PTDI_CONNECTION_INFORMATION ReturnInfo)
333 * FUNCTION: Attempts to connect to a remote peer
335 * Request = Pointer to TDI request
336 * ConnInfo = Pointer to connection information
337 * ReturnInfo = Pointer to structure for return information
339 * Status of operation
341 * This is the high level interface for connecting to remote peers
344 PDATAGRAM_SEND_REQUEST DGSendRequest;
345 PTCP_SEND_REQUEST TCPSendRequest;
346 PCONNECTION_ENDPOINT Connection;
347 LARGE_INTEGER DueTime;
351 TI_DbgPrint(MID_TRACE, ("Called.\n"));
353 Connection = Request->Handle.ConnectionContext;
355 KeAcquireSpinLock(&Connection->Lock, &OldIrql);
357 if (Connection->State != ctClosed) {
358 /* The connection has already been opened so return success */
359 KeReleaseSpinLock(&Connection->Lock, OldIrql);
360 return STATUS_SUCCESS;
363 Connection->LocalAddress = Connection->AddressFile->ADE->Address;
364 Connection->LocalPort = Connection->AddressFile->Port;
366 Status = AddrBuildAddress(
367 (PTA_ADDRESS)ConnInfo->RemoteAddress,
368 &Connection->RemoteAddress,
369 &Connection->RemotePort);
370 if (!NT_SUCCESS(Status)) {
371 KeReleaseSpinLock(&Connection->Lock, OldIrql);
375 /* Issue SYN segment */
377 Status = TCPBuildAndTransmitSendRequest(
378 Connection, /* Connection endpoint */
379 Request->RequestNotifyObject, /* Completion routine */
380 Request->RequestContext, /* Completion routine context */
382 0, /* Size of buffer */
383 SRF_SYN); /* Protocol specific flags */
384 if (!NT_SUCCESS(Status)) {
385 KeReleaseSpinLock(&Connection->Lock, OldIrql);
386 ExFreePool(Connection->RemoteAddress);
390 KeReleaseSpinLock(&Connection->Lock, OldIrql);
392 TI_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X)\n", Status));
398 NTSTATUS TCPSendDatagram(
399 PTDI_REQUEST Request,
400 PTDI_CONNECTION_INFORMATION ConnInfo,
404 * FUNCTION: Sends TCP data to a remote address
406 * Request = Pointer to TDI request
407 * ConnInfo = Pointer to connection information
408 * Buffer = Pointer to NDIS buffer with data
409 * DataSize = Size in bytes of data to be sent
411 * Status of operation
414 return STATUS_SUCCESS;
419 PNET_TABLE_ENTRY NTE,
422 * FUNCTION: Receives and queues TCP data
424 * NTE = Pointer to net table entry which the packet was received on
425 * IPPacket = Pointer to an IP packet that was received
427 * This is the low level interface for receiving TCP data
430 PIPv4_HEADER IPv4Header;
431 PADDRESS_FILE AddrFile;
432 PTCP_HEADER TCPHeader;
433 PIP_ADDRESS DstAddress;
435 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
437 switch (IPPacket->Type) {
440 IPv4Header = IPPacket->Header;
441 DstAddress = &IPPacket->DstAddr;
446 TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 TCP data (%i bytes).\n",
447 IPPacket->TotalSize));
449 /* FIXME: IPv6 is not supported */
456 TCPHeader = (PTCP_HEADER)IPPacket->Data;
458 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
465 * FUNCTION: Initializes the TCP subsystem
467 * Status of operation
470 /* Register this protocol with IP layer */
471 IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
473 TCPInitialized = TRUE;
475 return STATUS_SUCCESS;
479 NTSTATUS TCPShutdown(
482 * FUNCTION: Shuts down the TCP subsystem
484 * Status of operation
488 return STATUS_SUCCESS;
490 /* Deregister this protocol with IP layer */
491 IPRegisterProtocol(IPPROTO_TCP, NULL);
493 TCPInitialized = FALSE;
495 return STATUS_SUCCESS;