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