[CMAKE]
[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 FCB->PollStatus[FD_CONNECT_BIT] = STATUS_SUCCESS;
251 FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS;
252 PollReeval( FCB->DeviceExt, FCB->FileObject );
253
254 return Status;
255 }
256
257 static NTSTATUS NTAPI StreamSocketConnectComplete
258 ( PDEVICE_OBJECT DeviceObject,
259 PIRP Irp,
260 PVOID Context ) {
261 NTSTATUS Status = Irp->IoStatus.Status;
262 PAFD_FCB FCB = (PAFD_FCB)Context;
263 PLIST_ENTRY NextIrpEntry;
264 PIRP NextIrp;
265
266 AFD_DbgPrint(MID_TRACE,("Called: FCB %x, FO %x\n",
267 Context, FCB->FileObject));
268
269 /* I was wrong about this before as we can have pending writes to a not
270 * yet connected socket */
271 if( !SocketAcquireStateLock( FCB ) )
272 return STATUS_FILE_CLOSED;
273
274 AFD_DbgPrint(MID_TRACE,("Irp->IoStatus.Status = %x\n",
275 Irp->IoStatus.Status));
276
277 FCB->ConnectIrp.InFlightRequest = NULL;
278
279 if( FCB->State == SOCKET_STATE_CLOSED ) {
280 /* Cleanup our IRP queue because the FCB is being destroyed */
281 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) {
282 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]);
283 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
284 NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
285 NextIrp->IoStatus.Information = 0;
286 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
287 (void)IoSetCancelRoutine(NextIrp, NULL);
288 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
289 }
290 SocketStateUnlock( FCB );
291 return STATUS_FILE_CLOSED;
292 }
293
294 if( !NT_SUCCESS(Irp->IoStatus.Status) ) {
295 FCB->PollState |= AFD_EVENT_CONNECT_FAIL;
296 FCB->PollStatus[FD_CONNECT_BIT] = Irp->IoStatus.Status;
297 AFD_DbgPrint(MID_TRACE,("Going to bound state\n"));
298 FCB->State = SOCKET_STATE_BOUND;
299 PollReeval( FCB->DeviceExt, FCB->FileObject );
300 }
301
302 /* Succeed pending irps on the FUNCTION_CONNECT list */
303 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) {
304 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]);
305 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
306 AFD_DbgPrint(MID_TRACE,("Completing connect %x\n", NextIrp));
307 NextIrp->IoStatus.Status = Status;
308 NextIrp->IoStatus.Information = NT_SUCCESS(Status) ? ((ULONG_PTR)FCB->Connection.Handle) : 0;
309 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
310 (void)IoSetCancelRoutine(NextIrp, NULL);
311 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
312 }
313
314 if( NT_SUCCESS(Status) ) {
315 Status = MakeSocketIntoConnection( FCB );
316
317 if( !NT_SUCCESS(Status) ) {
318 SocketStateUnlock( FCB );
319 return Status;
320 }
321
322 FCB->FilledConnectData = MIN(FCB->ConnectInfo->UserDataLength, FCB->ConnectDataSize);
323 if (FCB->FilledConnectData)
324 {
325 RtlCopyMemory(FCB->ConnectData,
326 FCB->ConnectInfo->UserData,
327 FCB->FilledConnectData);
328 }
329
330 FCB->FilledConnectOptions = MIN(FCB->ConnectInfo->OptionsLength, FCB->ConnectOptionsSize);
331 if (FCB->FilledConnectOptions)
332 {
333 RtlCopyMemory(FCB->ConnectOptions,
334 FCB->ConnectInfo->Options,
335 FCB->FilledConnectOptions);
336 }
337
338 if( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
339 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
340 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP,
341 Tail.Overlay.ListEntry);
342 AFD_DbgPrint(MID_TRACE,("Launching send request %x\n", NextIrp));
343 Status = AfdConnectedSocketWriteData
344 ( DeviceObject,
345 NextIrp,
346 IoGetCurrentIrpStackLocation( NextIrp ),
347 FALSE );
348 }
349
350 if( Status == STATUS_PENDING )
351 Status = STATUS_SUCCESS;
352 }
353
354 SocketStateUnlock( FCB );
355
356 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
357
358 return Status;
359 }
360
361 /* Return the socket object for ths request only if it is a connected or
362 stream type. */
363 NTSTATUS NTAPI
364 AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
365 PIO_STACK_LOCATION IrpSp) {
366 NTSTATUS Status = STATUS_INVALID_PARAMETER;
367 PFILE_OBJECT FileObject = IrpSp->FileObject;
368 PAFD_FCB FCB = FileObject->FsContext;
369 PAFD_CONNECT_INFO ConnectReq;
370 PTDI_CONNECTION_INFORMATION TargetAddress;
371 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
372
373 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
374 if( !(ConnectReq = LockRequest( Irp, IrpSp )) )
375 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
376 0 );
377
378 AFD_DbgPrint(MID_TRACE,("Connect request:\n"));
379 #if 0
380 OskitDumpBuffer
381 ( (PCHAR)ConnectReq,
382 IrpSp->Parameters.DeviceIoControl.InputBufferLength );
383 #endif
384
385 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
386 {
387 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
388 FCB->RemoteAddress =
389 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
390
391 if( !FCB->RemoteAddress )
392 Status = STATUS_NO_MEMORY;
393 else
394 Status = STATUS_SUCCESS;
395
396 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
397 }
398
399 switch( FCB->State ) {
400 case SOCKET_STATE_CONNECTED:
401 Status = STATUS_SUCCESS;
402 break;
403
404 case SOCKET_STATE_CONNECTING:
405 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
406
407 case SOCKET_STATE_CREATED:
408 if( FCB->LocalAddress ) ExFreePool( FCB->LocalAddress );
409 FCB->LocalAddress =
410 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
411
412 if( FCB->LocalAddress ) {
413 Status = WarmSocketForBind( FCB );
414
415 if( NT_SUCCESS(Status) )
416 FCB->State = SOCKET_STATE_BOUND;
417 else
418 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
419 } else
420 return UnlockAndMaybeComplete
421 ( FCB, STATUS_NO_MEMORY, Irp, 0 );
422
423 /* Drop through to SOCKET_STATE_BOUND */
424
425 case SOCKET_STATE_BOUND:
426 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
427 FCB->RemoteAddress =
428 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
429
430 if( !FCB->RemoteAddress ) {
431 Status = STATUS_NO_MEMORY;
432 break;
433 }
434
435 Status = WarmSocketForConnection( FCB );
436
437 if( !NT_SUCCESS(Status) )
438 break;
439
440 Status = TdiBuildConnectionInfo
441 ( &FCB->ConnectInfo,
442 &ConnectReq->RemoteAddress );
443
444 if( NT_SUCCESS(Status) )
445 Status = TdiBuildConnectionInfo(&TargetAddress,
446 &ConnectReq->RemoteAddress);
447 else break;
448
449
450 if( NT_SUCCESS(Status) ) {
451 TargetAddress->UserData = FCB->ConnectData;
452 TargetAddress->UserDataLength = FCB->ConnectDataSize;
453 TargetAddress->Options = FCB->ConnectOptions;
454 TargetAddress->OptionsLength = FCB->ConnectOptionsSize;
455
456 Status = TdiConnect( &FCB->ConnectIrp.InFlightRequest,
457 FCB->Connection.Object,
458 TargetAddress,
459 FCB->ConnectInfo,
460 &FCB->ConnectIrp.Iosb,
461 StreamSocketConnectComplete,
462 FCB );
463
464 ExFreePool(TargetAddress);
465
466 AFD_DbgPrint(MID_TRACE,("Queueing IRP %x\n", Irp));
467
468 if( Status == STATUS_PENDING ) {
469 FCB->State = SOCKET_STATE_CONNECTING;
470 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
471 }
472 }
473 break;
474
475 default:
476 AFD_DbgPrint(MID_TRACE,("Inappropriate socket state %d for connect\n",
477 FCB->State));
478 break;
479 }
480
481 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
482 }