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