[NDISUIO]
[reactos.git] / drivers / network / ndisuio / protocol.c
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