Amd64/misc 64bit fixes (#236)
[reactos.git] / drivers / network / ndisuio / ioctl.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS User I/O driver
4 * FILE: ioctl.c
5 * PURPOSE: IOCTL handling
6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
7 */
8
9 #include "ndisuio.h"
10
11 //#define NDEBUG
12 #include <debug.h>
13
14 static
15 NTSTATUS
16 WaitForBind(PIRP Irp, PIO_STACK_LOCATION IrpSp)
17 {
18 /* I've seen several code samples that use this IOCTL but there's
19 * no official documentation on it. I'm just implementing it as a no-op
20 * right now because I don't see any reason we need it. We handle an open
21 * and bind just fine with IRP_MJ_CREATE and IOCTL_NDISUIO_OPEN_DEVICE */
22 DPRINT("Wait for bind complete\n");
23
24 Irp->IoStatus.Status = STATUS_SUCCESS;
25 Irp->IoStatus.Information = 0;
26
27 IoCompleteRequest(Irp, IO_NO_INCREMENT);
28
29 return STATUS_SUCCESS;
30 }
31
32 static
33 NTSTATUS
34 QueryBinding(PIRP Irp, PIO_STACK_LOCATION IrpSp)
35 {
36 PNDISUIO_ADAPTER_CONTEXT AdapterContext = NULL;
37 PNDISUIO_QUERY_BINDING QueryBinding = Irp->AssociatedIrp.SystemBuffer;
38 ULONG BindingLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
39 NTSTATUS Status;
40 PLIST_ENTRY CurrentEntry;
41 KIRQL OldIrql;
42 ULONG i;
43 ULONG BytesCopied = 0;
44
45 if (QueryBinding && BindingLength >= sizeof(NDISUIO_QUERY_BINDING))
46 {
47 KeAcquireSpinLock(&GlobalAdapterListLock, &OldIrql);
48 i = 0;
49 CurrentEntry = GlobalAdapterList.Flink;
50 while (CurrentEntry != &GlobalAdapterList)
51 {
52 if (i == QueryBinding->BindingIndex)
53 {
54 AdapterContext = CONTAINING_RECORD(CurrentEntry, NDISUIO_ADAPTER_CONTEXT, ListEntry);
55 break;
56 }
57 i++;
58 CurrentEntry = CurrentEntry->Flink;
59 }
60 KeReleaseSpinLock(&GlobalAdapterListLock, OldIrql);
61 if (AdapterContext)
62 {
63 DPRINT("Query binding for index %d is adapter %wZ\n", i, &AdapterContext->DeviceName);
64 BytesCopied = sizeof(NDISUIO_QUERY_BINDING);
65 if (AdapterContext->DeviceName.Length <= BindingLength - BytesCopied)
66 {
67 QueryBinding->DeviceNameOffset = BytesCopied;
68 QueryBinding->DeviceNameLength = AdapterContext->DeviceName.Length;
69 RtlCopyMemory((PUCHAR)QueryBinding + QueryBinding->DeviceNameOffset,
70 AdapterContext->DeviceName.Buffer,
71 QueryBinding->DeviceNameLength);
72 BytesCopied += AdapterContext->DeviceName.Length;
73
74 /* FIXME: Copy description too */
75 QueryBinding->DeviceDescrOffset = BytesCopied;
76 QueryBinding->DeviceDescrLength = 0;
77
78 /* Successful */
79 Status = STATUS_SUCCESS;
80 }
81 else
82 {
83 /* Not enough buffer space */
84 Status = STATUS_BUFFER_TOO_SMALL;
85 }
86 }
87 else
88 {
89 /* Invalid index */
90 Status = STATUS_NO_MORE_ENTRIES;
91 }
92 }
93 else
94 {
95 /* Invalid parameters */
96 Status = STATUS_INVALID_PARAMETER;
97 }
98
99 Irp->IoStatus.Status = Status;
100 Irp->IoStatus.Information = BytesCopied;
101
102 IoCompleteRequest(Irp, IO_NO_INCREMENT);
103
104 return Status;
105 }
106
107 #if 0
108 static
109 NTSTATUS
110 CancelPacketRead(PIRP Irp, PIO_STACK_LOCATION IrpSp)
111 {
112 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
113 PNDISUIO_PACKET_ENTRY PacketEntry;
114 NTSTATUS Status;
115
116 /* Indicate a 0-byte packet on the queue so one read returns 0 */
117 PacketEntry = ExAllocatePool(PagedPool, sizeof(NDISUIO_PACKET_ENTRY));
118 if (PacketEntry)
119 {
120 PacketEntry->PacketLength = 0;
121
122 ExInterlockedInsertHeadList(&AdapterContext->PacketList,
123 &PacketEntry->ListEntry,
124 &AdapterContext->Spinlock);
125
126 KeSetEvent(&AdapterContext->PacketReadEvent, IO_NO_INCREMENT, FALSE);
127
128 Status = STATUS_SUCCESS;
129 }
130 else
131 {
132 Status = STATUS_NO_MEMORY;
133 }
134
135 Irp->IoStatus.Status = Status;
136 Irp->IoStatus.Information = 0;
137
138 IoCompleteRequest(Irp, IO_NO_INCREMENT);
139
140 return Status;
141 }
142 #endif
143
144 static
145 NTSTATUS
146 SetAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
147 {
148 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
149 PNDISUIO_SET_OID SetOidRequest;
150 NDIS_REQUEST Request;
151 ULONG RequestLength;
152 NDIS_STATUS Status;
153
154 Irp->IoStatus.Information = 0;
155
156 SetOidRequest = Irp->AssociatedIrp.SystemBuffer;
157 RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
158 if (SetOidRequest && RequestLength >= sizeof(NDIS_OID))
159 {
160 /* Setup the NDIS request */
161 Request.RequestType = NdisRequestSetInformation;
162 Request.DATA.SET_INFORMATION.Oid = SetOidRequest->Oid;
163 Request.DATA.SET_INFORMATION.InformationBufferLength = RequestLength - sizeof(NDIS_OID);
164 if (Request.DATA.SET_INFORMATION.InformationBufferLength != 0)
165 {
166 Request.DATA.SET_INFORMATION.InformationBuffer = SetOidRequest->Data;
167 }
168 else
169 {
170 Request.DATA.SET_INFORMATION.InformationBuffer = NULL;
171 }
172 Request.DATA.SET_INFORMATION.BytesRead = 0;
173
174 DPRINT("Setting OID 0x%x on adapter %wZ\n", SetOidRequest->Oid, &AdapterContext->DeviceName);
175
176 /* Dispatch the request */
177 NdisRequest(&Status,
178 AdapterContext->BindingHandle,
179 &Request);
180
181 /* Wait for the request */
182 if (Status == NDIS_STATUS_PENDING)
183 {
184 KeWaitForSingleObject(&AdapterContext->AsyncEvent,
185 Executive,
186 KernelMode,
187 FALSE,
188 NULL);
189 Status = AdapterContext->AsyncStatus;
190 }
191
192 /* Return the bytes read */
193 if (Status == NDIS_STATUS_INVALID_LENGTH ||
194 Status == NDIS_STATUS_BUFFER_TOO_SHORT)
195 {
196 Status = STATUS_BUFFER_TOO_SMALL;
197 }
198 else if (Status == NDIS_STATUS_SUCCESS)
199 {
200 Irp->IoStatus.Information = sizeof(NDIS_OID) + Request.DATA.SET_INFORMATION.BytesRead;
201 }
202
203 DPRINT("Final request status: 0x%x (%d)\n", Status, Irp->IoStatus.Information);
204 }
205 else
206 {
207 /* Bad parameters */
208 Status = STATUS_INVALID_PARAMETER;
209 }
210
211 Irp->IoStatus.Status = Status;
212
213 IoCompleteRequest(Irp, IO_NO_INCREMENT);
214
215 return Status;
216 }
217
218 static
219 NTSTATUS
220 QueryAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
221 {
222 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
223 PNDISUIO_QUERY_OID QueryOidRequest;
224 NDIS_REQUEST Request;
225 ULONG RequestLength;
226 NDIS_STATUS Status;
227
228 Irp->IoStatus.Information = 0;
229
230 QueryOidRequest = Irp->AssociatedIrp.SystemBuffer;
231 RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
232 if (QueryOidRequest && RequestLength >= sizeof(NDIS_OID))
233 {
234 /* Setup the NDIS request */
235 Request.RequestType = NdisRequestQueryInformation;
236 Request.DATA.QUERY_INFORMATION.Oid = QueryOidRequest->Oid;
237 Request.DATA.QUERY_INFORMATION.InformationBufferLength = RequestLength - sizeof(NDIS_OID);
238 if (Request.DATA.QUERY_INFORMATION.InformationBufferLength != 0)
239 {
240 Request.DATA.QUERY_INFORMATION.InformationBuffer = QueryOidRequest->Data;
241 }
242 else
243 {
244 Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL;
245 }
246 Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
247
248 DPRINT("Querying OID 0x%x on adapter %wZ\n", QueryOidRequest->Oid, &AdapterContext->DeviceName);
249
250 /* Dispatch the request */
251 NdisRequest(&Status,
252 AdapterContext->BindingHandle,
253 &Request);
254
255 /* Wait for the request */
256 if (Status == NDIS_STATUS_PENDING)
257 {
258 KeWaitForSingleObject(&AdapterContext->AsyncEvent,
259 Executive,
260 KernelMode,
261 FALSE,
262 NULL);
263 Status = AdapterContext->AsyncStatus;
264 }
265
266 /* Return the bytes written */
267 if (Status == NDIS_STATUS_INVALID_LENGTH ||
268 Status == NDIS_STATUS_BUFFER_TOO_SHORT)
269 {
270 Status = STATUS_BUFFER_TOO_SMALL;
271 }
272 else if (Status == NDIS_STATUS_SUCCESS)
273 {
274 Irp->IoStatus.Information = sizeof(NDIS_OID) + Request.DATA.QUERY_INFORMATION.BytesWritten;
275 }
276
277 DPRINT("Final request status: 0x%x (%d)\n", Status, Irp->IoStatus.Information);
278 }
279 else
280 {
281 /* Bad parameters */
282 Status = STATUS_INVALID_PARAMETER;
283 }
284
285 Irp->IoStatus.Status = Status;
286
287 IoCompleteRequest(Irp, IO_NO_INCREMENT);
288
289 return Status;
290 }
291
292 static
293 NTSTATUS
294 OpenDeviceReadWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
295 {
296 PFILE_OBJECT FileObject = IrpSp->FileObject;
297 UNICODE_STRING DeviceName;
298 ULONG NameLength;
299 NTSTATUS Status;
300 PNDISUIO_ADAPTER_CONTEXT AdapterContext;
301 PNDISUIO_OPEN_ENTRY OpenEntry;
302 KIRQL OldIrql;
303
304 NameLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
305 if (NameLength != 0)
306 {
307 DeviceName.MaximumLength = DeviceName.Length = NameLength;
308 DeviceName.Buffer = Irp->AssociatedIrp.SystemBuffer;
309
310 /* Check if this already has a context */
311 AdapterContext = FindAdapterContextByName(&DeviceName);
312 if (AdapterContext != NULL)
313 {
314 DPRINT("Binding file object 0x%x to device %wZ\n", FileObject, &AdapterContext->DeviceName);
315
316 /* Reference the adapter context */
317 KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql);
318 if (AdapterContext->OpenCount != 0)
319 {
320 /* An open for read-write is exclusive,
321 * so we can't have any other open handles */
322 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
323 Status = STATUS_INVALID_PARAMETER;
324 }
325 else
326 {
327 /* Add a reference */
328 ReferenceAdapterContext(AdapterContext);
329 Status = STATUS_SUCCESS;
330 }
331 }
332 else
333 {
334 /* Invalid device name */
335 Status = STATUS_INVALID_PARAMETER;
336 }
337
338 /* Check that the bind succeeded */
339 if (NT_SUCCESS(Status))
340 {
341 OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry));
342 if (OpenEntry)
343 {
344 /* Set the file object pointer */
345 OpenEntry->FileObject = FileObject;
346
347 /* Set the permissions */
348 OpenEntry->WriteOnly = FALSE;
349
350 /* Associate this FO with the adapter */
351 FileObject->FsContext = AdapterContext;
352 FileObject->FsContext2 = OpenEntry;
353
354 /* Add it to the adapter's list */
355 InsertTailList(&AdapterContext->OpenEntryList,
356 &OpenEntry->ListEntry);
357
358 /* Success */
359 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
360 Status = STATUS_SUCCESS;
361 }
362 else
363 {
364 /* Remove the reference we added */
365 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
366 DereferenceAdapterContextWithOpenEntry(AdapterContext, NULL);
367 Status = STATUS_NO_MEMORY;
368 }
369 }
370 }
371 else
372 {
373 /* Invalid device name */
374 Status = STATUS_INVALID_PARAMETER;
375 }
376
377 Irp->IoStatus.Status = Status;
378 Irp->IoStatus.Information = 0;
379
380 IoCompleteRequest(Irp, IO_NO_INCREMENT);
381
382 return Status;
383 }
384
385 #if 0
386 static
387 NTSTATUS
388 OpenDeviceWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
389 {
390 PFILE_OBJECT FileObject = IrpSp->FileObject;
391 UNICODE_STRING DeviceName;
392 ULONG NameLength;
393 NTSTATUS Status;
394 PNDISUIO_ADAPTER_CONTEXT AdapterContext;
395 PNDISUIO_OPEN_ENTRY OpenEntry;
396 KIRQL OldIrql;
397
398 NameLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
399 if (NameLength != 0)
400 {
401 DeviceName.MaximumLength = DeviceName.Length = NameLength;
402 DeviceName.Buffer = Irp->AssociatedIrp.SystemBuffer;
403
404 /* Check if this already has a context */
405 AdapterContext = FindAdapterContextByName(&DeviceName);
406 if (AdapterContext != NULL)
407 {
408 /* Reference the adapter context */
409 KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql);
410 ReferenceAdapterContext(AdapterContext);
411 Status = STATUS_SUCCESS;
412 }
413 else
414 {
415 /* Invalid device name */
416 Status = STATUS_INVALID_PARAMETER;
417 }
418
419 /* Check that the bind succeeded */
420 if (NT_SUCCESS(Status))
421 {
422 OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry));
423 if (OpenEntry)
424 {
425 /* Set the file object pointer */
426 OpenEntry->FileObject = FileObject;
427
428 /* Associate this FO with the adapter */
429 FileObject->FsContext = AdapterContext;
430 FileObject->FsContext2 = OpenEntry;
431
432 /* Set permissions */
433 OpenEntry->WriteOnly = TRUE;
434
435 /* Add it to the adapter's list */
436 InsertTailList(&AdapterContext->OpenEntryList,
437 &OpenEntry->ListEntry);
438
439 /* Success */
440 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
441 Status = STATUS_SUCCESS;
442 }
443 else
444 {
445 /* Remove the reference we added */
446 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
447 DereferenceAdapterContext(AdapterContext, NULL);
448 Status = STATUS_NO_MEMORY;
449 }
450 }
451 }
452 else
453 {
454 /* Invalid device name */
455 Status = STATUS_INVALID_PARAMETER;
456 }
457
458 Irp->IoStatus.Status = Status;
459 Irp->IoStatus.Information = 0;
460
461 IoCompleteRequest(Irp, IO_NO_INCREMENT);
462
463 return Status;
464 }
465 #endif
466
467 NTSTATUS
468 NTAPI
469 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject,
470 PIRP Irp)
471 {
472 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
473 PNDISUIO_OPEN_ENTRY OpenEntry;
474
475 ASSERT(DeviceObject == GlobalDeviceObject);
476
477 /* Handle open IOCTLs first */
478 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
479 {
480 case IOCTL_NDISUIO_OPEN_DEVICE:
481 return OpenDeviceReadWrite(Irp, IrpSp);
482 #if 0
483 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE:
484 return OpenDeviceWrite(Irp, IrpSp);
485 #endif
486 case IOCTL_NDISUIO_BIND_WAIT:
487 return WaitForBind(Irp, IrpSp);
488
489 case IOCTL_NDISUIO_QUERY_BINDING:
490 return QueryBinding(Irp, IrpSp);
491
492 default:
493 /* Fail if this file object has no adapter associated */
494 if (IrpSp->FileObject->FsContext == NULL)
495 {
496 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
497 Irp->IoStatus.Information = 0;
498 IoCompleteRequest(Irp, IO_NO_INCREMENT);
499
500 return STATUS_INVALID_PARAMETER;
501 }
502
503 /* Now handle write IOCTLs */
504 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
505 {
506 case IOCTL_NDISUIO_SET_OID_VALUE:
507 return SetAdapterOid(Irp, IrpSp);
508
509 default:
510 /* Check that we have read permissions */
511 OpenEntry = IrpSp->FileObject->FsContext2;
512 if (OpenEntry->WriteOnly)
513 {
514 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
515 Irp->IoStatus.Information = 0;
516 IoCompleteRequest(Irp, IO_NO_INCREMENT);
517
518 return STATUS_INVALID_PARAMETER;
519 }
520
521 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
522 {
523 #if 0
524 case IOCTL_CANCEL_READ:
525 return CancelPacketRead(Irp, IrpSp);
526 #endif
527
528 case IOCTL_NDISUIO_QUERY_OID_VALUE:
529 return QueryAdapterOid(Irp, IrpSp);
530
531 default:
532 DPRINT1("Unimplemented\n");
533 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
534 Irp->IoStatus.Information = 0;
535 IoCompleteRequest(Irp, IO_NO_INCREMENT);
536 return STATUS_NOT_IMPLEMENTED;
537 }
538 }
539 break;
540 }
541 }