1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS NDIS User I/O driver 4 * FILE: protocol.c 5 * PURPOSE: Protocol stuff 6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) 7 */ 8 9 #include "ndisuio.h" 10 11 #define NDEBUG 12 #include <debug.h> 13 14 VOID 15 NTAPI 16 NduOpenAdapterComplete(NDIS_HANDLE ProtocolBindingContext, 17 NDIS_STATUS Status, 18 NDIS_STATUS OpenStatus) 19 { 20 PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext; 21 22 DPRINT("Asynchronous adapter open completed\n"); 23 24 /* Store the final status and signal the event */ 25 AdapterContext->AsyncStatus = Status; 26 KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE); 27 } 28 29 VOID 30 NTAPI 31 NduCloseAdapterComplete(NDIS_HANDLE ProtocolBindingContext, 32 NDIS_STATUS Status) 33 { 34 PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext; 35 36 DPRINT("Asynchronous adapter close completed\n"); 37 38 /* Store the final status and signal the event */ 39 AdapterContext->AsyncStatus = Status; 40 KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE); 41 } 42 43 NDIS_STATUS 44 NTAPI 45 NduNetPnPEvent(NDIS_HANDLE ProtocolBindingContext, 46 PNET_PNP_EVENT NetPnPEvent) 47 { 48 PNDIS_DEVICE_POWER_STATE PowerState; 49 50 DPRINT("NetPnPEvent\n"); 51 52 switch (NetPnPEvent->NetEvent) 53 { 54 case NetEventQueryRemoveDevice: 55 /* Nothing to do */ 56 DPRINT1("NetPnPEvent: QueryRemoveDevice\n"); 57 return NDIS_STATUS_SUCCESS; 58 59 case NetEventSetPower: 60 ASSERT(NetPnPEvent->BufferLength >= sizeof(*PowerState)); 61 62 PowerState = NetPnPEvent->Buffer; 63 switch (*PowerState) 64 { 65 case NdisDeviceStateD0: 66 DPRINT1("NetPnPEvent: SetPower D0\n"); 67 return NDIS_STATUS_SUCCESS; 68 69 default: 70 DPRINT1("NetPnPEvent: SetPower state %d not supported\n", *PowerState); 71 return NDIS_STATUS_FAILURE; 72 } 73 74 case NetEventQueryPower: 75 DPRINT1("NetPnPEvent: QueryPower\n"); 76 return NDIS_STATUS_SUCCESS; 77 78 case NetEventCancelRemoveDevice: 79 DPRINT1("NetPnPEvent: CancelRemoveDevice\n"); 80 return NDIS_STATUS_SUCCESS; 81 82 case NetEventReconfigure: 83 DPRINT1("NetPnPEvent: Reconfigure\n"); 84 return NDIS_STATUS_SUCCESS; 85 86 case NetEventBindList: 87 DPRINT1("NetPnPEvent: BindList\n"); 88 return NDIS_STATUS_SUCCESS; 89 90 case NetEventBindsComplete: 91 DPRINT("NetPnPEvent: BindsComplete\n"); 92 return NDIS_STATUS_SUCCESS; 93 94 case NetEventPnPCapabilities: 95 DPRINT1("NetPnPEvent: PnPCapabilities\n"); 96 return NDIS_STATUS_SUCCESS; 97 98 default: 99 DPRINT1("NetPnPEvent unimplemented for net event 0x%x\n", NetPnPEvent->NetEvent); 100 return NDIS_STATUS_FAILURE; 101 } 102 } 103 104 VOID 105 NTAPI 106 NduSendComplete(NDIS_HANDLE ProtocolBindingContext, 107 PNDIS_PACKET Packet, 108 NDIS_STATUS Status) 109 { 110 PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext; 111 112 DPRINT("Asynchronous adapter send completed\n"); 113 114 /* Store the final status and signal the event */ 115 AdapterContext->AsyncStatus = Status; 116 KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE); 117 } 118 119 VOID 120 NTAPI 121 NduTransferDataComplete(NDIS_HANDLE ProtocolBindingContext, 122 PNDIS_PACKET Packet, 123 NDIS_STATUS Status, 124 UINT BytesTransferred) 125 { 126 PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext; 127 128 DPRINT("Asynchronous adapter transfer completed\n"); 129 130 /* Store the final status and signal the event */ 131 AdapterContext->AsyncStatus = Status; 132 KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE); 133 } 134 135 VOID 136 NTAPI 137 NduResetComplete(NDIS_HANDLE ProtocolBindingContext, 138 NDIS_STATUS Status) 139 { 140 PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext; 141 142 DPRINT("Asynchronous adapter reset completed\n"); 143 144 /* Store the final status and signal the event */ 145 AdapterContext->AsyncStatus = Status; 146 KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE); 147 } 148 149 VOID 150 NTAPI 151 NduRequestComplete(NDIS_HANDLE ProtocolBindingContext, 152 PNDIS_REQUEST NdisRequest, 153 NDIS_STATUS Status) 154 { 155 PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext; 156 157 DPRINT("Asynchronous adapter request completed\n"); 158 159 /* Store the final status and signal the event */ 160 AdapterContext->AsyncStatus = Status; 161 KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE); 162 } 163 164 NDIS_STATUS 165 NTAPI 166 NduReceive(NDIS_HANDLE ProtocolBindingContext, 167 NDIS_HANDLE MacReceiveContext, 168 PVOID HeaderBuffer, 169 UINT HeaderBufferSize, 170 PVOID LookAheadBuffer, 171 UINT LookaheadBufferSize, 172 UINT PacketSize) 173 { 174 PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext; 175 PNDISUIO_PACKET_ENTRY PacketEntry; 176 PVOID PacketBuffer; 177 PNDIS_PACKET Packet; 178 NDIS_STATUS Status; 179 UINT BytesTransferred; 180 181 DPRINT("Received a %d byte packet\n", PacketSize); 182 183 /* Discard if nobody is waiting for it */ 184 if (AdapterContext->OpenCount == 0) 185 return NDIS_STATUS_NOT_ACCEPTED; 186 187 /* Allocate a buffer to hold the packet data and header */ 188 PacketBuffer = ExAllocatePool(NonPagedPool, PacketSize + HeaderBufferSize); 189 if (!PacketBuffer) 190 return NDIS_STATUS_NOT_ACCEPTED; 191 192 /* Allocate the packet descriptor and buffer */ 193 Packet = CreatePacketFromPoolBuffer(AdapterContext, 194 (PUCHAR)PacketBuffer + HeaderBufferSize, 195 PacketSize); 196 if (!Packet) 197 { 198 ExFreePool(PacketBuffer); 199 return NDIS_STATUS_NOT_ACCEPTED; 200 } 201 202 /* Transfer the packet data into our data buffer */ 203 if (LookaheadBufferSize == PacketSize) 204 { 205 NdisCopyLookaheadData((PVOID)((PUCHAR)PacketBuffer + HeaderBufferSize), 206 LookAheadBuffer, 207 PacketSize, 208 AdapterContext->MacOptions); 209 BytesTransferred = PacketSize; 210 } 211 else 212 { 213 NdisTransferData(&Status, 214 AdapterContext->BindingHandle, 215 MacReceiveContext, 216 0, 217 PacketSize, 218 Packet, 219 &BytesTransferred); 220 if (Status == NDIS_STATUS_PENDING) 221 { 222 KeWaitForSingleObject(&AdapterContext->AsyncEvent, 223 Executive, 224 KernelMode, 225 FALSE, 226 NULL); 227 Status = AdapterContext->AsyncStatus; 228 } 229 if (Status != NDIS_STATUS_SUCCESS) 230 { 231 DPRINT1("Failed to transfer data with status 0x%x\n", Status); 232 CleanupAndFreePacket(Packet, FALSE); 233 ExFreePool(PacketBuffer); 234 return NDIS_STATUS_NOT_ACCEPTED; 235 } 236 } 237 238 /* Copy the header data */ 239 RtlCopyMemory(PacketBuffer, HeaderBuffer, HeaderBufferSize); 240 241 /* Free the packet descriptor and buffers 242 but not the pool because we still need it */ 243 CleanupAndFreePacket(Packet, FALSE); 244 245 /* Allocate a packet entry from pool */ 246 PacketEntry = ExAllocatePool(NonPagedPool, sizeof(NDISUIO_PACKET_ENTRY) + BytesTransferred + HeaderBufferSize - 1); 247 if (!PacketEntry) 248 { 249 ExFreePool(PacketBuffer); 250 return NDIS_STATUS_RESOURCES; 251 } 252 253 /* Initialize the packet entry and copy in packet data */ 254 PacketEntry->PacketLength = BytesTransferred + HeaderBufferSize; 255 RtlCopyMemory(PacketEntry->PacketData, PacketBuffer, PacketEntry->PacketLength); 256 257 /* Free the old buffer */ 258 ExFreePool(PacketBuffer); 259 260 /* Insert the packet on the adapter's packet list */ 261 ExInterlockedInsertTailList(&AdapterContext->PacketList, 262 &PacketEntry->ListEntry, 263 &AdapterContext->Spinlock); 264 265 /* Signal the read event */ 266 KeSetEvent(&AdapterContext->PacketReadEvent, 267 IO_NETWORK_INCREMENT, 268 FALSE); 269 270 return NDIS_STATUS_SUCCESS; 271 } 272 273 VOID 274 NTAPI 275 NduReceiveComplete(NDIS_HANDLE ProtocolBindingContext) 276 { 277 /* No op */ 278 } 279 280 VOID 281 NTAPI 282 NduStatus(NDIS_HANDLE ProtocolBindingContext, 283 NDIS_STATUS GeneralStatus, 284 PVOID StatusBuffer, 285 UINT StatusBufferSize) 286 { 287 /* FIXME: Implement status tracking */ 288 } 289 290 VOID 291 NTAPI 292 NduStatusComplete(NDIS_HANDLE ProtocolBindingContext) 293 { 294 /* FIXME: Implement status tracking */ 295 } 296 297 static 298 NDIS_STATUS 299 UnbindAdapterByContext(PNDISUIO_ADAPTER_CONTEXT AdapterContext) 300 { 301 KIRQL OldIrql; 302 PLIST_ENTRY CurrentEntry; 303 PNDISUIO_OPEN_ENTRY OpenEntry; 304 PNDISUIO_PACKET_ENTRY PacketEntry; 305 NDIS_STATUS Status; 306 307 DPRINT("Unbinding adapter %wZ\n", &AdapterContext->DeviceName); 308 309 /* FIXME: We don't do anything with outstanding reads */ 310 311 /* Remove the adapter context from the global list */ 312 KeAcquireSpinLock(&GlobalAdapterListLock, &OldIrql); 313 RemoveEntryList(&AdapterContext->ListEntry); 314 KeReleaseSpinLock(&GlobalAdapterListLock, OldIrql); 315 316 /* Free the device name string */ 317 RtlFreeUnicodeString(&AdapterContext->DeviceName); 318 319 /* Invalidate all handles to this adapter */ 320 CurrentEntry = AdapterContext->OpenEntryList.Flink; 321 while (CurrentEntry != &AdapterContext->OpenEntryList) 322 { 323 OpenEntry = CONTAINING_RECORD(CurrentEntry, NDISUIO_OPEN_ENTRY, ListEntry); 324 325 /* Make sure the entry is sane */ 326 ASSERT(OpenEntry->FileObject); 327 328 /* Remove the adapter context pointer */ 329 ASSERT(AdapterContext == OpenEntry->FileObject->FsContext); 330 OpenEntry->FileObject->FsContext = NULL; 331 AdapterContext->OpenCount--; 332 333 /* Remove the open entry pointer */ 334 ASSERT(OpenEntry == OpenEntry->FileObject->FsContext2); 335 OpenEntry->FileObject->FsContext2 = NULL; 336 337 /* Move to the next entry */ 338 CurrentEntry = CurrentEntry->Flink; 339 340 /* Free the open entry */ 341 ExFreePool(OpenEntry); 342 } 343 344 /* If this fails, we have a refcount mismatch somewhere */ 345 ASSERT(AdapterContext->OpenCount == 0); 346 347 /* Free all pending packet entries */ 348 CurrentEntry = AdapterContext->PacketList.Flink; 349 while (CurrentEntry != &AdapterContext->PacketList) 350 { 351 PacketEntry = CONTAINING_RECORD(CurrentEntry, NDISUIO_PACKET_ENTRY, ListEntry); 352 353 /* Move to the next entry */ 354 CurrentEntry = CurrentEntry->Flink; 355 356 /* Free the packet entry */ 357 ExFreePool(PacketEntry); 358 } 359 360 /* Send the close request */ 361 NdisCloseAdapter(&Status, 362 AdapterContext->BindingHandle); 363 364 /* Wait for a pending close */ 365 if (Status == NDIS_STATUS_PENDING) 366 { 367 KeWaitForSingleObject(&AdapterContext->AsyncEvent, 368 Executive, 369 KernelMode, 370 FALSE, 371 NULL); 372 Status = AdapterContext->AsyncStatus; 373 } 374 375 /* Free the context */ 376 ExFreePool(AdapterContext); 377 378 return Status; 379 } 380 381 static 382 NDIS_STATUS 383 BindAdapterByName(PNDIS_STRING DeviceName) 384 { 385 NDIS_STATUS OpenErrorStatus; 386 PNDISUIO_ADAPTER_CONTEXT AdapterContext; 387 NDIS_MEDIUM SupportedMedia[1] = {NdisMedium802_3}; 388 UINT SelectedMedium; 389 NDIS_STATUS Status; 390 NDIS_REQUEST Request; 391 392 /* Allocate the adapter context */ 393 AdapterContext = ExAllocatePool(NonPagedPool, sizeof(*AdapterContext)); 394 if (!AdapterContext) 395 { 396 return NDIS_STATUS_RESOURCES; 397 } 398 399 /* Set up the adapter context */ 400 RtlZeroMemory(AdapterContext, sizeof(*AdapterContext)); 401 KeInitializeEvent(&AdapterContext->AsyncEvent, SynchronizationEvent, FALSE); 402 KeInitializeEvent(&AdapterContext->PacketReadEvent, SynchronizationEvent, FALSE); 403 KeInitializeSpinLock(&AdapterContext->Spinlock); 404 InitializeListHead(&AdapterContext->PacketList); 405 InitializeListHead(&AdapterContext->OpenEntryList); 406 AdapterContext->OpenCount = 0; 407 408 AdapterContext->DeviceName.Length = 409 AdapterContext->DeviceName.MaximumLength = DeviceName->Length; 410 AdapterContext->DeviceName.Buffer = ExAllocatePool(NonPagedPool, DeviceName->Length); 411 if (!AdapterContext->DeviceName.Buffer) 412 { 413 ExFreePool(AdapterContext); 414 return NDIS_STATUS_RESOURCES; 415 } 416 417 /* Copy the device name into the adapter context */ 418 RtlCopyMemory(AdapterContext->DeviceName.Buffer, DeviceName->Buffer, DeviceName->Length); 419 420 DPRINT("Binding adapter %wZ\n", &AdapterContext->DeviceName); 421 422 /* Create the buffer pool */ 423 NdisAllocateBufferPool(&Status, 424 &AdapterContext->BufferPoolHandle, 425 50); 426 if (Status != NDIS_STATUS_SUCCESS) 427 { 428 DPRINT1("Failed to allocate buffer pool with status 0x%x\n", Status); 429 RtlFreeUnicodeString(&AdapterContext->DeviceName); 430 ExFreePool(AdapterContext); 431 return Status; 432 } 433 434 /* Create the packet pool */ 435 NdisAllocatePacketPool(&Status, 436 &AdapterContext->PacketPoolHandle, 437 25, 438 PROTOCOL_RESERVED_SIZE_IN_PACKET); 439 if (Status != NDIS_STATUS_SUCCESS) 440 { 441 DPRINT1("Failed to allocate packet pool with status 0x%x\n", Status); 442 NdisFreeBufferPool(AdapterContext->BufferPoolHandle); 443 RtlFreeUnicodeString(&AdapterContext->DeviceName); 444 ExFreePool(AdapterContext); 445 return Status; 446 } 447 448 /* Send the open request */ 449 NdisOpenAdapter(&Status, 450 &OpenErrorStatus, 451 &AdapterContext->BindingHandle, 452 &SelectedMedium, 453 SupportedMedia, 454 1, 455 GlobalProtocolHandle, 456 AdapterContext, 457 DeviceName, 458 0, 459 NULL); 460 461 /* Wait for a pending open */ 462 if (Status == NDIS_STATUS_PENDING) 463 { 464 KeWaitForSingleObject(&AdapterContext->AsyncEvent, 465 Executive, 466 KernelMode, 467 FALSE, 468 NULL); 469 Status = AdapterContext->AsyncStatus; 470 } 471 472 /* Check the final status */ 473 if (Status != NDIS_STATUS_SUCCESS) 474 { 475 DPRINT1("Failed to open adapter for bind with status 0x%x\n", Status); 476 NdisFreePacketPool(AdapterContext->PacketPoolHandle); 477 NdisFreeBufferPool(AdapterContext->BufferPoolHandle); 478 RtlFreeUnicodeString(&AdapterContext->DeviceName); 479 ExFreePool(AdapterContext); 480 return Status; 481 } 482 483 /* Get the MAC options */ 484 Request.RequestType = NdisRequestQueryInformation; 485 Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS; 486 Request.DATA.QUERY_INFORMATION.InformationBuffer = &AdapterContext->MacOptions; 487 Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(ULONG); 488 NdisRequest(&Status, 489 AdapterContext->BindingHandle, 490 &Request); 491 492 /* Wait for a pending request */ 493 if (Status == NDIS_STATUS_PENDING) 494 { 495 KeWaitForSingleObject(&AdapterContext->AsyncEvent, 496 Executive, 497 KernelMode, 498 FALSE, 499 NULL); 500 Status = AdapterContext->AsyncStatus; 501 } 502 503 /* Check the final status */ 504 if (Status != NDIS_STATUS_SUCCESS) 505 { 506 NDIS_STATUS CloseStatus; 507 508 DPRINT1("Failed to get MAC options with status 0x%x\n", Status); 509 510 NdisCloseAdapter(&CloseStatus, 511 AdapterContext->BindingHandle); 512 if (CloseStatus == NDIS_STATUS_PENDING) 513 { 514 KeWaitForSingleObject(&AdapterContext->AsyncEvent, 515 Executive, 516 KernelMode, 517 FALSE, 518 NULL); 519 } 520 521 NdisFreePacketPool(AdapterContext->PacketPoolHandle); 522 NdisFreeBufferPool(AdapterContext->BufferPoolHandle); 523 RtlFreeUnicodeString(&AdapterContext->DeviceName); 524 ExFreePool(AdapterContext); 525 return Status; 526 } 527 528 /* Add the adapter context to the global list */ 529 ExInterlockedInsertTailList(&GlobalAdapterList, 530 &AdapterContext->ListEntry, 531 &GlobalAdapterListLock); 532 533 return STATUS_SUCCESS; 534 } 535 536 VOID 537 NTAPI 538 NduBindAdapter(PNDIS_STATUS Status, 539 NDIS_HANDLE BindContext, 540 PNDIS_STRING DeviceName, 541 PVOID SystemSpecific1, 542 PVOID SystemSpecific2) 543 { 544 /* Use our helper function to create a context for this adapter */ 545 *Status = BindAdapterByName(DeviceName); 546 } 547 548 VOID 549 NTAPI 550 NduUnbindAdapter(PNDIS_STATUS Status, 551 NDIS_HANDLE ProtocolBindingContext, 552 NDIS_HANDLE UnbindContext) 553 { 554 /* This is forced unbind. UnbindAdapterByContext() will take care of 555 * invalidating file handles pointer to this adapter for us */ 556 *Status = UnbindAdapterByContext(ProtocolBindingContext); 557 } 558