[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 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 /* Allocate a buffer to hold the packet data and header */
123 PacketBuffer = ExAllocatePool(NonPagedPool, PacketSize);
124 if (!PacketBuffer)
125 return NDIS_STATUS_NOT_ACCEPTED;
126
127 /* Allocate the packet descriptor and buffer */
128 Packet = CreatePacketFromPoolBuffer((PUCHAR)PacketBuffer + HeaderBufferSize,
129 PacketSize);
130 if (!Packet)
131 {
132 ExFreePool(PacketBuffer);
133 return NDIS_STATUS_NOT_ACCEPTED;
134 }
135
136 /* Transfer the packet data into our data buffer */
137 NdisTransferData(&Status,
138 AdapterContext->BindingHandle,
139 MacReceiveContext,
140 0,
141 PacketSize,
142 Packet,
143 &BytesTransferred);
144 if (Status == NDIS_STATUS_PENDING)
145 {
146 KeWaitForSingleObject(&AdapterContext->AsyncEvent,
147 Executive,
148 KernelMode,
149 FALSE,
150 NULL);
151 Status = AdapterContext->AsyncStatus;
152 }
153 if (Status != NDIS_STATUS_SUCCESS)
154 {
155 DPRINT1("Failed to transfer data with status 0x%x\n", Status);
156 CleanupAndFreePacket(Packet, TRUE);
157 return NDIS_STATUS_NOT_ACCEPTED;
158 }
159
160 /* Copy the header data */
161 RtlCopyMemory(PacketBuffer, HeaderBuffer, HeaderBufferSize);
162
163 /* Free the packet descriptor and buffers
164 but not the pool because we still need it */
165 CleanupAndFreePacket(Packet, FALSE);
166
167 /* Allocate a packet entry from paged pool */
168 PacketEntry = ExAllocatePool(PagedPool, sizeof(NDISUIO_PACKET_ENTRY) + BytesTransferred + HeaderBufferSize - 1);
169 if (!PacketEntry)
170 {
171 ExFreePool(PacketBuffer);
172 return NDIS_STATUS_RESOURCES;
173 }
174
175 /* Initialize the packet entry and copy in packet data */
176 PacketEntry->PacketLength = BytesTransferred + HeaderBufferSize;
177 RtlCopyMemory(&PacketEntry->PacketData[0], PacketBuffer, PacketEntry->PacketLength);
178
179 /* Free the old non-paged buffer */
180 ExFreePool(PacketBuffer);
181
182 /* Insert the packet on the adapter's packet list */
183 ExInterlockedInsertTailList(&AdapterContext->PacketList,
184 &PacketEntry->ListEntry,
185 &AdapterContext->Spinlock);
186
187 /* Signal the read event */
188 KeSetEvent(&AdapterContext->PacketReadEvent,
189 IO_NETWORK_INCREMENT,
190 FALSE);
191
192 return NDIS_STATUS_SUCCESS;
193 }
194
195 VOID
196 NTAPI
197 NduReceiveComplete(NDIS_HANDLE ProtocolBindingContext)
198 {
199 /* No op */
200 }
201
202 VOID
203 NTAPI
204 NduStatus(NDIS_HANDLE ProtocolBindingContext,
205 NDIS_STATUS GeneralStatus,
206 PVOID StatusBuffer,
207 UINT StatusBufferSize)
208 {
209 /* FIXME: Implement status tracking */
210 }
211
212 VOID
213 NTAPI
214 NduStatusComplete(NDIS_HANDLE ProtocolBindingContext)
215 {
216 /* FIXME: Implement status tracking */
217 }
218
219 static
220 NDIS_STATUS
221 UnbindAdapterByContext(PNDISUIO_ADAPTER_CONTEXT AdapterContext)
222 {
223 KIRQL OldIrql;
224 PLIST_ENTRY CurrentOpenEntry;
225 PNDISUIO_OPEN_ENTRY OpenEntry;
226 NDIS_STATUS Status;
227
228 /* Remove the adapter context from the global list */
229 KeAcquireSpinLock(&GlobalAdapterListLock, &OldIrql);
230 RemoveEntryList(&AdapterContext->ListEntry);
231 KeReleaseSpinLock(&GlobalAdapterListLock, OldIrql);
232
233 /* Invalidate all handles to this adapter */
234 CurrentOpenEntry = AdapterContext->OpenEntryList.Flink;
235 while (CurrentOpenEntry != &AdapterContext->OpenEntryList)
236 {
237 OpenEntry = CONTAINING_RECORD(CurrentOpenEntry, NDISUIO_OPEN_ENTRY, ListEntry);
238
239 /* Make sure the entry is sane */
240 ASSERT(OpenEntry->FileObject);
241
242 /* Remove the adapter context pointer */
243 ASSERT(AdapterContext == OpenEntry->FileObject->FsContext);
244 OpenEntry->FileObject->FsContext = NULL;
245 AdapterContext->OpenCount--;
246
247 /* Remove the open entry pointer */
248 ASSERT(OpenEntry == OpenEntry->FileObject->FsContext2);
249 OpenEntry->FileObject->FsContext2 = NULL;
250
251 /* Move to the next entry */
252 CurrentOpenEntry = CurrentOpenEntry->Flink;
253
254 /* Free the open entry */
255 ExFreePool(OpenEntry);
256 }
257
258 /* If this fails, we have a refcount mismatch somewhere */
259 ASSERT(AdapterContext->OpenCount == 0);
260
261 /* Send the close request */
262 NdisCloseAdapter(&Status,
263 AdapterContext->BindingHandle);
264
265 /* Wait for a pending close */
266 if (Status == NDIS_STATUS_PENDING)
267 {
268 KeWaitForSingleObject(&AdapterContext->AsyncEvent,
269 Executive,
270 KernelMode,
271 FALSE,
272 NULL);
273 Status = AdapterContext->AsyncStatus;
274 }
275
276 /* Free the context */
277 ExFreePool(AdapterContext);
278
279 return Status;
280 }
281
282 static
283 NDIS_STATUS
284 BindAdapterByName(PNDIS_STRING DeviceName)
285 {
286 NDIS_STATUS OpenErrorStatus;
287 PNDISUIO_ADAPTER_CONTEXT AdapterContext;
288 UINT SelectedMedium;
289 NDIS_STATUS Status;
290
291 /* Allocate the adapter context */
292 AdapterContext = ExAllocatePool(NonPagedPool, sizeof(*AdapterContext));
293 if (!AdapterContext)
294 {
295 return NDIS_STATUS_RESOURCES;
296 }
297
298 /* Set up the adapter context */
299 RtlZeroMemory(AdapterContext, sizeof(*AdapterContext));
300 KeInitializeEvent(&AdapterContext->AsyncEvent, SynchronizationEvent, FALSE);
301 KeInitializeEvent(&AdapterContext->PacketReadEvent, SynchronizationEvent, FALSE);
302 KeInitializeSpinLock(&AdapterContext->Spinlock);
303 InitializeListHead(&AdapterContext->PacketList);
304 InitializeListHead(&AdapterContext->OpenEntryList);
305 AdapterContext->OpenCount = 0;
306
307 AdapterContext->DeviceName.Length =
308 AdapterContext->DeviceName.MaximumLength = DeviceName->Length;
309 AdapterContext->DeviceName.Buffer = ExAllocatePool(NonPagedPool, DeviceName->Length);
310 if (!AdapterContext->DeviceName.Buffer)
311 {
312 ExFreePool(AdapterContext);
313 return NDIS_STATUS_RESOURCES;
314 }
315
316 RtlCopyMemory(AdapterContext->DeviceName.Buffer, DeviceName->Buffer, DeviceName->Length);
317
318 /* Send the open request */
319 NdisOpenAdapter(&Status,
320 &OpenErrorStatus,
321 &AdapterContext->BindingHandle,
322 &SelectedMedium,
323 SupportedMedia,
324 sizeof(SupportedMedia),
325 GlobalProtocolHandle,
326 AdapterContext,
327 DeviceName,
328 0,
329 NULL);
330
331 /* Wait for a pending open */
332 if (Status == NDIS_STATUS_PENDING)
333 {
334 KeWaitForSingleObject(&AdapterContext->AsyncEvent,
335 Executive,
336 KernelMode,
337 FALSE,
338 NULL);
339 Status = AdapterContext->AsyncStatus;
340 }
341
342 /* Check the final status */
343 if (Status != NDIS_STATUS_SUCCESS)
344 {
345 DPRINT1("Failed to open adapter for bind with status 0x%x\n", Status);
346 ExFreePool(AdapterContext);
347 return Status;
348 }
349
350 /* Add the adapter context to the global list */
351 ExInterlockedInsertTailList(&GlobalAdapterList,
352 &AdapterContext->ListEntry,
353 &GlobalAdapterListLock);
354
355 return STATUS_SUCCESS;
356 }
357
358 VOID
359 NTAPI
360 NduBindAdapter(PNDIS_STATUS Status,
361 NDIS_HANDLE BindContext,
362 PNDIS_STRING DeviceName,
363 PVOID SystemSpecific1,
364 PVOID SystemSpecific2)
365 {
366 /* Use our helper function to create a context for this adapter */
367 *Status = BindAdapterByName(DeviceName);
368 }
369
370 VOID
371 NTAPI
372 NduUnbindAdapter(PNDIS_STATUS Status,
373 NDIS_HANDLE ProtocolBindingContext,
374 NDIS_HANDLE UnbindContext)
375 {
376 /* This is forced unbind. UnbindAdapterByContext() will take care of
377 * invalidating file handles pointer to this adapter for us */
378 *Status = UnbindAdapterByContext(ProtocolBindingContext);
379 }
380