Sync with trunk r63786.
[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 &FCB->ReceiveIrp.Iosb,
290 ReceiveComplete,
291 FCB );
292
293 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
294
295 FCB->PollState |= AFD_EVENT_CONNECT | AFD_EVENT_SEND;
296 FCB->PollStatus[FD_CONNECT_BIT] = STATUS_SUCCESS;
297 FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS;
298 PollReeval( FCB->DeviceExt, FCB->FileObject );
299
300 return Status;
301 }
302
303 static IO_COMPLETION_ROUTINE StreamSocketConnectComplete;
304 static
305 NTSTATUS
306 NTAPI
307 StreamSocketConnectComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp,
308 PVOID Context) {
309 NTSTATUS Status = Irp->IoStatus.Status;
310 PAFD_FCB FCB = (PAFD_FCB)Context;
311 PLIST_ENTRY NextIrpEntry;
312 PIRP NextIrp;
313
314 AFD_DbgPrint(MID_TRACE,("Called: FCB %p, FO %p\n",
315 Context, FCB->FileObject));
316
317 /* I was wrong about this before as we can have pending writes to a not
318 * yet connected socket */
319 if( !SocketAcquireStateLock( FCB ) )
320 return STATUS_FILE_CLOSED;
321
322 AFD_DbgPrint(MID_TRACE,("Irp->IoStatus.Status = %x\n",
323 Irp->IoStatus.Status));
324
325 ASSERT(FCB->ConnectIrp.InFlightRequest == Irp);
326 FCB->ConnectIrp.InFlightRequest = NULL;
327
328 if( FCB->State == SOCKET_STATE_CLOSED ) {
329 /* Cleanup our IRP queue because the FCB is being destroyed */
330 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) {
331 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]);
332 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
333 NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
334 NextIrp->IoStatus.Information = 0;
335 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
336 (void)IoSetCancelRoutine(NextIrp, NULL);
337 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
338 }
339 SocketStateUnlock( FCB );
340 return STATUS_FILE_CLOSED;
341 }
342
343 if( !NT_SUCCESS(Irp->IoStatus.Status) ) {
344 FCB->PollState |= AFD_EVENT_CONNECT_FAIL;
345 FCB->PollStatus[FD_CONNECT_BIT] = Irp->IoStatus.Status;
346 AFD_DbgPrint(MID_TRACE,("Going to bound state\n"));
347 FCB->State = SOCKET_STATE_BOUND;
348 PollReeval( FCB->DeviceExt, FCB->FileObject );
349 }
350
351 /* Succeed pending irps on the FUNCTION_CONNECT list */
352 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) {
353 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]);
354 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
355 AFD_DbgPrint(MID_TRACE,("Completing connect %p\n", NextIrp));
356 NextIrp->IoStatus.Status = Status;
357 NextIrp->IoStatus.Information = NT_SUCCESS(Status) ? ((ULONG_PTR)FCB->Connection.Handle) : 0;
358 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
359 (void)IoSetCancelRoutine(NextIrp, NULL);
360 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
361 }
362
363 if( NT_SUCCESS(Status) ) {
364 Status = MakeSocketIntoConnection( FCB );
365
366 if( !NT_SUCCESS(Status) ) {
367 SocketStateUnlock( FCB );
368 return Status;
369 }
370
371 FCB->FilledConnectData = MIN(FCB->ConnectReturnInfo->UserDataLength, FCB->ConnectDataSize);
372 if (FCB->FilledConnectData)
373 {
374 RtlCopyMemory(FCB->ConnectData,
375 FCB->ConnectReturnInfo->UserData,
376 FCB->FilledConnectData);
377 }
378
379 FCB->FilledConnectOptions = MIN(FCB->ConnectReturnInfo->OptionsLength, FCB->ConnectOptionsSize);
380 if (FCB->FilledConnectOptions)
381 {
382 RtlCopyMemory(FCB->ConnectOptions,
383 FCB->ConnectReturnInfo->Options,
384 FCB->FilledConnectOptions);
385 }
386
387 if( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
388 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
389 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP,
390 Tail.Overlay.ListEntry);
391 AFD_DbgPrint(MID_TRACE,("Launching send request %p\n", NextIrp));
392 Status = AfdConnectedSocketWriteData
393 ( DeviceObject,
394 NextIrp,
395 IoGetCurrentIrpStackLocation( NextIrp ),
396 FALSE );
397 }
398
399 if( Status == STATUS_PENDING )
400 Status = STATUS_SUCCESS;
401 }
402
403 SocketStateUnlock( FCB );
404
405 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
406
407 return Status;
408 }
409
410 /* Return the socket object for ths request only if it is a connected or
411 stream type. */
412 NTSTATUS
413 NTAPI
414 AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
415 PIO_STACK_LOCATION IrpSp) {
416 NTSTATUS Status = STATUS_INVALID_PARAMETER;
417 PFILE_OBJECT FileObject = IrpSp->FileObject;
418 PAFD_FCB FCB = FileObject->FsContext;
419 PAFD_CONNECT_INFO ConnectReq;
420 AFD_DbgPrint(MID_TRACE,("Called on %p\n", FCB));
421
422 UNREFERENCED_PARAMETER(DeviceObject);
423
424 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
425 if( !(ConnectReq = LockRequest( Irp, IrpSp, FALSE, NULL )) )
426 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
427 0 );
428
429 AFD_DbgPrint(MID_TRACE,("Connect request:\n"));
430 #if 0
431 OskitDumpBuffer
432 ( (PCHAR)ConnectReq,
433 IrpSp->Parameters.DeviceIoControl.InputBufferLength );
434 #endif
435
436 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
437 {
438 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
439 FCB->RemoteAddress =
440 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
441
442 if( !FCB->RemoteAddress )
443 Status = STATUS_NO_MEMORY;
444 else
445 Status = STATUS_SUCCESS;
446
447 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
448 }
449
450 switch( FCB->State ) {
451 case SOCKET_STATE_CONNECTED:
452 Status = STATUS_SUCCESS;
453 break;
454
455 case SOCKET_STATE_CONNECTING:
456 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
457
458 case SOCKET_STATE_CREATED:
459 if( FCB->LocalAddress ) ExFreePool( FCB->LocalAddress );
460 FCB->LocalAddress =
461 TaBuildNullTransportAddress( ConnectReq->RemoteAddress.Address[0].AddressType );
462
463 if( FCB->LocalAddress ) {
464 Status = WarmSocketForBind( FCB, AFD_SHARE_WILDCARD );
465
466 if( NT_SUCCESS(Status) )
467 FCB->State = SOCKET_STATE_BOUND;
468 else
469 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
470 } else
471 return UnlockAndMaybeComplete
472 ( FCB, STATUS_NO_MEMORY, Irp, 0 );
473
474 /* Drop through to SOCKET_STATE_BOUND */
475
476 case SOCKET_STATE_BOUND:
477 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
478 FCB->RemoteAddress =
479 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
480
481 if( !FCB->RemoteAddress ) {
482 Status = STATUS_NO_MEMORY;
483 break;
484 }
485
486 Status = WarmSocketForConnection( FCB );
487
488 if( !NT_SUCCESS(Status) )
489 break;
490
491 if (FCB->ConnectReturnInfo) ExFreePool(FCB->ConnectReturnInfo);
492 Status = TdiBuildConnectionInfo
493 ( &FCB->ConnectReturnInfo,
494 &ConnectReq->RemoteAddress );
495
496 if( NT_SUCCESS(Status) )
497 {
498 if (FCB->ConnectCallInfo) ExFreePool(FCB->ConnectCallInfo);
499 Status = TdiBuildConnectionInfo(&FCB->ConnectCallInfo,
500 &ConnectReq->RemoteAddress);
501 }
502 else break;
503
504
505 if( NT_SUCCESS(Status) ) {
506 FCB->ConnectCallInfo->UserData = FCB->ConnectData;
507 FCB->ConnectCallInfo->UserDataLength = FCB->ConnectDataSize;
508 FCB->ConnectCallInfo->Options = FCB->ConnectOptions;
509 FCB->ConnectCallInfo->OptionsLength = FCB->ConnectOptionsSize;
510
511 FCB->State = SOCKET_STATE_CONNECTING;
512
513 AFD_DbgPrint(MID_TRACE,("Queueing IRP %p\n", Irp));
514 Status = QueueUserModeIrp( FCB, Irp, FUNCTION_CONNECT );
515 if (Status == STATUS_PENDING)
516 {
517 Status = TdiConnect( &FCB->ConnectIrp.InFlightRequest,
518 FCB->Connection.Object,
519 FCB->ConnectCallInfo,
520 FCB->ConnectReturnInfo,
521 &FCB->ConnectIrp.Iosb,
522 StreamSocketConnectComplete,
523 FCB );
524 }
525
526 if (Status != STATUS_PENDING)
527 FCB->State = SOCKET_STATE_BOUND;
528
529 SocketStateUnlock(FCB);
530
531 return Status;
532 }
533 break;
534
535 default:
536 AFD_DbgPrint(MIN_TRACE,("Inappropriate socket state %u for connect\n",
537 FCB->State));
538 break;
539 }
540
541 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
542 }