9c15009787d853f1788b4242ce532e165333649a
[reactos.git] / reactos / drivers / net / 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 WarmSocketForConnection( PAFD_FCB FCB ) {
16 NTSTATUS Status;
17
18 if( !FCB->TdiDeviceName.Length || !FCB->TdiDeviceName.Buffer ) {
19 AFD_DbgPrint(MID_TRACE,("Null Device\n"));
20 return STATUS_NO_SUCH_DEVICE;
21 }
22
23 Status = TdiOpenConnectionEndpointFile
24 ( &FCB->TdiDeviceName,
25 &FCB->Connection.Handle,
26 &FCB->Connection.Object );
27
28 if( NT_SUCCESS(Status) ) {
29 Status = TdiAssociateAddressFile
30 ( FCB->AddressFile.Handle,
31 FCB->Connection.Object );
32 }
33
34 if( !NT_SUCCESS(Status) ) {
35 TdiCloseDevice( &FCB->Connection.Handle,
36 FCB->Connection.Object );
37 RtlZeroMemory( &FCB->Connection, sizeof(FCB->Connection) );
38 }
39
40 return Status;
41 }
42
43 NTSTATUS MakeSocketIntoConnection( PAFD_FCB FCB ) {
44 NTSTATUS Status = STATUS_NO_MEMORY;
45
46 /* Allocate the receive area and start receiving */
47 FCB->Recv.Window =
48 ExAllocatePool( NonPagedPool, FCB->Recv.Size );
49 FCB->Send.Window =
50 ExAllocatePool( NonPagedPool, FCB->Send.Size );
51
52 FCB->State = SOCKET_STATE_CONNECTED;
53
54 if( FCB->Recv.Window ) {
55 Status = TdiReceive( &FCB->ReceiveIrp.InFlightRequest,
56 FCB->Connection.Object,
57 TDI_RECEIVE_NORMAL,
58 FCB->Recv.Window,
59 FCB->Recv.Size,
60 &FCB->ReceiveIrp.Iosb,
61 ReceiveComplete,
62 FCB );
63 }
64
65 return Status;
66 }
67
68 static NTSTATUS DDKAPI StreamSocketConnectComplete
69 ( PDEVICE_OBJECT DeviceObject,
70 PIRP Irp,
71 PVOID Context ) {
72 NTSTATUS Status = Irp->IoStatus.Status;
73 PAFD_FCB FCB = (PAFD_FCB)Context;
74 PLIST_ENTRY NextIrpEntry;
75 PIRP NextIrp;
76
77 AFD_DbgPrint(MID_TRACE,("Called: FCB %x, FO %x\n",
78 Context, FCB->FileObject));
79
80 /* I was wrong about this before as we can have pending writes to a not
81 * yet connected socket */
82 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp, FALSE );
83
84 AFD_DbgPrint(MID_TRACE,("Irp->IoStatus.Status = %x\n",
85 Irp->IoStatus.Status));
86
87 if( NT_SUCCESS(Irp->IoStatus.Status) ) {
88 FCB->PollState |= AFD_EVENT_CONNECT | AFD_EVENT_SEND;
89 FCB->State = SOCKET_STATE_CONNECTED;
90 AFD_DbgPrint(MID_TRACE,("Going to connected state %d\n", FCB->State));
91 PollReeval( FCB->DeviceExt, FCB->FileObject );
92 } else {
93 FCB->PollState |= AFD_EVENT_CONNECT_FAIL | AFD_EVENT_RECEIVE;
94 AFD_DbgPrint(MID_TRACE,("Going to bound state\n"));
95 FCB->State = SOCKET_STATE_BOUND;
96 PollReeval( FCB->DeviceExt, FCB->FileObject );
97 }
98
99 /* Succeed pending irps on the FUNCTION_CONNECT list */
100 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) {
101 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]);
102 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
103 AFD_DbgPrint(MID_TRACE,("Completing connect %x\n", NextIrp));
104 NextIrp->IoStatus.Status = Status;
105 NextIrp->IoStatus.Information = 0;
106 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
107 }
108
109 if( NT_SUCCESS(Status) ) {
110 Status = MakeSocketIntoConnection( FCB );
111
112 if( FCB->Send.Window &&
113 !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
114 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
115 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP,
116 Tail.Overlay.ListEntry);
117 AFD_DbgPrint(MID_TRACE,("Launching send request %x\n", NextIrp));
118 Status = AfdConnectedSocketWriteData
119 ( DeviceObject,
120 NextIrp,
121 IoGetCurrentIrpStackLocation( NextIrp ),
122 FALSE );
123 }
124
125 if( Status == STATUS_PENDING )
126 Status = STATUS_SUCCESS;
127 }
128
129 SocketStateUnlock( FCB );
130
131 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
132
133 return Status;
134 }
135
136 /* Return the socket object for ths request only if it is a connected or
137 stream type. */
138 NTSTATUS STDCALL
139 AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
140 PIO_STACK_LOCATION IrpSp) {
141 NTSTATUS Status = STATUS_INVALID_PARAMETER;
142 PTDI_CONNECTION_INFORMATION TargetAddress;
143 PFILE_OBJECT FileObject = IrpSp->FileObject;
144 PAFD_FCB FCB = FileObject->FsContext;
145 PAFD_CONNECT_INFO ConnectReq;
146 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
147
148 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp, FALSE );
149 if( !(ConnectReq = LockRequest( Irp, IrpSp )) )
150 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
151 0, NULL, TRUE );
152
153 AFD_DbgPrint(MID_TRACE,("Connect request:\n"));
154 OskitDumpBuffer
155 ( (PCHAR)ConnectReq,
156 IrpSp->Parameters.DeviceIoControl.InputBufferLength );
157
158 switch( FCB->State ) {
159 case SOCKET_STATE_CONNECTED:
160 Status = STATUS_SUCCESS;
161 break;
162
163 case SOCKET_STATE_CONNECTING:
164 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
165
166 case SOCKET_STATE_CREATED: {
167 FCB->LocalAddress =
168 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
169
170 if( FCB->LocalAddress ) {
171 RtlZeroMemory( FCB->LocalAddress,
172 TaLengthOfTransportAddress
173 ( &ConnectReq->RemoteAddress ) );
174
175 FCB->LocalAddress->TAAddressCount = 1;
176 FCB->LocalAddress->Address[0].AddressType =
177 ConnectReq->RemoteAddress.Address[0].AddressType;
178 FCB->LocalAddress->Address[0].AddressLength =
179 ConnectReq->RemoteAddress.Address[0].AddressLength;
180
181 Status = WarmSocketForBind( FCB );
182
183 if( NT_SUCCESS(Status) )
184 FCB->State = SOCKET_STATE_BOUND;
185 else
186 return UnlockAndMaybeComplete( FCB, Status, Irp, 0, NULL,
187 TRUE );
188 } else
189 return UnlockAndMaybeComplete
190 ( FCB, STATUS_NO_MEMORY, Irp, 0, NULL, TRUE );
191 } /* Drop through to SOCKET_STATE_BOUND */
192
193 case SOCKET_STATE_BOUND:
194 FCB->RemoteAddress =
195 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
196
197 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
198 {
199 Status = STATUS_SUCCESS;
200 break;
201 }
202
203 Status = WarmSocketForConnection( FCB );
204
205 if( !NT_SUCCESS(Status) )
206 break;
207
208 FCB->State = SOCKET_STATE_CONNECTING;
209
210 TdiBuildConnectionInfo
211 ( &TargetAddress,
212 &ConnectReq->RemoteAddress );
213
214 if( TargetAddress ) {
215 Status = TdiConnect( &FCB->ConnectIrp.InFlightRequest,
216 FCB->Connection.Object,
217 TargetAddress,
218 &FCB->ConnectIrp.Iosb,
219 StreamSocketConnectComplete,
220 FCB );
221
222 ExFreePool( TargetAddress );
223
224 AFD_DbgPrint(MID_TRACE,("Queueing IRP %x\n", Irp));
225
226 if( Status == STATUS_PENDING )
227 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
228 } else Status = STATUS_NO_MEMORY;
229 break;
230
231 default:
232 AFD_DbgPrint(MID_TRACE,("Inappropriate socket state %d for connect\n",
233 FCB->State));
234 break;
235 }
236
237 return UnlockAndMaybeComplete( FCB, Status, Irp, 0, NULL, TRUE );
238 }