sync with trunk r46493
[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 NTAPI
16 AfdGetConnectOptions(PDEVICE_OBJECT DeviceObject, PIRP Irp,
17 PIO_STACK_LOCATION IrpSp)
18 {
19 PFILE_OBJECT FileObject = IrpSp->FileObject;
20 PAFD_FCB FCB = FileObject->FsContext;
21 UINT BufferSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
22
23 if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
24
25 if (FCB->ConnectOptionsSize == 0)
26 return UnlockAndMaybeComplete(FCB, STATUS_INVALID_PARAMETER, Irp, 0);
27
28 ASSERT(FCB->ConnectOptions);
29
30 if (FCB->FilledConnectOptions < BufferSize) BufferSize = FCB->FilledConnectOptions;
31
32 RtlCopyMemory(Irp->UserBuffer,
33 FCB->ConnectOptions,
34 BufferSize);
35
36 return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, BufferSize);
37 }
38
39 NTSTATUS
40 NTAPI
41 AfdSetConnectOptions(PDEVICE_OBJECT DeviceObject, PIRP Irp,
42 PIO_STACK_LOCATION IrpSp)
43 {
44 PFILE_OBJECT FileObject = IrpSp->FileObject;
45 PAFD_FCB FCB = FileObject->FsContext;
46 PVOID ConnectOptions = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
47 UINT ConnectOptionsSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
48
49 if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
50
51 if (FCB->ConnectOptions)
52 {
53 ExFreePool(FCB->ConnectOptions);
54 FCB->ConnectOptions = NULL;
55 FCB->ConnectOptionsSize = 0;
56 FCB->FilledConnectOptions = 0;
57 }
58
59 FCB->ConnectOptions = ExAllocatePool(PagedPool, ConnectOptionsSize);
60 if (!FCB->ConnectOptions) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
61
62 RtlCopyMemory(FCB->ConnectOptions,
63 ConnectOptions,
64 ConnectOptionsSize);
65
66 FCB->ConnectOptionsSize = ConnectOptionsSize;
67
68 return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
69 }
70
71 NTSTATUS
72 NTAPI
73 AfdSetConnectOptionsSize(PDEVICE_OBJECT DeviceObject, PIRP Irp,
74 PIO_STACK_LOCATION IrpSp)
75 {
76 PFILE_OBJECT FileObject = IrpSp->FileObject;
77 PAFD_FCB FCB = FileObject->FsContext;
78 PUINT ConnectOptionsSize = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
79 UINT BufferSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
80
81 if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
82
83 if (BufferSize < sizeof(UINT))
84 return UnlockAndMaybeComplete(FCB, STATUS_BUFFER_TOO_SMALL, Irp, 0);
85
86 if (FCB->ConnectOptions)
87 {
88 ExFreePool(FCB->ConnectOptions);
89 FCB->ConnectOptionsSize = 0;
90 FCB->FilledConnectOptions = 0;
91 }
92
93 FCB->ConnectOptions = ExAllocatePool(PagedPool, *ConnectOptionsSize);
94 if (!FCB->ConnectOptions) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
95
96 FCB->ConnectOptionsSize = *ConnectOptionsSize;
97
98 return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
99 }
100
101 NTSTATUS NTAPI
102 AfdGetConnectData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
103 PIO_STACK_LOCATION IrpSp)
104 {
105 PFILE_OBJECT FileObject = IrpSp->FileObject;
106 PAFD_FCB FCB = FileObject->FsContext;
107 UINT BufferSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
108
109 if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
110
111 if (FCB->ConnectDataSize == 0)
112 return UnlockAndMaybeComplete(FCB, STATUS_INVALID_PARAMETER, Irp, 0);
113
114 ASSERT(FCB->ConnectData);
115
116 if (FCB->FilledConnectData < BufferSize) BufferSize = FCB->FilledConnectData;
117
118 RtlCopyMemory(Irp->UserBuffer,
119 FCB->ConnectData,
120 BufferSize);
121
122 return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, BufferSize);
123 }
124
125 NTSTATUS
126 NTAPI
127 AfdSetConnectData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
128 PIO_STACK_LOCATION IrpSp)
129 {
130 PFILE_OBJECT FileObject = IrpSp->FileObject;
131 PAFD_FCB FCB = FileObject->FsContext;
132 PVOID ConnectData = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
133 UINT ConnectDataSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
134
135 if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
136
137 if (FCB->ConnectData)
138 {
139 ExFreePool(FCB->ConnectData);
140 FCB->ConnectData = NULL;
141 FCB->ConnectDataSize = 0;
142 FCB->FilledConnectData = 0;
143 }
144
145 FCB->ConnectData = ExAllocatePool(PagedPool, ConnectDataSize);
146 if (!FCB->ConnectData) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
147
148 RtlCopyMemory(FCB->ConnectData,
149 ConnectData,
150 ConnectDataSize);
151
152 FCB->ConnectDataSize = ConnectDataSize;
153
154 return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
155 }
156
157 NTSTATUS
158 NTAPI
159 AfdSetConnectDataSize(PDEVICE_OBJECT DeviceObject, PIRP Irp,
160 PIO_STACK_LOCATION IrpSp)
161 {
162 PFILE_OBJECT FileObject = IrpSp->FileObject;
163 PAFD_FCB FCB = FileObject->FsContext;
164 PUINT ConnectDataSize = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
165 UINT BufferSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
166
167 if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
168
169 if (BufferSize < sizeof(UINT))
170 return UnlockAndMaybeComplete(FCB, STATUS_BUFFER_TOO_SMALL, Irp, 0);
171
172 if (FCB->ConnectData)
173 {
174 ExFreePool(FCB->ConnectData);
175 FCB->ConnectDataSize = 0;
176 FCB->FilledConnectData = 0;
177 }
178
179 FCB->ConnectData = ExAllocatePool(PagedPool, *ConnectDataSize);
180 if (!FCB->ConnectData) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
181
182 FCB->ConnectDataSize = *ConnectDataSize;
183
184 return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
185 }
186
187
188 NTSTATUS WarmSocketForConnection( PAFD_FCB FCB ) {
189 NTSTATUS Status;
190
191 if( !FCB->TdiDeviceName.Length || !FCB->TdiDeviceName.Buffer ) {
192 AFD_DbgPrint(MID_TRACE,("Null Device\n"));
193 return STATUS_NO_SUCH_DEVICE;
194 }
195
196 Status = TdiOpenConnectionEndpointFile(&FCB->TdiDeviceName,
197 &FCB->Connection.Handle,
198 &FCB->Connection.Object );
199
200 if( NT_SUCCESS(Status) ) {
201 Status = TdiAssociateAddressFile( FCB->AddressFile.Handle,
202 FCB->Connection.Object );
203 }
204
205 return Status;
206 }
207
208 NTSTATUS MakeSocketIntoConnection( PAFD_FCB FCB ) {
209 NTSTATUS Status;
210
211 ASSERT(!FCB->Recv.Window);
212 ASSERT(!FCB->Send.Window);
213
214 Status = TdiQueryMaxDatagramLength(FCB->Connection.Object,
215 &FCB->Send.Size);
216 if (!NT_SUCCESS(Status))
217 return Status;
218
219 FCB->Recv.Size = FCB->Send.Size;
220
221 /* Allocate the receive area and start receiving */
222 FCB->Recv.Window =
223 ExAllocatePool( PagedPool, FCB->Recv.Size );
224
225 if( !FCB->Recv.Window ) return STATUS_NO_MEMORY;
226
227 FCB->Send.Window =
228 ExAllocatePool( PagedPool, FCB->Send.Size );
229
230 if( !FCB->Send.Window ) {
231 ExFreePool( FCB->Recv.Window );
232 FCB->Recv.Window = NULL;
233 return STATUS_NO_MEMORY;
234 }
235
236 FCB->State = SOCKET_STATE_CONNECTED;
237
238 Status = TdiReceive( &FCB->ReceiveIrp.InFlightRequest,
239 FCB->Connection.Object,
240 TDI_RECEIVE_NORMAL,
241 FCB->Recv.Window,
242 FCB->Recv.Size,
243 &FCB->ReceiveIrp.Iosb,
244 ReceiveComplete,
245 FCB );
246
247 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
248
249 FCB->PollState |= AFD_EVENT_CONNECT | AFD_EVENT_SEND;
250 PollReeval( FCB->DeviceExt, FCB->FileObject );
251
252 return Status;
253 }
254
255 static NTSTATUS NTAPI StreamSocketConnectComplete
256 ( PDEVICE_OBJECT DeviceObject,
257 PIRP Irp,
258 PVOID Context ) {
259 NTSTATUS Status = Irp->IoStatus.Status;
260 PAFD_FCB FCB = (PAFD_FCB)Context;
261 PLIST_ENTRY NextIrpEntry;
262 PIRP NextIrp;
263
264 AFD_DbgPrint(MID_TRACE,("Called: FCB %x, FO %x\n",
265 Context, FCB->FileObject));
266
267 /* I was wrong about this before as we can have pending writes to a not
268 * yet connected socket */
269 if( !SocketAcquireStateLock( FCB ) )
270 return STATUS_FILE_CLOSED;
271
272 AFD_DbgPrint(MID_TRACE,("Irp->IoStatus.Status = %x\n",
273 Irp->IoStatus.Status));
274
275 FCB->ConnectIrp.InFlightRequest = NULL;
276
277 if( FCB->State == SOCKET_STATE_CLOSED ) {
278 /* Cleanup our IRP queue because the FCB is being destroyed */
279 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) {
280 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]);
281 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
282 NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
283 NextIrp->IoStatus.Information = 0;
284 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
285 (void)IoSetCancelRoutine(NextIrp, NULL);
286 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
287 }
288 SocketStateUnlock( FCB );
289 return STATUS_FILE_CLOSED;
290 }
291
292 if( !NT_SUCCESS(Irp->IoStatus.Status) ) {
293 FCB->PollState |= AFD_EVENT_CONNECT_FAIL;
294 AFD_DbgPrint(MID_TRACE,("Going to bound state\n"));
295 FCB->State = SOCKET_STATE_BOUND;
296 PollReeval( FCB->DeviceExt, FCB->FileObject );
297 }
298
299 /* Succeed pending irps on the FUNCTION_CONNECT list */
300 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) {
301 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]);
302 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
303 AFD_DbgPrint(MID_TRACE,("Completing connect %x\n", NextIrp));
304 NextIrp->IoStatus.Status = Status;
305 NextIrp->IoStatus.Information = NT_SUCCESS(Status) ? ((ULONG_PTR)FCB->Connection.Handle) : 0;
306 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
307 (void)IoSetCancelRoutine(NextIrp, NULL);
308 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
309 }
310
311 if( NT_SUCCESS(Status) ) {
312 Status = MakeSocketIntoConnection( FCB );
313
314 if( !NT_SUCCESS(Status) ) {
315 SocketStateUnlock( FCB );
316 return Status;
317 }
318
319 FCB->FilledConnectData = MIN(FCB->ConnectInfo->UserDataLength, FCB->ConnectDataSize);
320 if (FCB->FilledConnectData)
321 {
322 RtlCopyMemory(FCB->ConnectData,
323 FCB->ConnectInfo->UserData,
324 FCB->FilledConnectData);
325 }
326
327 FCB->FilledConnectOptions = MIN(FCB->ConnectInfo->OptionsLength, FCB->ConnectOptionsSize);
328 if (FCB->FilledConnectOptions)
329 {
330 RtlCopyMemory(FCB->ConnectOptions,
331 FCB->ConnectInfo->Options,
332 FCB->FilledConnectOptions);
333 }
334
335 if( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
336 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
337 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP,
338 Tail.Overlay.ListEntry);
339 AFD_DbgPrint(MID_TRACE,("Launching send request %x\n", NextIrp));
340 Status = AfdConnectedSocketWriteData
341 ( DeviceObject,
342 NextIrp,
343 IoGetCurrentIrpStackLocation( NextIrp ),
344 FALSE );
345 }
346
347 if( Status == STATUS_PENDING )
348 Status = STATUS_SUCCESS;
349 }
350
351 SocketStateUnlock( FCB );
352
353 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
354
355 return Status;
356 }
357
358 /* Return the socket object for ths request only if it is a connected or
359 stream type. */
360 NTSTATUS NTAPI
361 AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
362 PIO_STACK_LOCATION IrpSp) {
363 NTSTATUS Status = STATUS_INVALID_PARAMETER;
364 PFILE_OBJECT FileObject = IrpSp->FileObject;
365 PAFD_FCB FCB = FileObject->FsContext;
366 PAFD_CONNECT_INFO ConnectReq;
367 PTDI_CONNECTION_INFORMATION TargetAddress;
368 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
369
370 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
371 if( !(ConnectReq = LockRequest( Irp, IrpSp )) )
372 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
373 0 );
374
375 AFD_DbgPrint(MID_TRACE,("Connect request:\n"));
376 #if 0
377 OskitDumpBuffer
378 ( (PCHAR)ConnectReq,
379 IrpSp->Parameters.DeviceIoControl.InputBufferLength );
380 #endif
381
382 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
383 {
384 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
385 FCB->RemoteAddress =
386 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
387
388 if( !FCB->RemoteAddress )
389 Status = STATUS_NO_MEMORY;
390 else
391 Status = STATUS_SUCCESS;
392
393 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
394 }
395
396 switch( FCB->State ) {
397 case SOCKET_STATE_CONNECTED:
398 Status = STATUS_SUCCESS;
399 break;
400
401 case SOCKET_STATE_CONNECTING:
402 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
403
404 case SOCKET_STATE_CREATED:
405 if( FCB->LocalAddress ) ExFreePool( FCB->LocalAddress );
406 FCB->LocalAddress =
407 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
408
409 if( FCB->LocalAddress ) {
410 Status = WarmSocketForBind( FCB );
411
412 if( NT_SUCCESS(Status) )
413 FCB->State = SOCKET_STATE_BOUND;
414 else
415 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
416 } else
417 return UnlockAndMaybeComplete
418 ( FCB, STATUS_NO_MEMORY, Irp, 0 );
419
420 /* Drop through to SOCKET_STATE_BOUND */
421
422 case SOCKET_STATE_BOUND:
423 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
424 FCB->RemoteAddress =
425 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
426
427 if( !FCB->RemoteAddress ) {
428 Status = STATUS_NO_MEMORY;
429 break;
430 }
431
432 Status = WarmSocketForConnection( FCB );
433
434 if( !NT_SUCCESS(Status) )
435 break;
436
437 Status = TdiBuildConnectionInfo
438 ( &FCB->ConnectInfo,
439 &ConnectReq->RemoteAddress );
440
441 if( NT_SUCCESS(Status) )
442 Status = TdiBuildConnectionInfo(&TargetAddress,
443 &ConnectReq->RemoteAddress);
444 else break;
445
446
447 if( NT_SUCCESS(Status) ) {
448 TargetAddress->UserData = FCB->ConnectData;
449 TargetAddress->UserDataLength = FCB->ConnectDataSize;
450 TargetAddress->Options = FCB->ConnectOptions;
451 TargetAddress->OptionsLength = FCB->ConnectOptionsSize;
452
453 Status = TdiConnect( &FCB->ConnectIrp.InFlightRequest,
454 FCB->Connection.Object,
455 TargetAddress,
456 FCB->ConnectInfo,
457 &FCB->ConnectIrp.Iosb,
458 StreamSocketConnectComplete,
459 FCB );
460
461 ExFreePool(TargetAddress);
462
463 AFD_DbgPrint(MID_TRACE,("Queueing IRP %x\n", Irp));
464
465 if( Status == STATUS_PENDING ) {
466 FCB->State = SOCKET_STATE_CONNECTING;
467 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
468 }
469 }
470 break;
471
472 default:
473 AFD_DbgPrint(MID_TRACE,("Inappropriate socket state %d for connect\n",
474 FCB->State));
475 break;
476 }
477
478 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
479 }