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