More work on winsock stack (ping is now working)
[reactos.git] / reactos / drivers / net / afd / afd / dispatch.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Ancillary Function Driver
4 * FILE: afd/dispatch.c
5 * PURPOSE: File object dispatch functions
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISIONS:
8 * CSH 01/09-2000 Created
9 */
10 #include <afd.h>
11
12 NTSTATUS AfdDispBind(
13 PIRP Irp,
14 PIO_STACK_LOCATION IrpSp)
15 /*
16 * FUNCTION: Binds to an address
17 * ARGUMENTS:
18 * Irp = Pointer to I/O request packet
19 * IrpSp = Pointer to current stack location of Irp
20 * RETURNS:
21 * Status of operation
22 */
23 {
24 NTSTATUS Status;
25 UINT InputBufferLength;
26 UINT OutputBufferLength;
27 PFILE_REQUEST_BIND Request;
28 PFILE_REPLY_BIND Reply;
29 PAFDFCB FCB;
30
31 InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
32 OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
33
34 /* Validate parameters */
35 if ((InputBufferLength >= sizeof(FILE_REQUEST_BIND)) &&
36 (OutputBufferLength >= sizeof(FILE_REPLY_BIND))) {
37 FCB = IrpSp->FileObject->FsContext;
38
39 Request = (PFILE_REQUEST_BIND)Irp->AssociatedIrp.SystemBuffer;
40 Reply = (PFILE_REPLY_BIND)Irp->AssociatedIrp.SystemBuffer;
41
42 switch (Request->Name.sa_family) {
43 case AF_INET:
44 Status = TdiOpenAddressFileIPv4(&FCB->TdiDeviceName,
45 &Request->Name,
46 &FCB->TdiAddressObjectHandle,
47 &FCB->TdiAddressObject);
48 break;
49 default:
50 AFD_DbgPrint(MIN_TRACE, ("Bad address family (%d).\n", Request->Name.sa_family));
51 Status = STATUS_INVALID_PARAMETER;
52 }
53
54 if (NT_SUCCESS(Status)) {
55 AfdRegisterEventHandlers(FCB);
56 FCB->State = SOCKET_STATE_BOUND;
57 }
58 } else
59 Status = STATUS_INVALID_PARAMETER;
60
61 AFD_DbgPrint(MAX_TRACE, ("Status (0x%X).\n", Status));
62
63 return Status;
64 }
65
66
67 NTSTATUS AfdDispListen(
68 PIRP Irp,
69 PIO_STACK_LOCATION IrpSp)
70 /*
71 * FUNCTION: Starts listening for connections
72 * ARGUMENTS:
73 * Irp = Pointer to I/O request packet
74 * IrpSp = Pointer to current stack location of Irp
75 * RETURNS:
76 * Status of operation
77 */
78 {
79 NTSTATUS Status;
80 UINT InputBufferLength;
81 UINT OutputBufferLength;
82 PFILE_REQUEST_LISTEN Request;
83 PFILE_REPLY_LISTEN Reply;
84 PAFDFCB FCB;
85
86 InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
87 OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
88
89 /* Validate parameters */
90 if ((InputBufferLength >= sizeof(FILE_REQUEST_LISTEN)) &&
91 (OutputBufferLength >= sizeof(FILE_REPLY_LISTEN))) {
92 FCB = IrpSp->FileObject->FsContext;
93
94 Request = (PFILE_REQUEST_LISTEN)Irp->AssociatedIrp.SystemBuffer;
95 Reply = (PFILE_REPLY_LISTEN)Irp->AssociatedIrp.SystemBuffer;
96 } else
97 Status = STATUS_INVALID_PARAMETER;
98
99 AFD_DbgPrint(MAX_TRACE, ("Status (0x%X).\n", Status));
100
101 return Status;
102 }
103
104
105 NTSTATUS AfdDispSendTo(
106 PIRP Irp,
107 PIO_STACK_LOCATION IrpSp)
108 /*
109 * FUNCTION: Sends data to an address
110 * ARGUMENTS:
111 * Irp = Pointer to I/O request packet
112 * IrpSp = Pointer to current stack location of Irp
113 * RETURNS:
114 * Status of operation
115 */
116 {
117 NTSTATUS Status;
118 UINT InputBufferLength;
119 UINT OutputBufferLength;
120 PFILE_REQUEST_SENDTO Request;
121 PFILE_REPLY_SENDTO Reply;
122 PAFDFCB FCB;
123 PVOID SystemVirtualAddress;
124 PVOID DataBufferAddress;
125 ULONG BufferSize;
126 ULONG BytesCopied;
127 PMDL Mdl;
128
129 InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
130 OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
131
132 /* Validate parameters */
133 if ((InputBufferLength >= sizeof(FILE_REQUEST_SENDTO)) &&
134 (OutputBufferLength >= sizeof(FILE_REPLY_SENDTO))) {
135
136 AFD_DbgPrint(MAX_TRACE, ("FileObject at (0x%X).\n", IrpSp->FileObject));
137 AFD_DbgPrint(MAX_TRACE, ("FCB at (0x%X).\n", IrpSp->FileObject->FsContext));
138 AFD_DbgPrint(MAX_TRACE, ("CCB at (0x%X).\n", IrpSp->FileObject->FsContext2));
139
140 FCB = IrpSp->FileObject->FsContext;
141 Request = (PFILE_REQUEST_SENDTO)Irp->AssociatedIrp.SystemBuffer;
142 Reply = (PFILE_REPLY_SENDTO)Irp->AssociatedIrp.SystemBuffer;
143 BufferSize = WSABufferSize(Request->Buffers, Request->BufferCount);
144
145
146 /* FIXME: Should we handle special cases here? */
147 if ((FCB->SocketType == SOCK_RAW) && (FCB->AddressFamily == AF_INET)) {
148 BufferSize += sizeof(IPv4_HEADER);
149 }
150
151
152 if (BufferSize != 0) {
153 AFD_DbgPrint(MAX_TRACE, ("Allocating %d bytes for send buffer.\n", BufferSize));
154 SystemVirtualAddress = ExAllocatePool(NonPagedPool, BufferSize);
155 if (!SystemVirtualAddress) {
156 return STATUS_INSUFFICIENT_RESOURCES;
157 }
158
159 /* FIXME: Should we handle special cases here? */
160 if ((FCB->SocketType == SOCK_RAW) && (FCB->AddressFamily == AF_INET)) {
161 DataBufferAddress = SystemVirtualAddress + sizeof(IPv4_HEADER);
162
163 /* FIXME: Should TCP/IP driver assign source address for raw sockets? */
164 ((PSOCKADDR_IN)&FCB->SocketName)->sin_addr.S_un.S_addr = 0x0100007F;
165
166 BuildIPv4Header(
167 (PIPv4_HEADER)SystemVirtualAddress,
168 BufferSize,
169 FCB->Protocol,
170 &FCB->SocketName,
171 &Request->To);
172 } else {
173 DataBufferAddress = SystemVirtualAddress;
174 }
175
176 Status = MergeWSABuffers(
177 Request->Buffers,
178 Request->BufferCount,
179 DataBufferAddress,
180 BufferSize,
181 &BytesCopied);
182 if (!NT_SUCCESS(Status)) {
183 AFD_DbgPrint(MAX_TRACE, ("Status (0x%X).\n", Status));
184 return Status;
185 }
186 } else {
187 SystemVirtualAddress = NULL;
188 BytesCopied = 0;
189 }
190
191 Mdl = IoAllocateMdl(
192 SystemVirtualAddress, /* Virtual address of buffer */
193 BufferSize, /* Length of buffer */
194 FALSE, /* Not secondary */
195 FALSE, /* Don't charge quota */
196 NULL); /* Don't use IRP */
197 if (!Mdl) {
198 ExFreePool(SystemVirtualAddress);
199 return STATUS_INSUFFICIENT_RESOURCES;
200 }
201
202 MmBuildMdlForNonPagedPool(Mdl);
203
204 AFD_DbgPrint(MAX_TRACE, ("System virtual address is (0x%X).\n", SystemVirtualAddress));
205 AFD_DbgPrint(MAX_TRACE, ("MDL for data buffer is at (0x%X).\n", Mdl));
206
207 AFD_DbgPrint(MAX_TRACE, ("AFD.SYS: NDIS data buffer is at (0x%X).\n", Mdl));
208 AFD_DbgPrint(MAX_TRACE, ("NDIS data buffer MdlFlags is (0x%X).\n", Mdl->MdlFlags));
209 AFD_DbgPrint(MAX_TRACE, ("NDIS data buffer Next is at (0x%X).\n", Mdl->Next));
210 AFD_DbgPrint(MAX_TRACE, ("NDIS data buffer Size is (0x%X).\n", Mdl->Size));
211 AFD_DbgPrint(MAX_TRACE, ("NDIS data buffer MappedSystemVa is (0x%X).\n", Mdl->MappedSystemVa));
212 AFD_DbgPrint(MAX_TRACE, ("NDIS data buffer StartVa is (0x%X).\n", Mdl->StartVa));
213 AFD_DbgPrint(MAX_TRACE, ("NDIS data buffer ByteCount is (0x%X).\n", Mdl->ByteCount));
214 AFD_DbgPrint(MAX_TRACE, ("NDIS data buffer ByteOffset is (0x%X).\n", Mdl->ByteOffset));
215
216 #if 0
217 #ifdef _MSC_VER
218 try {
219 #endif
220 MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
221 #ifdef _MSC_VER
222 } except(EXCEPTION_EXECUTE_HANDLER) {
223 AFD_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
224 IoFreeMdl(Mdl);
225 if (BufferSize != 0) {
226 ExFreePool(SystemVirtualAddress);
227 }
228 return STATUS_UNSUCCESSFUL;
229 }
230 #endif
231 #endif
232
233 Status = TdiSendDatagram(FCB->TdiAddressObject,
234 &Request->To,
235 Mdl,
236 BufferSize);
237
238 /* FIXME: Assumes synchronous operation */
239 #if 0
240 MmUnlockPages(Mdl);
241 #endif
242
243 IoFreeMdl(Mdl);
244
245 if (BufferSize != 0) {
246 ExFreePool(SystemVirtualAddress);
247 }
248
249 Reply->NumberOfBytesSent = BufferSize;
250 Reply->Status = NO_ERROR;
251 } else
252 Status = STATUS_INVALID_PARAMETER;
253
254 AFD_DbgPrint(MAX_TRACE, ("Status (0x%X).\n", Status));
255
256 return Status;
257 }
258
259
260 NTSTATUS AfdDispRecvFrom(
261 PIRP Irp,
262 PIO_STACK_LOCATION IrpSp)
263 /*
264 * FUNCTION: Receives data from an address
265 * ARGUMENTS:
266 * Irp = Pointer to I/O request packet
267 * IrpSp = Pointer to current stack location of Irp
268 * RETURNS:
269 * Status of operation
270 */
271 {
272 NTSTATUS Status;
273 UINT InputBufferLength;
274 UINT OutputBufferLength;
275 PFILE_REQUEST_RECVFROM Request;
276 PFILE_REPLY_RECVFROM Reply;
277 PAFD_READ_REQUEST ReadRequest;
278 DWORD NumberOfBytesRecvd;
279 KIRQL OldIrql;
280 PAFDFCB FCB;
281
282 AFD_DbgPrint(MAX_TRACE, ("Called.\n"));
283
284 InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
285 OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
286
287 /* Validate parameters */
288 if ((InputBufferLength >= sizeof(FILE_REQUEST_RECVFROM)) &&
289 (OutputBufferLength >= sizeof(FILE_REPLY_RECVFROM))) {
290 FCB = IrpSp->FileObject->FsContext;
291
292 Request = (PFILE_REQUEST_RECVFROM)Irp->AssociatedIrp.SystemBuffer;
293 Reply = (PFILE_REPLY_RECVFROM)Irp->AssociatedIrp.SystemBuffer;
294
295 KeAcquireSpinLock(&FCB->ReceiveQueueLock, &OldIrql);
296 if (IsListEmpty(&FCB->ReceiveQueue)) {
297 KeReleaseSpinLock(&FCB->ReceiveQueueLock, OldIrql);
298
299 /* Queue a read request and return STATUS_PENDING */
300
301 AFD_DbgPrint(MAX_TRACE, ("Queueing read request.\n"));
302
303 /*ReadRequest = (PAFD_READ_REQUEST)ExAllocateFromNPagedLookasideList(
304 &ReadRequestLookasideList);*/
305 ReadRequest = (PAFD_READ_REQUEST)ExAllocatePool(
306 NonPagedPool,
307 sizeof(AFD_READ_REQUEST));
308 if (ReadRequest) {
309 ReadRequest->Irp = Irp;
310 ReadRequest->RecvFromRequest = Request;
311 ReadRequest->RecvFromReply = Reply;
312
313 ExInterlockedInsertTailList(
314 &FCB->ReadRequestQueue,
315 &ReadRequest->ListEntry,
316 &FCB->ReadRequestQueueLock);
317 Status = STATUS_PENDING;
318 } else {
319 Status = STATUS_INSUFFICIENT_RESOURCES;
320 }
321 } else {
322 AFD_DbgPrint(MAX_TRACE, ("Satisfying read request.\n"));
323
324 /* Satisfy the request at once */
325 Status = FillWSABuffers(
326 FCB,
327 Request->Buffers,
328 Request->BufferCount,
329 &NumberOfBytesRecvd);
330 KeReleaseSpinLock(&FCB->ReceiveQueueLock, OldIrql);
331 Reply->Status = NO_ERROR;
332 Reply->NumberOfBytesRecvd = NumberOfBytesRecvd;
333 AFD_DbgPrint(MAX_TRACE, ("NumberOfBytesRecvd (0x%X).\n",
334 NumberOfBytesRecvd));
335 }
336 } else {
337 Status = STATUS_INVALID_PARAMETER;
338 }
339
340 AFD_DbgPrint(MAX_TRACE, ("Status (0x%X).\n", Status));
341
342 return Status;
343 }
344
345
346 typedef enum {
347 soRead,
348 soWrite,
349 soExcept
350 } SelectOperation;
351
352
353 DWORD AfdDispSelectEx(
354 LPFD_SET FDSet,
355 SelectOperation Operation)
356 {
357 NTSTATUS Status;
358 PAFDFCB Current;
359 KIRQL OldIrql;
360 DWORD Count;
361 ULONG i;
362
363 AFD_DbgPrint(MAX_TRACE, ("FDSet (0x%X) Operation (0x%X).\n",
364 FDSet, Operation));
365
366 AFD_DbgPrint(MAX_TRACE, ("FDSet->fd_count (0x%X).\n", FDSet->fd_count));
367
368 Count = 0;
369 for (i = 0; i < FDSet->fd_count; i++) {
370 Status = ObReferenceObjectByHandle(
371 (HANDLE)FDSet->fd_array[i],
372 0,
373 IoFileObjectType,
374 KernelMode,
375 (PVOID*)&Current,
376 NULL);
377 if (NT_SUCCESS(Status)) {
378
379 switch (Operation) {
380 case soRead:
381 KeAcquireSpinLock(&Current->ReceiveQueueLock, &OldIrql);
382 if (!IsListEmpty(&Current->ReceiveQueue)) {
383 AFD_DbgPrint(MAX_TRACE, ("Socket is readable.\n"));
384 Count++;
385 }
386 KeReleaseSpinLock(&Current->ReceiveQueueLock, OldIrql);
387 break;
388 case soWrite:
389 /* FIXME: How can we check for writability? */
390 Count++;
391 break;
392 case soExcept:
393 /* FIXME: What is this? */
394 Count++;
395 break;
396 }
397
398 ObDereferenceObject(Current);
399 }
400 }
401
402 return Count;
403 }
404
405 NTSTATUS AfdDispSelect(
406 PIRP Irp,
407 PIO_STACK_LOCATION IrpSp)
408 /*
409 * FUNCTION: Checks if sockets have data in the receive buffers
410 * ARGUMENTS:
411 * Irp = Pointer to I/O request packet
412 * IrpSp = Pointer to current stack location of Irp
413 * RETURNS:
414 * Status of operation
415 */
416 {
417 NTSTATUS Status;
418 UINT InputBufferLength;
419 UINT OutputBufferLength;
420 PFILE_REQUEST_SELECT Request;
421 PFILE_REPLY_SELECT Reply;
422 DWORD SocketCount;
423 PAFDFCB FCB;
424
425 InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
426 OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
427
428 /* Validate parameters */
429 if ((InputBufferLength >= sizeof(FILE_REQUEST_SELECT)) &&
430 (OutputBufferLength >= sizeof(FILE_REPLY_SELECT))) {
431 FCB = IrpSp->FileObject->FsContext;
432
433 Request = (PFILE_REQUEST_SELECT)Irp->AssociatedIrp.SystemBuffer;
434 Reply = (PFILE_REPLY_SELECT)Irp->AssociatedIrp.SystemBuffer;
435
436 AFD_DbgPrint(MAX_TRACE, ("R (0x%X) W (0x%X).\n",
437 Request->ReadFDSet, Request->WriteFDSet));
438
439 SocketCount = 0;
440
441 if (Request->ReadFDSet) {
442 AFD_DbgPrint(MAX_TRACE, ("Read.\n"));
443 SocketCount += AfdDispSelectEx(Request->ReadFDSet, soRead);
444 }
445 if (Request->WriteFDSet) {
446 AFD_DbgPrint(MAX_TRACE, ("Write.\n"));
447 SocketCount += AfdDispSelectEx(Request->WriteFDSet, soWrite);
448 }
449 if (Request->ExceptFDSet) {
450 SocketCount += AfdDispSelectEx(Request->ExceptFDSet, soExcept);
451 }
452
453 AFD_DbgPrint(MAX_TRACE, ("Sockets selected (0x%X).\n", SocketCount));
454
455 Reply->Status = NO_ERROR;
456 Reply->SocketCount = SocketCount;
457 Status = STATUS_SUCCESS;
458 } else
459 Status = STATUS_INVALID_PARAMETER;
460
461 AFD_DbgPrint(MAX_TRACE, ("Status (0x%X).\n", Status));
462
463 return Status;
464 }
465
466 /* EOF */