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