5e7628450bd4a658ee57d1e4c4fe06f76febe4e8
[reactos.git] / reactos / 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 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 DPRINT1("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 }