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