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