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