Implement support for MSG_PEEK.
[reactos.git] / reactos / drivers / network / afd / afd / write.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/net/afd/afd/write.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 static NTSTATUS NTAPI SendComplete
16 ( PDEVICE_OBJECT DeviceObject,
17 PIRP Irp,
18 PVOID Context ) {
19 NTSTATUS Status = Irp->IoStatus.Status;
20 PAFD_FCB FCB = (PAFD_FCB)Context;
21 PLIST_ENTRY NextIrpEntry;
22 PIRP NextIrp = NULL;
23 PIO_STACK_LOCATION NextIrpSp;
24 PAFD_SEND_INFO SendReq = NULL;
25 PAFD_MAPBUF Map;
26 UINT TotalBytesCopied = 0, SpaceAvail, i, CopySize = 0;
27
28 /*
29 * The Irp parameter passed in is the IRP of the stream between AFD and
30 * TDI driver. It's not very usefull to us. We need the IRPs of the stream
31 * between usermode and AFD. Those are chained from
32 * FCB->PendingIrpList[FUNCTION_SEND] and you'll see them in the code
33 * below as "NextIrp" ('cause they are the next usermode IRP to be
34 * processed).
35 */
36
37 AFD_DbgPrint(MID_TRACE,("Called, status %x, %d bytes used\n",
38 Irp->IoStatus.Status,
39 Irp->IoStatus.Information));
40
41 ASSERT_IRQL(APC_LEVEL);
42
43 if( !SocketAcquireStateLock( FCB ) ) return Status;
44
45 FCB->SendIrp.InFlightRequest = NULL;
46 /* Request is not in flight any longer */
47
48 if( FCB->State == SOCKET_STATE_CLOSED ) {
49 SocketStateUnlock( FCB );
50 DestroySocket( FCB );
51 return STATUS_SUCCESS;
52 }
53
54 if( !NT_SUCCESS(Status) ) {
55 /* Complete all following send IRPs with error */
56
57 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
58 NextIrpEntry =
59 RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
60 NextIrp =
61 CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
62 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
63 SendReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
64
65 UnlockBuffers( SendReq->BufferArray,
66 SendReq->BufferCount,
67 FALSE );
68
69 NextIrp->IoStatus.Status = Status;
70 NextIrp->IoStatus.Information = 0;
71
72 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
73 }
74
75 SocketStateUnlock( FCB );
76
77 return STATUS_SUCCESS;
78 }
79
80 RtlMoveMemory( FCB->Send.Window,
81 FCB->Send.Window + FCB->Send.BytesUsed,
82 FCB->Send.BytesUsed - Irp->IoStatus.Information );
83 FCB->Send.BytesUsed -= Irp->IoStatus.Information;
84
85 if( !FCB->Send.BytesUsed &&
86 !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) &&
87 NT_SUCCESS(Status) ) {
88 NextIrpEntry =
89 RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
90 NextIrp =
91 CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
92 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
93 SendReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
94 Map = (PAFD_MAPBUF)(SendReq->BufferArray + SendReq->BufferCount);
95
96 AFD_DbgPrint(MID_TRACE,("SendReq @ %x\n", SendReq));
97
98 SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
99
100 for( i = 0; i < SendReq->BufferCount; i++ ) {
101 Map[i].BufferAddress =
102 MmMapLockedPages( Map[i].Mdl, KernelMode );
103
104 CopySize = MIN( SpaceAvail,
105 SendReq->BufferArray[i].len );
106
107 RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed,
108 Map[i].BufferAddress,
109 CopySize );
110
111 MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl );
112
113 FCB->Send.BytesUsed += CopySize;
114 TotalBytesCopied += CopySize;
115 SpaceAvail -= CopySize;
116 }
117 }
118
119 /* Some data is still waiting */
120 if( FCB->Send.BytesUsed ) {
121 FCB->PollState &= ~AFD_EVENT_SEND;
122
123 SocketCalloutEnter( FCB );
124
125 Status = TdiSend( &FCB->SendIrp.InFlightRequest,
126 FCB->Connection.Object,
127 0,
128 FCB->Send.Window,
129 FCB->Send.BytesUsed,
130 &FCB->SendIrp.Iosb,
131 SendComplete,
132 FCB );
133
134 SocketCalloutLeave( FCB );
135 } else {
136 FCB->PollState |= AFD_EVENT_SEND;
137 PollReeval( FCB->DeviceExt, FCB->FileObject );
138 }
139
140 if( TotalBytesCopied > 0 ) {
141 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
142
143 if( Status == STATUS_PENDING )
144 Status = STATUS_SUCCESS;
145
146 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
147
148 return UnlockAndMaybeComplete( FCB, Status, NextIrp, TotalBytesCopied,
149 NULL, TRUE );
150 } else if( NextIrp ) {
151 AFD_DbgPrint(MID_TRACE,("Could not do any more with Irp %x\n",
152 NextIrp));
153 InsertHeadList( &FCB->PendingIrpList[FUNCTION_SEND],
154 &NextIrp->Tail.Overlay.ListEntry );
155 }
156
157 SocketStateUnlock( FCB );
158
159 return STATUS_SUCCESS;
160 }
161
162 static NTSTATUS NTAPI PacketSocketSendComplete
163 ( PDEVICE_OBJECT DeviceObject,
164 PIRP Irp,
165 PVOID Context ) {
166 PAFD_FCB FCB = (PAFD_FCB)Context;
167
168 AFD_DbgPrint(MID_TRACE,("Called, status %x, %d bytes used\n",
169 Irp->IoStatus.Status,
170 Irp->IoStatus.Information));
171
172 /* It's ok if the FCB already died */
173 if( !SocketAcquireStateLock( FCB ) ) return STATUS_SUCCESS;
174
175 FCB->PollState |= AFD_EVENT_SEND;
176 PollReeval( FCB->DeviceExt, FCB->FileObject );
177
178 FCB->SendIrp.InFlightRequest = NULL;
179 /* Request is not in flight any longer */
180
181 if( FCB->State == SOCKET_STATE_CLOSED ) {
182 SocketStateUnlock( FCB );
183 DestroySocket( FCB );
184 return STATUS_SUCCESS;
185 }
186
187 SocketStateUnlock( FCB );
188
189 return STATUS_SUCCESS;
190 }
191
192 NTSTATUS STDCALL
193 AfdConnectedSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
194 PIO_STACK_LOCATION IrpSp, BOOLEAN Short) {
195 NTSTATUS Status = STATUS_SUCCESS;
196 PFILE_OBJECT FileObject = IrpSp->FileObject;
197 PAFD_FCB FCB = FileObject->FsContext;
198 PAFD_SEND_INFO SendReq;
199 UINT TotalBytesCopied = 0, i, CopySize = 0,
200 SpaceAvail = 0, TotalBytesEncountered = 0;
201
202 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
203
204 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp, FALSE );
205
206 FCB->EventsFired &= ~AFD_EVENT_SEND;
207
208 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
209 {
210 PAFD_SEND_INFO_UDP SendReq;
211 PTDI_CONNECTION_INFORMATION TargetAddress;
212
213 /* Check that the socket is bound */
214 if( FCB->State != SOCKET_STATE_BOUND )
215 return UnlockAndMaybeComplete( FCB, STATUS_UNSUCCESSFUL, Irp,
216 0, NULL, FALSE );
217
218 if( !(SendReq = LockRequest( Irp, IrpSp )) )
219 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0,
220 NULL, FALSE );
221
222 /* Must lock buffers before handing off user data */
223 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
224 SendReq->BufferCount,
225 NULL, NULL,
226 FALSE, FALSE );
227
228 TdiBuildConnectionInfo( &TargetAddress, FCB->RemoteAddress );
229
230 SocketCalloutEnter( FCB );
231
232 Status = TdiSendDatagram
233 ( &FCB->SendIrp.InFlightRequest,
234 FCB->AddressFile.Object,
235 SendReq->BufferArray[0].buf,
236 SendReq->BufferArray[0].len,
237 TargetAddress,
238 &FCB->SendIrp.Iosb,
239 PacketSocketSendComplete,
240 FCB );
241
242 SocketCalloutLeave( FCB );
243
244 ExFreePool( TargetAddress );
245
246 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
247
248 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
249
250 return UnlockAndMaybeComplete( FCB, Status, Irp,
251 SendReq->BufferArray[0].len,
252 NULL, TRUE );
253 }
254
255 if( !(SendReq = LockRequest( Irp, IrpSp )) )
256 return UnlockAndMaybeComplete
257 ( FCB, STATUS_NO_MEMORY, Irp, TotalBytesCopied, NULL, FALSE );
258
259 AFD_DbgPrint(MID_TRACE,("Socket state %d\n", FCB->State));
260
261 if( FCB->State != SOCKET_STATE_CONNECTED ) {
262 if( SendReq->AfdFlags & AFD_IMMEDIATE ) {
263 AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
264 return UnlockAndMaybeComplete
265 ( FCB, STATUS_CANT_WAIT, Irp, 0, NULL, TRUE );
266 } else {
267 AFD_DbgPrint(MID_TRACE,("Queuing request\n"));
268 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND );
269 }
270 }
271
272 AFD_DbgPrint(MID_TRACE,("We already have %d bytes waiting.\n",
273 FCB->Send.BytesUsed));
274
275 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
276 SendReq->BufferCount,
277 NULL, NULL,
278 FALSE, FALSE );
279
280 AFD_DbgPrint(MID_TRACE,("FCB->Send.BytesUsed = %d\n",
281 FCB->Send.BytesUsed));
282
283 if( !FCB->Send.BytesUsed ) {
284 SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
285
286 AFD_DbgPrint(MID_TRACE,("We can accept %d bytes\n",
287 SpaceAvail));
288
289 for( i = 0; FCB->Send.BytesUsed < FCB->Send.Size &&
290 i < SendReq->BufferCount; i++ ) {
291 CopySize = MIN( SpaceAvail,
292 SendReq->BufferArray[i].len );
293
294 TotalBytesEncountered += SendReq->BufferArray[i].len;
295
296 AFD_DbgPrint(MID_TRACE,("Copying Buffer %d, %x:%d to %x\n",
297 i,
298 SendReq->BufferArray[i].buf,
299 CopySize,
300 FCB->Send.Window + FCB->Send.BytesUsed));
301
302 RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed,
303 SendReq->BufferArray[i].buf,
304 CopySize );
305
306 FCB->Send.BytesUsed += CopySize;
307 TotalBytesCopied += CopySize;
308 SpaceAvail -= CopySize;
309 }
310
311 if( TotalBytesEncountered == 0 ) {
312 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
313
314 AFD_DbgPrint(MID_TRACE,("Empty send\n"));
315 return UnlockAndMaybeComplete
316 ( FCB, Status, Irp, TotalBytesCopied, NULL, TRUE );
317 }
318
319 AFD_DbgPrint(MID_TRACE,("Completed %d bytes\n", TotalBytesCopied));
320
321 if( TotalBytesCopied > 0 ) {
322 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
323
324 FCB->SendIrp.InFlightRequest = (PVOID)1; /* Placeholder */
325
326 SocketCalloutEnter( FCB );
327
328 Status = TdiSend( &FCB->SendIrp.InFlightRequest,
329 FCB->Connection.Object,
330 0,
331 FCB->Send.Window,
332 FCB->Send.BytesUsed,
333 &FCB->SendIrp.Iosb,
334 SendComplete,
335 FCB );
336
337 SocketCalloutLeave( FCB );
338
339 if( Status == STATUS_PENDING )
340 Status = STATUS_SUCCESS;
341
342 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x (%d)\n",
343 Status, TotalBytesCopied));
344
345 return UnlockAndMaybeComplete
346 ( FCB, Status, Irp, TotalBytesCopied, NULL, TRUE );
347 }
348 }
349
350 if( SendReq->AfdFlags & AFD_IMMEDIATE ) {
351 AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
352 return UnlockAndMaybeComplete
353 ( FCB, STATUS_CANT_WAIT, Irp, 0, NULL, TRUE );
354 } else {
355 AFD_DbgPrint(MID_TRACE,("Queuing request\n"));
356 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND );
357 }
358 }
359
360 NTSTATUS STDCALL
361 AfdPacketSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
362 PIO_STACK_LOCATION IrpSp) {
363 NTSTATUS Status = STATUS_SUCCESS;
364 PTDI_CONNECTION_INFORMATION TargetAddress;
365 PFILE_OBJECT FileObject = IrpSp->FileObject;
366 PAFD_FCB FCB = FileObject->FsContext;
367 PAFD_SEND_INFO_UDP SendReq;
368
369 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
370
371 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp, FALSE );
372
373 FCB->EventsFired &= ~AFD_EVENT_SEND;
374 FCB->PollState &= ~AFD_EVENT_SEND;
375
376 /* Check that the socket is bound */
377 if( FCB->State != SOCKET_STATE_BOUND )
378 return UnlockAndMaybeComplete
379 ( FCB, STATUS_UNSUCCESSFUL, Irp, 0, NULL, FALSE );
380 if( !(SendReq = LockRequest( Irp, IrpSp )) )
381 return UnlockAndMaybeComplete
382 ( FCB, STATUS_NO_MEMORY, Irp, 0, NULL, FALSE );
383
384 AFD_DbgPrint
385 (MID_TRACE,("RemoteAddress #%d Type %d\n",
386 ((PTRANSPORT_ADDRESS)SendReq->RemoteAddress)->
387 TAAddressCount,
388 ((PTRANSPORT_ADDRESS)SendReq->RemoteAddress)->
389 Address[0].AddressType));
390
391 TdiBuildConnectionInfo( &TargetAddress,
392 ((PTRANSPORT_ADDRESS)SendReq->RemoteAddress) );
393
394 /* Check the size of the Address given ... */
395
396 if( TargetAddress ) {
397 SocketCalloutEnter( FCB );
398
399 Status = TdiSendDatagram
400 ( &FCB->SendIrp.InFlightRequest,
401 FCB->AddressFile.Object,
402 SendReq->BufferArray[0].buf,
403 SendReq->BufferArray[0].len,
404 TargetAddress,
405 &FCB->SendIrp.Iosb,
406 PacketSocketSendComplete,
407 FCB );
408
409 SocketCalloutLeave( FCB );
410
411 ExFreePool( TargetAddress );
412 } else Status = STATUS_NO_MEMORY;
413
414 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
415
416 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
417
418 return UnlockAndMaybeComplete
419 ( FCB, Status, Irp, SendReq->BufferArray[0].len, NULL, TRUE );
420 }
421