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