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