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; 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 break; 54 i++; 55 CurrentEntry = CurrentEntry->Flink; 56 } 57 KeReleaseSpinLock(&GlobalAdapterListLock, OldIrql); 58 if (i == QueryBinding->BindingIndex) 59 { 60 AdapterContext = CONTAINING_RECORD(CurrentEntry, NDISUIO_ADAPTER_CONTEXT, ListEntry); 61 DPRINT("Query binding for index %d is adapter %wZ\n", i, &AdapterContext->DeviceName); 62 BytesCopied = sizeof(NDISUIO_QUERY_BINDING); 63 if (AdapterContext->DeviceName.Length <= BindingLength - BytesCopied) 64 { 65 BytesCopied += AdapterContext->DeviceName.Length; 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 73 /* FIXME: Copy description too */ 74 QueryBinding->DeviceDescrOffset = BytesCopied; 75 QueryBinding->DeviceDescrLength = 0; 76 77 /* Successful */ 78 Status = STATUS_SUCCESS; 79 } 80 else 81 { 82 /* Not enough buffer space */ 83 Status = STATUS_BUFFER_TOO_SMALL; 84 } 85 } 86 else 87 { 88 /* Invalid index */ 89 Status = STATUS_NO_MORE_ENTRIES; 90 } 91 } 92 else 93 { 94 /* Invalid parameters */ 95 Status = STATUS_INVALID_PARAMETER; 96 } 97 98 Irp->IoStatus.Status = Status; 99 Irp->IoStatus.Information = BytesCopied; 100 101 IoCompleteRequest(Irp, IO_NO_INCREMENT); 102 103 return Status; 104 } 105 106 #if 0 107 static 108 NTSTATUS 109 CancelPacketRead(PIRP Irp, PIO_STACK_LOCATION IrpSp) 110 { 111 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; 112 PNDISUIO_PACKET_ENTRY PacketEntry; 113 NTSTATUS Status; 114 115 /* Indicate a 0-byte packet on the queue so one read returns 0 */ 116 PacketEntry = ExAllocatePool(PagedPool, sizeof(NDISUIO_PACKET_ENTRY)); 117 if (PacketEntry) 118 { 119 PacketEntry->PacketLength = 0; 120 121 ExInterlockedInsertHeadList(&AdapterContext->PacketList, 122 &PacketEntry->ListEntry, 123 &AdapterContext->Spinlock); 124 125 KeSetEvent(&AdapterContext->PacketReadEvent, IO_NO_INCREMENT, FALSE); 126 127 Status = STATUS_SUCCESS; 128 } 129 else 130 { 131 Status = STATUS_NO_MEMORY; 132 } 133 134 Irp->IoStatus.Status = Status; 135 Irp->IoStatus.Information = 0; 136 137 IoCompleteRequest(Irp, IO_NO_INCREMENT); 138 139 return Status; 140 } 141 #endif 142 143 static 144 NTSTATUS 145 SetAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp) 146 { 147 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; 148 PNDISUIO_SET_OID SetOidRequest; 149 NDIS_REQUEST Request; 150 ULONG RequestLength; 151 NDIS_STATUS Status; 152 153 Irp->IoStatus.Information = 0; 154 155 SetOidRequest = Irp->AssociatedIrp.SystemBuffer; 156 RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; 157 if (SetOidRequest && RequestLength >= sizeof(NDIS_OID)) 158 { 159 /* Setup the NDIS request */ 160 Request.RequestType = NdisRequestSetInformation; 161 Request.DATA.SET_INFORMATION.Oid = SetOidRequest->Oid; 162 Request.DATA.SET_INFORMATION.InformationBuffer = SetOidRequest->Data; 163 Request.DATA.SET_INFORMATION.InformationBufferLength = RequestLength - sizeof(NDIS_OID); 164 165 DPRINT("Setting OID 0x%x on adapter %wZ\n", SetOidRequest->Oid, &AdapterContext->DeviceName); 166 167 /* Dispatch the request */ 168 NdisRequest(&Status, 169 AdapterContext->BindingHandle, 170 &Request); 171 172 /* Wait for the request */ 173 if (Status == NDIS_STATUS_PENDING) 174 { 175 KeWaitForSingleObject(&AdapterContext->AsyncEvent, 176 Executive, 177 KernelMode, 178 FALSE, 179 NULL); 180 Status = AdapterContext->AsyncStatus; 181 } 182 183 /* Return the bytes read */ 184 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = Request.DATA.SET_INFORMATION.BytesRead; 185 } 186 else 187 { 188 /* Bad parameters */ 189 Status = STATUS_INVALID_PARAMETER; 190 } 191 192 Irp->IoStatus.Status = Status; 193 194 IoCompleteRequest(Irp, IO_NO_INCREMENT); 195 196 return Status; 197 } 198 199 static 200 NTSTATUS 201 QueryAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp) 202 { 203 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; 204 PNDISUIO_QUERY_OID QueryOidRequest; 205 NDIS_REQUEST Request; 206 ULONG RequestLength; 207 NDIS_STATUS Status; 208 209 Irp->IoStatus.Information = 0; 210 211 QueryOidRequest = Irp->AssociatedIrp.SystemBuffer; 212 RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; 213 if (QueryOidRequest && RequestLength >= sizeof(NDIS_OID)) 214 { 215 /* Setup the NDIS request */ 216 Request.RequestType = NdisRequestQueryInformation; 217 Request.DATA.QUERY_INFORMATION.Oid = QueryOidRequest->Oid; 218 Request.DATA.QUERY_INFORMATION.InformationBuffer = QueryOidRequest->Data; 219 Request.DATA.QUERY_INFORMATION.InformationBufferLength = RequestLength - sizeof(NDIS_OID); 220 221 DPRINT("Querying OID 0x%x on adapter %wZ\n", QueryOidRequest->Oid, &AdapterContext->DeviceName); 222 223 /* Dispatch the request */ 224 NdisRequest(&Status, 225 AdapterContext->BindingHandle, 226 &Request); 227 228 /* Wait for the request */ 229 if (Status == NDIS_STATUS_PENDING) 230 { 231 KeWaitForSingleObject(&AdapterContext->AsyncEvent, 232 Executive, 233 KernelMode, 234 FALSE, 235 NULL); 236 Status = AdapterContext->AsyncStatus; 237 } 238 239 /* Return the bytes written */ 240 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = Request.DATA.QUERY_INFORMATION.BytesWritten; 241 } 242 else 243 { 244 /* Bad parameters */ 245 Status = STATUS_INVALID_PARAMETER; 246 } 247 248 Irp->IoStatus.Status = Status; 249 250 IoCompleteRequest(Irp, IO_NO_INCREMENT); 251 252 return Status; 253 } 254 255 static 256 NTSTATUS 257 OpenDeviceReadWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp) 258 { 259 PFILE_OBJECT FileObject = IrpSp->FileObject; 260 UNICODE_STRING DeviceName; 261 ULONG NameLength; 262 NTSTATUS Status; 263 PNDISUIO_ADAPTER_CONTEXT AdapterContext; 264 PNDISUIO_OPEN_ENTRY OpenEntry; 265 KIRQL OldIrql; 266 267 NameLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; 268 if (NameLength != 0) 269 { 270 DeviceName.MaximumLength = DeviceName.Length = NameLength; 271 DeviceName.Buffer = Irp->AssociatedIrp.SystemBuffer; 272 273 /* Check if this already has a context */ 274 AdapterContext = FindAdapterContextByName(&DeviceName); 275 if (AdapterContext != NULL) 276 { 277 DPRINT("Binding file object 0x%x to device %wZ\n", FileObject, &AdapterContext->DeviceName); 278 279 /* Reference the adapter context */ 280 KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql); 281 if (AdapterContext->OpenCount != 0) 282 { 283 /* An open for read-write is exclusive, 284 * so we can't have any other open handles */ 285 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); 286 Status = STATUS_INVALID_PARAMETER; 287 } 288 else 289 { 290 /* Add a reference */ 291 ReferenceAdapterContext(AdapterContext); 292 Status = STATUS_SUCCESS; 293 } 294 } 295 else 296 { 297 /* Invalid device name */ 298 Status = STATUS_INVALID_PARAMETER; 299 } 300 301 /* Check that the bind succeeded */ 302 if (NT_SUCCESS(Status)) 303 { 304 OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry)); 305 if (OpenEntry) 306 { 307 /* Set the file object pointer */ 308 OpenEntry->FileObject = FileObject; 309 310 /* Set the permissions */ 311 OpenEntry->WriteOnly = FALSE; 312 313 /* Associate this FO with the adapter */ 314 FileObject->FsContext = AdapterContext; 315 FileObject->FsContext2 = OpenEntry; 316 317 /* Add it to the adapter's list */ 318 InsertTailList(&AdapterContext->OpenEntryList, 319 &OpenEntry->ListEntry); 320 321 /* Success */ 322 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); 323 Status = STATUS_SUCCESS; 324 } 325 else 326 { 327 /* Remove the reference we added */ 328 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); 329 DereferenceAdapterContextWithOpenEntry(AdapterContext, NULL); 330 Status = STATUS_NO_MEMORY; 331 } 332 } 333 } 334 else 335 { 336 /* Invalid device name */ 337 Status = STATUS_INVALID_PARAMETER; 338 } 339 340 Irp->IoStatus.Status = Status; 341 Irp->IoStatus.Information = 0; 342 343 IoCompleteRequest(Irp, IO_NO_INCREMENT); 344 345 return Status; 346 } 347 348 #if 0 349 static 350 NTSTATUS 351 OpenDeviceWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp) 352 { 353 PFILE_OBJECT FileObject = IrpSp->FileObject; 354 UNICODE_STRING DeviceName; 355 ULONG NameLength; 356 NTSTATUS Status; 357 PNDISUIO_ADAPTER_CONTEXT AdapterContext; 358 PNDISUIO_OPEN_ENTRY OpenEntry; 359 KIRQL OldIrql; 360 361 NameLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; 362 if (NameLength != 0) 363 { 364 DeviceName.MaximumLength = DeviceName.Length = NameLength; 365 DeviceName.Buffer = Irp->AssociatedIrp.SystemBuffer; 366 367 /* Check if this already has a context */ 368 AdapterContext = FindAdapterContextByName(&DeviceName); 369 if (AdapterContext != NULL) 370 { 371 /* Reference the adapter context */ 372 KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql); 373 ReferenceAdapterContext(AdapterContext); 374 Status = STATUS_SUCCESS; 375 } 376 else 377 { 378 /* Invalid device name */ 379 Status = STATUS_INVALID_PARAMETER; 380 } 381 382 /* Check that the bind succeeded */ 383 if (NT_SUCCESS(Status)) 384 { 385 OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry)); 386 if (OpenEntry) 387 { 388 /* Set the file object pointer */ 389 OpenEntry->FileObject = FileObject; 390 391 /* Associate this FO with the adapter */ 392 FileObject->FsContext = AdapterContext; 393 FileObject->FsContext2 = OpenEntry; 394 395 /* Set permissions */ 396 OpenEntry->WriteOnly = TRUE; 397 398 /* Add it to the adapter's list */ 399 InsertTailList(&AdapterContext->OpenEntryList, 400 &OpenEntry->ListEntry); 401 402 /* Success */ 403 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); 404 Status = STATUS_SUCCESS; 405 } 406 else 407 { 408 /* Remove the reference we added */ 409 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); 410 DereferenceAdapterContext(AdapterContext, NULL); 411 Status = STATUS_NO_MEMORY; 412 } 413 } 414 } 415 else 416 { 417 /* Invalid device name */ 418 Status = STATUS_INVALID_PARAMETER; 419 } 420 421 Irp->IoStatus.Status = Status; 422 Irp->IoStatus.Information = 0; 423 424 IoCompleteRequest(Irp, IO_NO_INCREMENT); 425 426 return Status; 427 } 428 #endif 429 430 NTSTATUS 431 NTAPI 432 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, 433 PIRP Irp) 434 { 435 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 436 PNDISUIO_OPEN_ENTRY OpenEntry; 437 438 ASSERT(DeviceObject == GlobalDeviceObject); 439 440 /* Handle open IOCTLs first */ 441 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) 442 { 443 case IOCTL_NDISUIO_OPEN_DEVICE: 444 return OpenDeviceReadWrite(Irp, IrpSp); 445 #if 0 446 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE: 447 return OpenDeviceWrite(Irp, IrpSp); 448 #endif 449 case IOCTL_NDISUIO_BIND_WAIT: 450 return WaitForBind(Irp, IrpSp); 451 452 case IOCTL_NDISUIO_QUERY_BINDING: 453 return QueryBinding(Irp, IrpSp); 454 455 default: 456 /* Fail if this file object has no adapter associated */ 457 if (IrpSp->FileObject->FsContext == NULL) 458 { 459 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 460 Irp->IoStatus.Information = 0; 461 IoCompleteRequest(Irp, IO_NO_INCREMENT); 462 463 return STATUS_INVALID_PARAMETER; 464 } 465 466 /* Now handle write IOCTLs */ 467 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) 468 { 469 case IOCTL_NDISUIO_SET_OID_VALUE: 470 return SetAdapterOid(Irp, IrpSp); 471 472 default: 473 /* Check that we have read permissions */ 474 OpenEntry = IrpSp->FileObject->FsContext2; 475 if (OpenEntry->WriteOnly) 476 { 477 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 478 Irp->IoStatus.Information = 0; 479 IoCompleteRequest(Irp, IO_NO_INCREMENT); 480 481 return STATUS_INVALID_PARAMETER; 482 } 483 484 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) 485 { 486 #if 0 487 case IOCTL_CANCEL_READ: 488 return CancelPacketRead(Irp, IrpSp); 489 #endif 490 491 case IOCTL_NDISUIO_QUERY_OID_VALUE: 492 return QueryAdapterOid(Irp, IrpSp); 493 494 default: 495 DPRINT1("Unimplemented\n"); 496 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; 497 Irp->IoStatus.Information = 0; 498 IoCompleteRequest(Irp, IO_NO_INCREMENT); 499 return STATUS_NOT_IMPLEMENTED; 500 } 501 } 502 break; 503 } 504 } 505