Merge from amd64 branch:
[reactos.git] / reactos / lib / drivers / ip / transport / tcp / tcp.c
1 /*
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)
7 * Art Yerkes (arty@users.sf.net)
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 * arty 12/21/2004 Added accept
11 */
12
13 #include "precomp.h"
14
15 LONG TCP_IPIdentification = 0;
16 static BOOLEAN TCPInitialized = FALSE;
17 static NPAGED_LOOKASIDE_LIST TCPSegmentList;
18 PORT_SET TCPPorts;
19 CLIENT_DATA ClientInfo;
20
21 VOID HandleSignalledConnection(PCONNECTION_ENDPOINT Connection)
22 {
23 PTDI_BUCKET Bucket;
24 PLIST_ENTRY Entry;
25 NTSTATUS Status;
26 PIRP Irp;
27 PMDL Mdl;
28 ULONG SocketError = 0;
29 KIRQL OldIrql;
30 PTCP_COMPLETION_ROUTINE Complete;
31
32 if (ClientInfo.Unlocked)
33 LockObjectAtDpcLevel(Connection);
34
35 TI_DbgPrint(MID_TRACE,("Handling signalled state on %x (%x)\n",
36 Connection, Connection->SocketContext));
37
38 if( Connection->SignalState & SEL_FIN ) {
39 TI_DbgPrint(DEBUG_TCP, ("EOF From socket\n"));
40
41 /* If OskitTCP initiated the disconnect, try to read the socket error that occurred */
42 if (Connection->SocketContext)
43 SocketError = TCPTranslateError(OskitTCPGetSocketError(Connection->SocketContext));
44
45 /* Default to STATUS_CANCELLED if we initiated the disconnect or no socket error was reported */
46 if (!Connection->SocketContext || !SocketError)
47 SocketError = STATUS_CANCELLED;
48
49 while (!IsListEmpty(&Connection->ReceiveRequest))
50 {
51 Entry = RemoveHeadList( &Connection->ReceiveRequest );
52
53 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
54
55 Bucket->Status = SocketError;
56 Bucket->Information = 0;
57
58 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
59 }
60
61 while (!IsListEmpty(&Connection->SendRequest))
62 {
63 Entry = RemoveHeadList( &Connection->SendRequest );
64
65 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
66
67 Bucket->Status = SocketError;
68 Bucket->Information = 0;
69
70 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
71 }
72
73 while (!IsListEmpty(&Connection->ListenRequest))
74 {
75 Entry = RemoveHeadList( &Connection->ListenRequest );
76
77 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
78
79 Bucket->Status = SocketError;
80 Bucket->Information = 0;
81 DereferenceObject(Bucket->AssociatedEndpoint);
82
83 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
84 }
85
86 while (!IsListEmpty(&Connection->ConnectRequest))
87 {
88 Entry = RemoveHeadList( &Connection->ConnectRequest );
89
90 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
91
92 Bucket->Status = SocketError;
93 Bucket->Information = 0;
94
95 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
96 }
97
98 Connection->SignalState = SEL_FIN;
99 }
100
101 /* Things that can happen when we try the initial connection */
102 if( Connection->SignalState & SEL_CONNECT ) {
103 while (!IsListEmpty(&Connection->ConnectRequest)) {
104 Entry = RemoveHeadList( &Connection->ConnectRequest );
105
106 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
107
108 Bucket->Status = STATUS_SUCCESS;
109 Bucket->Information = 0;
110
111 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
112 }
113 }
114
115 if( Connection->SignalState & SEL_ACCEPT ) {
116 /* Handle readable on a listening socket --
117 * TODO: Implement filtering
118 */
119 TI_DbgPrint(DEBUG_TCP,("Accepting new connection on %x (Queue: %s)\n",
120 Connection,
121 IsListEmpty(&Connection->ListenRequest) ?
122 "empty" : "nonempty"));
123
124 while (!IsListEmpty(&Connection->ListenRequest)) {
125 PIO_STACK_LOCATION IrpSp;
126
127 Entry = RemoveHeadList( &Connection->ListenRequest );
128
129 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
130
131 Irp = Bucket->Request.RequestContext;
132 IrpSp = IoGetCurrentIrpStackLocation( Irp );
133
134 TI_DbgPrint(DEBUG_TCP,("Getting the socket\n"));
135
136 Status = TCPServiceListeningSocket
137 ( Connection->AddressFile->Listener,
138 Bucket->AssociatedEndpoint,
139 (PTDI_REQUEST_KERNEL)&IrpSp->Parameters );
140
141 TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n"));
142
143 if( Status == STATUS_PENDING ) {
144 InsertHeadList( &Connection->ListenRequest, &Bucket->Entry );
145 break;
146 } else {
147 Bucket->Status = Status;
148 Bucket->Information = 0;
149 DereferenceObject(Bucket->AssociatedEndpoint);
150
151 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
152 }
153 }
154 }
155
156 /* Things that happen after we're connected */
157 if( Connection->SignalState & SEL_READ ) {
158 TI_DbgPrint(DEBUG_TCP,("Readable: irp list %s\n",
159 IsListEmpty(&Connection->ReceiveRequest) ?
160 "empty" : "nonempty"));
161
162 while (!IsListEmpty(&Connection->ReceiveRequest)) {
163 OSK_UINT RecvLen = 0, Received = 0;
164 PVOID RecvBuffer = 0;
165
166 Entry = RemoveHeadList( &Connection->ReceiveRequest );
167
168 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
169
170 Irp = Bucket->Request.RequestContext;
171 Mdl = Irp->MdlAddress;
172
173 TI_DbgPrint(DEBUG_TCP,
174 ("Getting the user buffer from %x\n", Mdl));
175
176 NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
177
178 TI_DbgPrint(DEBUG_TCP,
179 ("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
180
181 TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
182 TI_DbgPrint
183 (DEBUG_TCP,
184 ("Connection->SocketContext: %x\n",
185 Connection->SocketContext));
186 TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer));
187
188 Status = TCPTranslateError
189 ( OskitTCPRecv( Connection->SocketContext,
190 RecvBuffer,
191 RecvLen,
192 &Received,
193 0 ) );
194
195 TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received));
196
197 if( Status == STATUS_PENDING ) {
198 InsertHeadList( &Connection->ReceiveRequest, &Bucket->Entry );
199 break;
200 } else {
201 TI_DbgPrint(DEBUG_TCP,
202 ("Completing Receive request: %x %x\n",
203 Bucket->Request, Status));
204
205 Bucket->Status = Status;
206 Bucket->Information = (Status == STATUS_SUCCESS) ? Received : 0;
207
208 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
209 }
210 }
211 }
212 if( Connection->SignalState & SEL_WRITE ) {
213 TI_DbgPrint(DEBUG_TCP,("Writeable: irp list %s\n",
214 IsListEmpty(&Connection->SendRequest) ?
215 "empty" : "nonempty"));
216
217 while (!IsListEmpty(&Connection->SendRequest)) {
218 OSK_UINT SendLen = 0, Sent = 0;
219 PVOID SendBuffer = 0;
220
221 Entry = RemoveHeadList( &Connection->SendRequest );
222
223 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
224
225 Irp = Bucket->Request.RequestContext;
226 Mdl = Irp->MdlAddress;
227
228 TI_DbgPrint(DEBUG_TCP,
229 ("Getting the user buffer from %x\n", Mdl));
230
231 NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
232
233 TI_DbgPrint(DEBUG_TCP,
234 ("Writing %d bytes to %x\n", SendLen, SendBuffer));
235
236 TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
237 TI_DbgPrint
238 (DEBUG_TCP,
239 ("Connection->SocketContext: %x\n",
240 Connection->SocketContext));
241
242 Status = TCPTranslateError
243 ( OskitTCPSend( Connection->SocketContext,
244 SendBuffer,
245 SendLen,
246 &Sent,
247 0 ) );
248
249 TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Sent));
250
251 if( Status == STATUS_PENDING ) {
252 InsertHeadList( &Connection->SendRequest, &Bucket->Entry );
253 break;
254 } else {
255 TI_DbgPrint(DEBUG_TCP,
256 ("Completing Send request: %x %x\n",
257 Bucket->Request, Status));
258
259 Bucket->Status = Status;
260 Bucket->Information = (Status == STATUS_SUCCESS) ? Sent : 0;
261
262 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
263 }
264 }
265 }
266
267 ReferenceObject(Connection);
268 if (ClientInfo.Unlocked)
269 {
270 UnlockObjectFromDpcLevel(Connection);
271 KeReleaseSpinLock(&ClientInfo.Lock, ClientInfo.OldIrql);
272 }
273 else
274 {
275 UnlockObject(Connection, Connection->OldIrql);
276 }
277
278 while ((Entry = ExInterlockedRemoveHeadList(&Connection->CompletionQueue,
279 &Connection->Lock)))
280 {
281 Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
282 Complete = Bucket->Request.RequestNotifyObject;
283
284 Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
285
286 ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
287 }
288
289 if (!ClientInfo.Unlocked)
290 {
291 LockObject(Connection, &OldIrql);
292 }
293 else
294 {
295 KeAcquireSpinLock(&ClientInfo.Lock, &ClientInfo.OldIrql);
296 }
297 DereferenceObject(Connection);
298
299 /* If the socket is dead, remove the reference we added for oskit */
300 if (Connection->SignalState & SEL_FIN)
301 DereferenceObject(Connection);
302 }
303
304 VOID ConnectionFree(PVOID Object) {
305 PCONNECTION_ENDPOINT Connection = Object;
306 KIRQL OldIrql;
307
308 TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n"));
309
310 TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
311 RemoveEntryList(&Connection->ListEntry);
312 TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
313
314 ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
315 }
316
317 PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) {
318 PCONNECTION_ENDPOINT Connection =
319 ExAllocatePoolWithTag(NonPagedPool, sizeof(CONNECTION_ENDPOINT),
320 CONN_ENDPT_TAG);
321 if (!Connection)
322 return Connection;
323
324 TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
325
326 RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
327
328 /* Initialize spin lock that protects the connection endpoint file object */
329 KeInitializeSpinLock(&Connection->Lock);
330 InitializeListHead(&Connection->ConnectRequest);
331 InitializeListHead(&Connection->ListenRequest);
332 InitializeListHead(&Connection->ReceiveRequest);
333 InitializeListHead(&Connection->SendRequest);
334 InitializeListHead(&Connection->CompletionQueue);
335
336 /* Save client context pointer */
337 Connection->ClientContext = ClientContext;
338
339 /* Add an extra reference for oskit */
340 Connection->RefCount = 2;
341 Connection->Free = ConnectionFree;
342
343 /* Add connection endpoint to global list */
344 ExInterlockedInsertTailList(&ConnectionEndpointListHead,
345 &Connection->ListEntry,
346 &ConnectionEndpointListLock);
347
348 return Connection;
349 }
350
351 NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
352 UINT Family, UINT Type, UINT Proto ) {
353 NTSTATUS Status;
354 KIRQL OldIrql;
355
356 LockObject(Connection, &OldIrql);
357
358 TI_DbgPrint(DEBUG_TCP,("Called: Connection %x, Family %d, Type %d, "
359 "Proto %d\n",
360 Connection, Family, Type, Proto));
361
362 Status = TCPTranslateError( OskitTCPSocket( Connection,
363 &Connection->SocketContext,
364 Family,
365 Type,
366 Proto ) );
367
368 ASSERT_KM_POINTER(Connection->SocketContext);
369
370 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
371 Connection->SocketContext));
372
373 UnlockObject(Connection, OldIrql);
374
375 return Status;
376 }
377
378 VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
379 /*
380 * FUNCTION: Receives and queues TCP data
381 * ARGUMENTS:
382 * IPPacket = Pointer to an IP packet that was received
383 * NOTES:
384 * This is the low level interface for receiving TCP data
385 */
386 {
387 KIRQL OldIrql;
388
389 TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to oskit\n",
390 IPPacket->TotalSize,
391 IPPacket->HeaderSize));
392
393 KeAcquireSpinLock(&ClientInfo.Lock, &OldIrql);
394 ClientInfo.Unlocked = TRUE;
395 ClientInfo.OldIrql = OldIrql;
396
397 OskitTCPReceiveDatagram( IPPacket->Header,
398 IPPacket->TotalSize,
399 IPPacket->HeaderSize );
400
401 ClientInfo.Unlocked = FALSE;
402 KeReleaseSpinLock(&ClientInfo.Lock, OldIrql);
403 }
404
405 /* event.c */
406 int TCPSocketState( void *ClientData,
407 void *WhichSocket,
408 void *WhichConnection,
409 OSK_UINT NewState );
410
411 int TCPPacketSend( void *ClientData,
412 OSK_PCHAR Data,
413 OSK_UINT Len );
414
415 POSK_IFADDR TCPFindInterface( void *ClientData,
416 OSK_UINT AddrType,
417 OSK_UINT FindType,
418 OSK_SOCKADDR *ReqAddr );
419
420 NTSTATUS TCPMemStartup( void );
421 void *TCPMalloc( void *ClientData,
422 OSK_UINT bytes, OSK_PCHAR file, OSK_UINT line );
423 void TCPFree( void *ClientData,
424 void *data, OSK_PCHAR file, OSK_UINT line );
425 void TCPMemShutdown( void );
426
427 OSKITTCP_EVENT_HANDLERS EventHandlers = {
428 NULL, /* Client Data */
429 TCPSocketState, /* SocketState */
430 TCPPacketSend, /* PacketSend */
431 TCPFindInterface, /* FindInterface */
432 TCPMalloc, /* Malloc */
433 TCPFree, /* Free */
434 NULL, /* Sleep */
435 NULL, /* Wakeup */
436 };
437
438 static KEVENT TimerLoopEvent;
439 static HANDLE TimerThreadHandle;
440
441 /*
442 * We are running 2 timers here, one with a 200ms interval (fast) and the other
443 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
444 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
445 * "slow" events at 500 and 1000.
446 */
447 static VOID NTAPI
448 TimerThread(PVOID Context)
449 {
450 LARGE_INTEGER Timeout;
451 NTSTATUS Status;
452 unsigned Current, NextFast, NextSlow, Next;
453
454 Current = 0;
455 Next = 0;
456 NextFast = 0;
457 NextSlow = 0;
458 while ( 1 ) {
459 if (Next == NextFast) {
460 NextFast += 2;
461 }
462 if (Next == NextSlow) {
463 NextSlow += 5;
464 }
465 Next = min(NextFast, NextSlow);
466 Timeout.QuadPart = (LONGLONG) (Next - Current) * -1000000; /* 100 ms */
467 Status = KeWaitForSingleObject(&TimerLoopEvent, Executive, KernelMode,
468 FALSE, &Timeout);
469 if (Status != STATUS_TIMEOUT) {
470 PsTerminateSystemThread(Status);
471 }
472
473 TimerOskitTCP( Next == NextFast, Next == NextSlow );
474
475 Current = Next;
476 if (10 <= Current) {
477 Current = 0;
478 Next = 0;
479 NextFast = 0;
480 NextSlow = 0;
481 }
482 }
483 }
484
485 static VOID
486 StartTimer(VOID)
487 {
488 KeInitializeEvent(&TimerLoopEvent, NotificationEvent, FALSE);
489 PsCreateSystemThread(&TimerThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0,
490 TimerThread, NULL);
491 }
492
493 NTSTATUS TCPStartup(VOID)
494 /*
495 * FUNCTION: Initializes the TCP subsystem
496 * RETURNS:
497 * Status of operation
498 */
499 {
500 NTSTATUS Status;
501
502 Status = TCPMemStartup();
503 if ( ! NT_SUCCESS(Status) ) {
504 return Status;
505 }
506
507 Status = PortsStartup( &TCPPorts, 1, 0xfffe );
508 if( !NT_SUCCESS(Status) ) {
509 TCPMemShutdown();
510 return Status;
511 }
512
513 KeInitializeSpinLock(&ClientInfo.Lock);
514 ClientInfo.Unlocked = FALSE;
515
516 RegisterOskitTCPEventHandlers( &EventHandlers );
517 InitOskitTCP();
518
519 /* Register this protocol with IP layer */
520 IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
521
522 ExInitializeNPagedLookasideList(
523 &TCPSegmentList, /* Lookaside list */
524 NULL, /* Allocate routine */
525 NULL, /* Free routine */
526 0, /* Flags */
527 sizeof(TCP_SEGMENT), /* Size of each entry */
528 'SPCT', /* Tag */
529 0); /* Depth */
530
531 StartTimer();
532
533 TCPInitialized = TRUE;
534
535 return STATUS_SUCCESS;
536 }
537
538
539 NTSTATUS TCPShutdown(VOID)
540 /*
541 * FUNCTION: Shuts down the TCP subsystem
542 * RETURNS:
543 * Status of operation
544 */
545 {
546 LARGE_INTEGER WaitForThread;
547
548 if (!TCPInitialized)
549 return STATUS_SUCCESS;
550
551 WaitForThread.QuadPart = -2500000; /* 250 ms */
552 KeSetEvent(&TimerLoopEvent, IO_NO_INCREMENT, FALSE);
553 ZwWaitForSingleObject(TimerThreadHandle, FALSE, &WaitForThread);
554
555 /* Deregister this protocol with IP layer */
556 IPRegisterProtocol(IPPROTO_TCP, NULL);
557
558 ExDeleteNPagedLookasideList(&TCPSegmentList);
559
560 TCPInitialized = FALSE;
561
562 DeinitOskitTCP();
563
564 PortsShutdown( &TCPPorts );
565
566 TCPMemShutdown();
567
568 return STATUS_SUCCESS;
569 }
570
571 NTSTATUS TCPTranslateError( int OskitError ) {
572 NTSTATUS Status;
573
574 switch( OskitError ) {
575 case 0: Status = STATUS_SUCCESS; break;
576 case OSK_EADDRNOTAVAIL: Status = STATUS_INVALID_ADDRESS; break;
577 case OSK_EAFNOSUPPORT: Status = STATUS_INVALID_CONNECTION; break;
578 case OSK_ECONNREFUSED: Status = STATUS_REMOTE_NOT_LISTENING; break;
579 case OSK_ECONNRESET:
580 case OSK_ECONNABORTED: Status = STATUS_REMOTE_DISCONNECT; break;
581 case OSK_EWOULDBLOCK:
582 case OSK_EINPROGRESS: Status = STATUS_PENDING; break;
583 case OSK_EINVAL: Status = STATUS_INVALID_PARAMETER; break;
584 case OSK_ENOMEM:
585 case OSK_ENOBUFS: Status = STATUS_INSUFFICIENT_RESOURCES; break;
586 case OSK_ESHUTDOWN: Status = STATUS_FILE_CLOSED; break;
587 case OSK_EMSGSIZE: Status = STATUS_BUFFER_TOO_SMALL; break;
588 case OSK_ETIMEDOUT: Status = STATUS_TIMEOUT; break;
589 case OSK_ENETUNREACH: Status = STATUS_NETWORK_UNREACHABLE; break;
590 case OSK_EFAULT: Status = STATUS_ACCESS_VIOLATION; break;
591 default:
592 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError);
593 Status = STATUS_INVALID_CONNECTION;
594 break;
595 }
596
597 TI_DbgPrint(DEBUG_TCP,("Error %d -> %x\n", OskitError, Status));
598 return Status;
599 }
600
601 NTSTATUS TCPConnect
602 ( PCONNECTION_ENDPOINT Connection,
603 PTDI_CONNECTION_INFORMATION ConnInfo,
604 PTDI_CONNECTION_INFORMATION ReturnInfo,
605 PTCP_COMPLETION_ROUTINE Complete,
606 PVOID Context ) {
607 NTSTATUS Status;
608 SOCKADDR_IN AddressToConnect = { 0 }, AddressToBind = { 0 };
609 IP_ADDRESS RemoteAddress;
610 USHORT RemotePort;
611 PTDI_BUCKET Bucket;
612 PNEIGHBOR_CACHE_ENTRY NCE;
613 KIRQL OldIrql;
614
615 TI_DbgPrint(DEBUG_TCP,("TCPConnect: Called\n"));
616
617 Status = AddrBuildAddress
618 ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress,
619 &RemoteAddress,
620 &RemotePort);
621
622 if (!NT_SUCCESS(Status)) {
623 TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n"));
624 return Status;
625 }
626
627 /* Freed in TCPSocketState */
628 TI_DbgPrint(DEBUG_TCP,
629 ("Connecting to address %x:%x\n",
630 RemoteAddress.Address.IPv4Address,
631 RemotePort));
632
633 AddressToConnect.sin_family = AF_INET;
634 AddressToBind = AddressToConnect;
635
636 LockObject(Connection, &OldIrql);
637
638 if (!Connection->AddressFile)
639 {
640 UnlockObject(Connection, OldIrql);
641 return STATUS_INVALID_PARAMETER;
642 }
643
644 if (AddrIsUnspecified(&Connection->AddressFile->Address))
645 {
646 if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
647 {
648 UnlockObject(Connection, OldIrql);
649 return STATUS_NETWORK_UNREACHABLE;
650 }
651
652 AddressToBind.sin_addr.s_addr = NCE->Interface->Unicast.Address.IPv4Address;
653 }
654 else
655 {
656 AddressToBind.sin_addr.s_addr = Connection->AddressFile->Address.Address.IPv4Address;
657 }
658
659 Status = TCPTranslateError
660 ( OskitTCPBind( Connection->SocketContext,
661 &AddressToBind,
662 sizeof(AddressToBind) ) );
663
664 if (NT_SUCCESS(Status)) {
665 memcpy( &AddressToConnect.sin_addr,
666 &RemoteAddress.Address.IPv4Address,
667 sizeof(AddressToConnect.sin_addr) );
668 AddressToConnect.sin_port = RemotePort;
669
670 Status = TCPTranslateError
671 ( OskitTCPConnect( Connection->SocketContext,
672 &AddressToConnect,
673 sizeof(AddressToConnect) ) );
674
675 if (Status == STATUS_PENDING)
676 {
677 Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
678 if( !Bucket )
679 {
680 UnlockObject(Connection, OldIrql);
681 return STATUS_NO_MEMORY;
682 }
683
684 Bucket->Request.RequestNotifyObject = (PVOID)Complete;
685 Bucket->Request.RequestContext = Context;
686
687 InsertTailList( &Connection->ConnectRequest, &Bucket->Entry );
688 }
689 }
690
691 UnlockObject(Connection, OldIrql);
692
693 return Status;
694 }
695
696 NTSTATUS TCPDisconnect
697 ( PCONNECTION_ENDPOINT Connection,
698 UINT Flags,
699 PTDI_CONNECTION_INFORMATION ConnInfo,
700 PTDI_CONNECTION_INFORMATION ReturnInfo,
701 PTCP_COMPLETION_ROUTINE Complete,
702 PVOID Context ) {
703 NTSTATUS Status = STATUS_INVALID_PARAMETER;
704 KIRQL OldIrql;
705
706 TI_DbgPrint(DEBUG_TCP,("started\n"));
707
708 LockObject(Connection, &OldIrql);
709
710 if (Flags & TDI_DISCONNECT_RELEASE)
711 Status = TCPTranslateError(OskitTCPDisconnect(Connection->SocketContext));
712
713 if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
714 Status = TCPTranslateError(OskitTCPShutdown(Connection->SocketContext, FWRITE | FREAD));
715
716 UnlockObject(Connection, OldIrql);
717
718 TI_DbgPrint(DEBUG_TCP,("finished %x\n", Status));
719
720 return Status;
721 }
722
723 NTSTATUS TCPClose
724 ( PCONNECTION_ENDPOINT Connection )
725 {
726 KIRQL OldIrql;
727 NTSTATUS Status;
728 PVOID Socket;
729
730 /* We don't rely on SocketContext == NULL for socket
731 * closure anymore but we still need it to determine
732 * if we caused the closure
733 */
734 LockObject(Connection, &OldIrql);
735 Socket = Connection->SocketContext;
736 Connection->SocketContext = NULL;
737
738 /* We need to close here otherwise oskit will never indicate
739 * SEL_FIN and we will never fully close the connection
740 */
741 Status = TCPTranslateError( OskitTCPClose( Socket ) );
742
743 if (!NT_SUCCESS(Status))
744 {
745 Connection->SocketContext = Socket;
746 UnlockObject(Connection, OldIrql);
747 return Status;
748 }
749
750 if (Connection->AddressFile)
751 DereferenceObject(Connection->AddressFile);
752
753 UnlockObject(Connection, OldIrql);
754
755 DereferenceObject(Connection);
756
757 return Status;
758 }
759
760 NTSTATUS TCPReceiveData
761 ( PCONNECTION_ENDPOINT Connection,
762 PNDIS_BUFFER Buffer,
763 ULONG ReceiveLength,
764 PULONG BytesReceived,
765 ULONG ReceiveFlags,
766 PTCP_COMPLETION_ROUTINE Complete,
767 PVOID Context ) {
768 PVOID DataBuffer;
769 UINT DataLen, Received = 0;
770 NTSTATUS Status;
771 PTDI_BUCKET Bucket;
772 KIRQL OldIrql;
773
774 TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
775 ReceiveLength, Connection->SocketContext));
776
777 NdisQueryBuffer( Buffer, &DataBuffer, &DataLen );
778
779 TI_DbgPrint(DEBUG_TCP,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen));
780
781 LockObject(Connection, &OldIrql);
782
783 Status = TCPTranslateError
784 ( OskitTCPRecv
785 ( Connection->SocketContext,
786 DataBuffer,
787 DataLen,
788 &Received,
789 ReceiveFlags ) );
790
791 TI_DbgPrint(DEBUG_TCP,("OskitTCPReceive: %x, %d\n", Status, Received));
792
793 /* Keep this request around ... there was no data yet */
794 if( Status == STATUS_PENDING ) {
795 /* Freed in TCPSocketState */
796 Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
797 if( !Bucket ) {
798 TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
799 UnlockObject(Connection, OldIrql);
800 return STATUS_NO_MEMORY;
801 }
802
803 Bucket->Request.RequestNotifyObject = Complete;
804 Bucket->Request.RequestContext = Context;
805 *BytesReceived = 0;
806
807 InsertTailList( &Connection->ReceiveRequest, &Bucket->Entry );
808 TI_DbgPrint(DEBUG_TCP,("Queued read irp\n"));
809 } else {
810 TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Received));
811 *BytesReceived = Received;
812 }
813
814 UnlockObject(Connection, OldIrql);
815
816 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
817
818 return Status;
819 }
820
821 NTSTATUS TCPSendData
822 ( PCONNECTION_ENDPOINT Connection,
823 PCHAR BufferData,
824 ULONG SendLength,
825 PULONG BytesSent,
826 ULONG Flags,
827 PTCP_COMPLETION_ROUTINE Complete,
828 PVOID Context ) {
829 UINT Sent = 0;
830 NTSTATUS Status;
831 PTDI_BUCKET Bucket;
832 KIRQL OldIrql;
833
834 LockObject(Connection, &OldIrql);
835
836 TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
837 SendLength, Connection->SocketContext));
838
839 TI_DbgPrint(DEBUG_TCP,("Connection = %x\n", Connection));
840 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext = %x\n",
841 Connection->SocketContext));
842
843 Status = TCPTranslateError
844 ( OskitTCPSend( Connection->SocketContext,
845 (OSK_PCHAR)BufferData, SendLength,
846 &Sent, 0 ) );
847
848 TI_DbgPrint(DEBUG_TCP,("OskitTCPSend: %x, %d\n", Status, Sent));
849
850 /* Keep this request around ... there was no data yet */
851 if( Status == STATUS_PENDING ) {
852 /* Freed in TCPSocketState */
853 Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
854 if( !Bucket ) {
855 UnlockObject(Connection, OldIrql);
856 TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
857 return STATUS_NO_MEMORY;
858 }
859
860 Bucket->Request.RequestNotifyObject = Complete;
861 Bucket->Request.RequestContext = Context;
862 *BytesSent = 0;
863
864 InsertTailList( &Connection->SendRequest, &Bucket->Entry );
865 TI_DbgPrint(DEBUG_TCP,("Queued write irp\n"));
866 } else {
867 TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Sent));
868 *BytesSent = Sent;
869 }
870
871 UnlockObject(Connection, OldIrql);
872
873 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
874
875 return Status;
876 }
877
878 UINT TCPAllocatePort( UINT HintPort ) {
879 if( HintPort ) {
880 if( AllocatePort( &TCPPorts, HintPort ) ) return HintPort;
881 else {
882 TI_DbgPrint
883 (MID_TRACE,("We got a hint port but couldn't allocate it\n"));
884 return (UINT)-1;
885 }
886 } else return AllocatePortFromRange( &TCPPorts, 1024, 5000 );
887 }
888
889 VOID TCPFreePort( UINT Port ) {
890 DeallocatePort( &TCPPorts, Port );
891 }
892
893 NTSTATUS TCPGetSockAddress
894 ( PCONNECTION_ENDPOINT Connection,
895 PTRANSPORT_ADDRESS Address,
896 BOOLEAN GetRemote ) {
897 OSK_UINT LocalAddress, RemoteAddress;
898 OSK_UI16 LocalPort, RemotePort;
899 PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
900 NTSTATUS Status;
901 KIRQL OldIrql;
902
903 LockObject(Connection, &OldIrql);
904
905 Status = TCPTranslateError(OskitTCPGetAddress(Connection->SocketContext,
906 &LocalAddress, &LocalPort,
907 &RemoteAddress, &RemotePort));
908
909 UnlockObject(Connection, OldIrql);
910
911 if (!NT_SUCCESS(Status))
912 return Status;
913
914 AddressIP->TAAddressCount = 1;
915 AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
916 AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
917 AddressIP->Address[0].Address[0].sin_port = GetRemote ? RemotePort : LocalPort;
918 AddressIP->Address[0].Address[0].in_addr = GetRemote ? RemoteAddress : LocalAddress;
919
920 return Status;
921 }
922
923 BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp ) {
924 PLIST_ENTRY Entry;
925 PLIST_ENTRY ListHead[4];
926 KIRQL OldIrql;
927 PTDI_BUCKET Bucket;
928 UINT i = 0;
929 BOOLEAN Found = FALSE;
930
931 ListHead[0] = &Endpoint->SendRequest;
932 ListHead[1] = &Endpoint->ReceiveRequest;
933 ListHead[2] = &Endpoint->ConnectRequest;
934 ListHead[3] = &Endpoint->ListenRequest;
935
936 LockObject(Endpoint, &OldIrql);
937
938 for( i = 0; i < 4; i++ )
939 {
940 for( Entry = ListHead[i]->Flink;
941 Entry != ListHead[i];
942 Entry = Entry->Flink )
943 {
944 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
945 if( Bucket->Request.RequestContext == Irp )
946 {
947 RemoveEntryList( &Bucket->Entry );
948 ExFreePoolWithTag( Bucket, TDI_BUCKET_TAG );
949 Found = TRUE;
950 break;
951 }
952 }
953 }
954
955 UnlockObject(Endpoint, OldIrql);
956
957 return Found;
958 }
959
960 /* EOF */