9b0beebbb0abc54db4b22fb40a3a89b22997575c
[reactos.git] / drivers / network / afd / afd / connect.c
1 /* $Id$
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/net/afd/afd/connect.c
5 * PURPOSE: Ancillary functions driver
6 * PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
7 * UPDATE HISTORY:
8 * 20040708 Created
9 */
10 #include "afd.h"
11 #include "tdi_proto.h"
12 #include "tdiconn.h"
13 #include "debug.h"
14
15 NTSTATUS WarmSocketForConnection( PAFD_FCB FCB ) {
16 NTSTATUS Status;
17
18 if( !FCB->TdiDeviceName.Length || !FCB->TdiDeviceName.Buffer ) {
19 AFD_DbgPrint(MID_TRACE,("Null Device\n"));
20 return STATUS_NO_SUCH_DEVICE;
21 }
22
23 Status = TdiOpenConnectionEndpointFile(&FCB->TdiDeviceName,
24 &FCB->Connection.Handle,
25 &FCB->Connection.Object );
26
27 if( NT_SUCCESS(Status) ) {
28 Status = TdiAssociateAddressFile( FCB->AddressFile.Handle,
29 FCB->Connection.Object );
30 }
31
32 return Status;
33 }
34
35 NTSTATUS MakeSocketIntoConnection( PAFD_FCB FCB ) {
36 NTSTATUS Status;
37
38 /* Allocate the receive area and start receiving */
39 FCB->Recv.Window =
40 ExAllocatePool( PagedPool, FCB->Recv.Size );
41
42 if( !FCB->Recv.Window ) return STATUS_NO_MEMORY;
43
44 FCB->Send.Window =
45 ExAllocatePool( PagedPool, FCB->Send.Size );
46
47 if( !FCB->Send.Window ) {
48 ExFreePool( FCB->Recv.Window );
49 FCB->Recv.Window = NULL;
50 return STATUS_NO_MEMORY;
51 }
52
53 FCB->State = SOCKET_STATE_CONNECTED;
54
55 Status = TdiReceive( &FCB->ReceiveIrp.InFlightRequest,
56 FCB->Connection.Object,
57 TDI_RECEIVE_NORMAL,
58 FCB->Recv.Window,
59 FCB->Recv.Size,
60 &FCB->ReceiveIrp.Iosb,
61 ReceiveComplete,
62 FCB );
63
64 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
65
66 FCB->PollState |= AFD_EVENT_CONNECT | AFD_EVENT_SEND;
67 PollReeval( FCB->DeviceExt, FCB->FileObject );
68
69 return Status;
70 }
71
72 static NTSTATUS NTAPI StreamSocketConnectComplete
73 ( PDEVICE_OBJECT DeviceObject,
74 PIRP Irp,
75 PVOID Context ) {
76 NTSTATUS Status = Irp->IoStatus.Status;
77 PAFD_FCB FCB = (PAFD_FCB)Context;
78 PLIST_ENTRY NextIrpEntry;
79 PIRP NextIrp;
80
81 AFD_DbgPrint(MID_TRACE,("Called: FCB %x, FO %x\n",
82 Context, FCB->FileObject));
83
84 /* I was wrong about this before as we can have pending writes to a not
85 * yet connected socket */
86 if( !SocketAcquireStateLock( FCB ) )
87 return STATUS_FILE_CLOSED;
88
89 AFD_DbgPrint(MID_TRACE,("Irp->IoStatus.Status = %x\n",
90 Irp->IoStatus.Status));
91
92 FCB->ConnectIrp.InFlightRequest = NULL;
93
94 if( FCB->State == SOCKET_STATE_CLOSED ) {
95 /* Cleanup our IRP queue because the FCB is being destroyed */
96 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) {
97 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]);
98 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
99 NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
100 NextIrp->IoStatus.Information = 0;
101 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
102 (void)IoSetCancelRoutine(NextIrp, NULL);
103 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
104 }
105 SocketStateUnlock( FCB );
106 return STATUS_FILE_CLOSED;
107 }
108
109 if( !NT_SUCCESS(Irp->IoStatus.Status) ) {
110 FCB->PollState |= AFD_EVENT_CONNECT_FAIL;
111 AFD_DbgPrint(MID_TRACE,("Going to bound state\n"));
112 FCB->State = SOCKET_STATE_BOUND;
113 PollReeval( FCB->DeviceExt, FCB->FileObject );
114 }
115
116 /* Succeed pending irps on the FUNCTION_CONNECT list */
117 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) {
118 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]);
119 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
120 AFD_DbgPrint(MID_TRACE,("Completing connect %x\n", NextIrp));
121 NextIrp->IoStatus.Status = Status;
122 NextIrp->IoStatus.Information = 0;
123 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
124 (void)IoSetCancelRoutine(NextIrp, NULL);
125 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
126 }
127
128 if( NT_SUCCESS(Status) ) {
129 Status = MakeSocketIntoConnection( FCB );
130
131 if( !NT_SUCCESS(Status) ) {
132 SocketStateUnlock( FCB );
133 return Status;
134 }
135
136 if( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
137 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
138 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP,
139 Tail.Overlay.ListEntry);
140 AFD_DbgPrint(MID_TRACE,("Launching send request %x\n", NextIrp));
141 Status = AfdConnectedSocketWriteData
142 ( DeviceObject,
143 NextIrp,
144 IoGetCurrentIrpStackLocation( NextIrp ),
145 FALSE );
146 }
147
148 if( Status == STATUS_PENDING )
149 Status = STATUS_SUCCESS;
150 }
151
152 SocketStateUnlock( FCB );
153
154 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
155
156 return Status;
157 }
158
159 /* Return the socket object for ths request only if it is a connected or
160 stream type. */
161 NTSTATUS NTAPI
162 AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
163 PIO_STACK_LOCATION IrpSp) {
164 NTSTATUS Status = STATUS_INVALID_PARAMETER;
165 PTDI_CONNECTION_INFORMATION TargetAddress;
166 PFILE_OBJECT FileObject = IrpSp->FileObject;
167 PAFD_FCB FCB = FileObject->FsContext;
168 PAFD_CONNECT_INFO ConnectReq;
169 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
170
171 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
172 if( !(ConnectReq = LockRequest( Irp, IrpSp )) )
173 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
174 0 );
175
176 AFD_DbgPrint(MID_TRACE,("Connect request:\n"));
177 #if 0
178 OskitDumpBuffer
179 ( (PCHAR)ConnectReq,
180 IrpSp->Parameters.DeviceIoControl.InputBufferLength );
181 #endif
182
183 switch( FCB->State ) {
184 case SOCKET_STATE_CONNECTED:
185 Status = STATUS_SUCCESS;
186 break;
187
188 case SOCKET_STATE_CONNECTING:
189 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
190
191 case SOCKET_STATE_CREATED:
192 if( FCB->LocalAddress ) ExFreePool( FCB->LocalAddress );
193 FCB->LocalAddress =
194 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
195
196 if( FCB->LocalAddress ) {
197 Status = WarmSocketForBind( FCB );
198
199 if( NT_SUCCESS(Status) )
200 FCB->State = SOCKET_STATE_BOUND;
201 else
202 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
203 } else
204 return UnlockAndMaybeComplete
205 ( FCB, STATUS_NO_MEMORY, Irp, 0 );
206
207 /* Drop through to SOCKET_STATE_BOUND */
208
209 case SOCKET_STATE_BOUND:
210 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
211 FCB->RemoteAddress =
212 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
213
214 if( !FCB->RemoteAddress ) {
215 Status = STATUS_NO_MEMORY;
216 break;
217 }
218
219 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
220 {
221 Status = STATUS_SUCCESS;
222 break;
223 }
224
225 Status = WarmSocketForConnection( FCB );
226
227 if( !NT_SUCCESS(Status) )
228 break;
229
230 FCB->State = SOCKET_STATE_CONNECTING;
231
232 TdiBuildConnectionInfo
233 ( &TargetAddress,
234 &ConnectReq->RemoteAddress );
235
236 if( TargetAddress ) {
237 Status = TdiConnect( &FCB->ConnectIrp.InFlightRequest,
238 FCB->Connection.Object,
239 TargetAddress,
240 &FCB->ConnectIrp.Iosb,
241 StreamSocketConnectComplete,
242 FCB );
243
244 ExFreePool( TargetAddress );
245
246 AFD_DbgPrint(MID_TRACE,("Queueing IRP %x\n", Irp));
247
248 if( Status == STATUS_PENDING )
249 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
250 } else Status = STATUS_NO_MEMORY;
251 break;
252
253 default:
254 AFD_DbgPrint(MID_TRACE,("Inappropriate socket state %d for connect\n",
255 FCB->State));
256 break;
257 }
258
259 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
260 }