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