xref: /reactos/drivers/network/ndisuio/protocol.c (revision 84344399)
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