]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From fec8755b6193c93a935423fdd6026b354aa2e15e Mon Sep 17 00:00:00 2001 |
2 | From: Hank Janssen <hjanssen@microsoft.com> | |
3 | Date: Mon, 13 Jul 2009 15:34:54 -0700 | |
4 | Subject: Staging: hv: add the Hyper-V virtual network driver | |
5 | ||
6 | From: Hank Janssen <hjanssen@microsoft.com> | |
7 | ||
8 | This is the virtual network driver when running Linux on top of Hyper-V. | |
9 | ||
10 | Signed-off-by: Hank Janssen <hjanssen@microsoft.com> | |
11 | Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> | |
12 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
13 | --- | |
14 | drivers/staging/hv/NetVsc.c | 1499 +++++++++++++++++++++++++++++++++++++++ | |
15 | drivers/staging/hv/NetVsc.h | 91 ++ | |
16 | drivers/staging/hv/RndisFilter.c | 1162 ++++++++++++++++++++++++++++++ | |
17 | drivers/staging/hv/RndisFilter.h | 61 + | |
18 | drivers/staging/hv/netvsc_drv.c | 720 ++++++++++++++++++ | |
19 | 5 files changed, 3533 insertions(+) | |
20 | create mode 100644 drivers/staging/hv/netvsc.c | |
21 | ||
22 | --- /dev/null | |
23 | +++ b/drivers/staging/hv/NetVsc.c | |
24 | @@ -0,0 +1,1499 @@ | |
25 | +/* | |
26 | + * | |
27 | + * Copyright (c) 2009, Microsoft Corporation. | |
28 | + * | |
29 | + * This program is free software; you can redistribute it and/or modify it | |
30 | + * under the terms and conditions of the GNU General Public License, | |
31 | + * version 2, as published by the Free Software Foundation. | |
32 | + * | |
33 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
34 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
35 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
36 | + * more details. | |
37 | + * | |
38 | + * You should have received a copy of the GNU General Public License along with | |
39 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
40 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
41 | + * | |
42 | + * Authors: | |
43 | + * Hank Janssen <hjanssen@microsoft.com> | |
44 | + * | |
45 | + */ | |
46 | + | |
47 | + | |
48 | +#include "logging.h" | |
49 | +#include "NetVsc.h" | |
50 | +#include "RndisFilter.h" | |
51 | + | |
52 | + | |
53 | +// | |
54 | +// Globals | |
55 | +// | |
56 | +static const char* gDriverName="netvsc"; | |
57 | + | |
58 | +// {F8615163-DF3E-46c5-913F-F2D2F965ED0E} | |
59 | +static const GUID gNetVscDeviceType={ | |
60 | + .Data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E} | |
61 | +}; | |
62 | + | |
63 | + | |
64 | +// | |
65 | +// Internal routines | |
66 | +// | |
67 | +static int | |
68 | +NetVscOnDeviceAdd( | |
69 | + DEVICE_OBJECT *Device, | |
70 | + void *AdditionalInfo | |
71 | + ); | |
72 | + | |
73 | +static int | |
74 | +NetVscOnDeviceRemove( | |
75 | + DEVICE_OBJECT *Device | |
76 | + ); | |
77 | + | |
78 | +static void | |
79 | +NetVscOnCleanup( | |
80 | + DRIVER_OBJECT *Driver | |
81 | + ); | |
82 | + | |
83 | +static void | |
84 | +NetVscOnChannelCallback( | |
85 | + PVOID context | |
86 | + ); | |
87 | + | |
88 | +static int | |
89 | +NetVscInitializeSendBufferWithNetVsp( | |
90 | + DEVICE_OBJECT *Device | |
91 | + ); | |
92 | + | |
93 | +static int | |
94 | +NetVscInitializeReceiveBufferWithNetVsp( | |
95 | + DEVICE_OBJECT *Device | |
96 | + ); | |
97 | + | |
98 | +static int | |
99 | +NetVscDestroySendBuffer( | |
100 | + NETVSC_DEVICE *NetDevice | |
101 | + ); | |
102 | + | |
103 | +static int | |
104 | +NetVscDestroyReceiveBuffer( | |
105 | + NETVSC_DEVICE *NetDevice | |
106 | + ); | |
107 | + | |
108 | +static int | |
109 | +NetVscConnectToVsp( | |
110 | + DEVICE_OBJECT *Device | |
111 | + ); | |
112 | + | |
113 | +static void | |
114 | +NetVscOnSendCompletion( | |
115 | + DEVICE_OBJECT *Device, | |
116 | + VMPACKET_DESCRIPTOR *Packet | |
117 | + ); | |
118 | + | |
119 | +static int | |
120 | +NetVscOnSend( | |
121 | + DEVICE_OBJECT *Device, | |
122 | + NETVSC_PACKET *Packet | |
123 | + ); | |
124 | + | |
125 | +static void | |
126 | +NetVscOnReceive( | |
127 | + DEVICE_OBJECT *Device, | |
128 | + VMPACKET_DESCRIPTOR *Packet | |
129 | + ); | |
130 | + | |
131 | +static void | |
132 | +NetVscOnReceiveCompletion( | |
133 | + PVOID Context | |
134 | + ); | |
135 | + | |
136 | +static void | |
137 | +NetVscSendReceiveCompletion( | |
138 | + DEVICE_OBJECT *Device, | |
139 | + UINT64 TransactionId | |
140 | + ); | |
141 | + | |
142 | +static inline NETVSC_DEVICE* AllocNetDevice(DEVICE_OBJECT *Device) | |
143 | +{ | |
144 | + NETVSC_DEVICE *netDevice; | |
145 | + | |
146 | + netDevice = MemAllocZeroed(sizeof(NETVSC_DEVICE)); | |
147 | + if (!netDevice) | |
148 | + return NULL; | |
149 | + | |
150 | + // Set to 2 to allow both inbound and outbound traffic | |
151 | + InterlockedCompareExchange(&netDevice->RefCount, 2, 0); | |
152 | + | |
153 | + netDevice->Device = Device; | |
154 | + Device->Extension = netDevice; | |
155 | + | |
156 | + return netDevice; | |
157 | +} | |
158 | + | |
159 | +static inline void FreeNetDevice(NETVSC_DEVICE *Device) | |
160 | +{ | |
161 | + ASSERT(Device->RefCount == 0); | |
162 | + Device->Device->Extension = NULL; | |
163 | + MemFree(Device); | |
164 | +} | |
165 | + | |
166 | + | |
167 | +// Get the net device object iff exists and its refcount > 1 | |
168 | +static inline NETVSC_DEVICE* GetOutboundNetDevice(DEVICE_OBJECT *Device) | |
169 | +{ | |
170 | + NETVSC_DEVICE *netDevice; | |
171 | + | |
172 | + netDevice = (NETVSC_DEVICE*)Device->Extension; | |
173 | + if (netDevice && netDevice->RefCount > 1) | |
174 | + { | |
175 | + InterlockedIncrement(&netDevice->RefCount); | |
176 | + } | |
177 | + else | |
178 | + { | |
179 | + netDevice = NULL; | |
180 | + } | |
181 | + | |
182 | + return netDevice; | |
183 | +} | |
184 | + | |
185 | +// Get the net device object iff exists and its refcount > 0 | |
186 | +static inline NETVSC_DEVICE* GetInboundNetDevice(DEVICE_OBJECT *Device) | |
187 | +{ | |
188 | + NETVSC_DEVICE *netDevice; | |
189 | + | |
190 | + netDevice = (NETVSC_DEVICE*)Device->Extension; | |
191 | + if (netDevice && netDevice->RefCount) | |
192 | + { | |
193 | + InterlockedIncrement(&netDevice->RefCount); | |
194 | + } | |
195 | + else | |
196 | + { | |
197 | + netDevice = NULL; | |
198 | + } | |
199 | + | |
200 | + return netDevice; | |
201 | +} | |
202 | + | |
203 | +static inline void PutNetDevice(DEVICE_OBJECT *Device) | |
204 | +{ | |
205 | + NETVSC_DEVICE *netDevice; | |
206 | + | |
207 | + netDevice = (NETVSC_DEVICE*)Device->Extension; | |
208 | + ASSERT(netDevice); | |
209 | + | |
210 | + InterlockedDecrement(&netDevice->RefCount); | |
211 | +} | |
212 | + | |
213 | +static inline NETVSC_DEVICE* ReleaseOutboundNetDevice(DEVICE_OBJECT *Device) | |
214 | +{ | |
215 | + NETVSC_DEVICE *netDevice; | |
216 | + | |
217 | + netDevice = (NETVSC_DEVICE*)Device->Extension; | |
218 | + if (netDevice == NULL) | |
219 | + return NULL; | |
220 | + | |
221 | + // Busy wait until the ref drop to 2, then set it to 1 | |
222 | + while (InterlockedCompareExchange(&netDevice->RefCount, 1, 2) != 2) | |
223 | + { | |
224 | + Sleep(100); | |
225 | + } | |
226 | + | |
227 | + return netDevice; | |
228 | +} | |
229 | + | |
230 | +static inline NETVSC_DEVICE* ReleaseInboundNetDevice(DEVICE_OBJECT *Device) | |
231 | +{ | |
232 | + NETVSC_DEVICE *netDevice; | |
233 | + | |
234 | + netDevice = (NETVSC_DEVICE*)Device->Extension; | |
235 | + if (netDevice == NULL) | |
236 | + return NULL; | |
237 | + | |
238 | + // Busy wait until the ref drop to 1, then set it to 0 | |
239 | + while (InterlockedCompareExchange(&netDevice->RefCount, 0, 1) != 1) | |
240 | + { | |
241 | + Sleep(100); | |
242 | + } | |
243 | + | |
244 | + Device->Extension = NULL; | |
245 | + return netDevice; | |
246 | +} | |
247 | + | |
248 | +/*++; | |
249 | + | |
250 | + | |
251 | +Name: | |
252 | + NetVscInitialize() | |
253 | + | |
254 | +Description: | |
255 | + Main entry point | |
256 | + | |
257 | +--*/ | |
258 | +int | |
259 | +NetVscInitialize( | |
260 | + DRIVER_OBJECT *drv | |
261 | + ) | |
262 | +{ | |
263 | + NETVSC_DRIVER_OBJECT* driver = (NETVSC_DRIVER_OBJECT*)drv; | |
264 | + int ret=0; | |
265 | + | |
266 | + DPRINT_ENTER(NETVSC); | |
267 | + | |
268 | + DPRINT_DBG(NETVSC, "sizeof(NETVSC_PACKET)=%d, sizeof(NVSP_MESSAGE)=%d, sizeof(VMTRANSFER_PAGE_PACKET_HEADER)=%d", | |
269 | + sizeof(NETVSC_PACKET), sizeof(NVSP_MESSAGE), sizeof(VMTRANSFER_PAGE_PACKET_HEADER)); | |
270 | + | |
271 | + // Make sure we are at least 2 pages since 1 page is used for control | |
272 | + ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1)); | |
273 | + | |
274 | + drv->name = gDriverName; | |
275 | + memcpy(&drv->deviceType, &gNetVscDeviceType, sizeof(GUID)); | |
276 | + | |
277 | + // Make sure it is set by the caller | |
278 | + ASSERT(driver->OnReceiveCallback); | |
279 | + ASSERT(driver->OnLinkStatusChanged); | |
280 | + | |
281 | + // Setup the dispatch table | |
282 | + driver->Base.OnDeviceAdd = NetVscOnDeviceAdd; | |
283 | + driver->Base.OnDeviceRemove = NetVscOnDeviceRemove; | |
284 | + driver->Base.OnCleanup = NetVscOnCleanup; | |
285 | + | |
286 | + driver->OnSend = NetVscOnSend; | |
287 | + | |
288 | + RndisFilterInit(driver); | |
289 | + | |
290 | + DPRINT_EXIT(NETVSC); | |
291 | + | |
292 | + return ret; | |
293 | +} | |
294 | + | |
295 | +static int | |
296 | +NetVscInitializeReceiveBufferWithNetVsp( | |
297 | + DEVICE_OBJECT *Device | |
298 | + ) | |
299 | +{ | |
300 | + int ret=0; | |
301 | + NETVSC_DEVICE *netDevice; | |
302 | + NVSP_MESSAGE *initPacket; | |
303 | + | |
304 | + DPRINT_ENTER(NETVSC); | |
305 | + | |
306 | + netDevice = GetOutboundNetDevice(Device); | |
307 | + if (!netDevice) | |
308 | + { | |
309 | + DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); | |
310 | + DPRINT_EXIT(NETVSC); | |
311 | + return -1; | |
312 | + } | |
313 | + ASSERT(netDevice->ReceiveBufferSize > 0); | |
314 | + ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE-1)) == 0); // page-size grandularity | |
315 | + | |
316 | + netDevice->ReceiveBuffer = PageAlloc(netDevice->ReceiveBufferSize >> PAGE_SHIFT); | |
317 | + if (!netDevice->ReceiveBuffer) | |
318 | + { | |
319 | + DPRINT_ERR(NETVSC, "unable to allocate receive buffer of size %d", netDevice->ReceiveBufferSize); | |
320 | + ret = -1; | |
321 | + goto Cleanup; | |
322 | + } | |
323 | + ASSERT(((ULONG_PTR)netDevice->ReceiveBuffer & (PAGE_SIZE-1)) == 0); // page-aligned buffer | |
324 | + | |
325 | + DPRINT_INFO(NETVSC, "Establishing receive buffer's GPADL..."); | |
326 | + | |
327 | + // Establish the gpadl handle for this buffer on this channel. | |
328 | + // Note: This call uses the vmbus connection rather than the channel to establish | |
329 | + // the gpadl handle. | |
330 | + ret = Device->Driver->VmbusChannelInterface.EstablishGpadl(Device, | |
331 | + netDevice->ReceiveBuffer, | |
332 | + netDevice->ReceiveBufferSize, | |
333 | + &netDevice->ReceiveBufferGpadlHandle); | |
334 | + | |
335 | + if (ret != 0) | |
336 | + { | |
337 | + DPRINT_ERR(NETVSC, "unable to establish receive buffer's gpadl"); | |
338 | + goto Cleanup; | |
339 | + } | |
340 | + | |
341 | + //WaitEventWait(ext->ChannelInitEvent); | |
342 | + | |
343 | + // Notify the NetVsp of the gpadl handle | |
344 | + DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendReceiveBuffer..."); | |
345 | + | |
346 | + initPacket = &netDevice->ChannelInitPacket; | |
347 | + | |
348 | + memset(initPacket, 0, sizeof(NVSP_MESSAGE)); | |
349 | + | |
350 | + initPacket->Header.MessageType = NvspMessage1TypeSendReceiveBuffer; | |
351 | + initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->ReceiveBufferGpadlHandle; | |
352 | + initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; | |
353 | + | |
354 | + // Send the gpadl notification request | |
355 | + ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, | |
356 | + initPacket, | |
357 | + sizeof(NVSP_MESSAGE), | |
358 | + (ULONG_PTR)initPacket, | |
359 | + VmbusPacketTypeDataInBand, | |
360 | + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | |
361 | + if (ret != 0) | |
362 | + { | |
363 | + DPRINT_ERR(NETVSC, "unable to send receive buffer's gpadl to netvsp"); | |
364 | + goto Cleanup; | |
365 | + } | |
366 | + | |
367 | + WaitEventWait(netDevice->ChannelInitEvent); | |
368 | + | |
369 | + // Check the response | |
370 | + if (initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status != NvspStatusSuccess) | |
371 | + { | |
372 | + DPRINT_ERR(NETVSC, | |
373 | + "Unable to complete receive buffer initialzation with NetVsp - status %d", | |
374 | + initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status); | |
375 | + ret = -1; | |
376 | + goto Cleanup; | |
377 | + } | |
378 | + | |
379 | + // Parse the response | |
380 | + ASSERT(netDevice->ReceiveSectionCount == 0); | |
381 | + ASSERT(netDevice->ReceiveSections == NULL); | |
382 | + | |
383 | + netDevice->ReceiveSectionCount = initPacket->Messages.Version1Messages.SendReceiveBufferComplete.NumSections; | |
384 | + | |
385 | + netDevice->ReceiveSections = MemAlloc(netDevice->ReceiveSectionCount * sizeof(NVSP_1_RECEIVE_BUFFER_SECTION)); | |
386 | + if (netDevice->ReceiveSections == NULL) | |
387 | + { | |
388 | + ret = -1; | |
389 | + goto Cleanup; | |
390 | + } | |
391 | + | |
392 | + memcpy(netDevice->ReceiveSections, | |
393 | + initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Sections, | |
394 | + netDevice->ReceiveSectionCount * sizeof(NVSP_1_RECEIVE_BUFFER_SECTION)); | |
395 | + | |
396 | + DPRINT_INFO(NETVSC, | |
397 | + "Receive sections info (count %d, offset %d, endoffset %d, suballoc size %d, num suballocs %d)", | |
398 | + netDevice->ReceiveSectionCount, netDevice->ReceiveSections[0].Offset, netDevice->ReceiveSections[0].EndOffset, | |
399 | + netDevice->ReceiveSections[0].SubAllocationSize, netDevice->ReceiveSections[0].NumSubAllocations); | |
400 | + | |
401 | + | |
402 | + //For 1st release, there should only be 1 section that represents the entire receive buffer | |
403 | + if (netDevice->ReceiveSectionCount != 1 || | |
404 | + netDevice->ReceiveSections->Offset != 0 ) | |
405 | + { | |
406 | + ret = -1; | |
407 | + goto Cleanup; | |
408 | + } | |
409 | + | |
410 | + goto Exit; | |
411 | + | |
412 | +Cleanup: | |
413 | + NetVscDestroyReceiveBuffer(netDevice); | |
414 | + | |
415 | +Exit: | |
416 | + PutNetDevice(Device); | |
417 | + DPRINT_EXIT(NETVSC); | |
418 | + return ret; | |
419 | +} | |
420 | + | |
421 | + | |
422 | +static int | |
423 | +NetVscInitializeSendBufferWithNetVsp( | |
424 | + DEVICE_OBJECT *Device | |
425 | + ) | |
426 | +{ | |
427 | + int ret=0; | |
428 | + NETVSC_DEVICE *netDevice; | |
429 | + NVSP_MESSAGE *initPacket; | |
430 | + | |
431 | + DPRINT_ENTER(NETVSC); | |
432 | + | |
433 | + netDevice = GetOutboundNetDevice(Device); | |
434 | + if (!netDevice) | |
435 | + { | |
436 | + DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); | |
437 | + DPRINT_EXIT(NETVSC); | |
438 | + return -1; | |
439 | + } | |
440 | + ASSERT(netDevice->SendBufferSize > 0); | |
441 | + ASSERT((netDevice->SendBufferSize & (PAGE_SIZE-1)) == 0); // page-size grandularity | |
442 | + | |
443 | + netDevice->SendBuffer = PageAlloc(netDevice->SendBufferSize >> PAGE_SHIFT); | |
444 | + if (!netDevice->SendBuffer) | |
445 | + { | |
446 | + DPRINT_ERR(NETVSC, "unable to allocate send buffer of size %d", netDevice->SendBufferSize); | |
447 | + ret = -1; | |
448 | + goto Cleanup; | |
449 | + } | |
450 | + ASSERT(((ULONG_PTR)netDevice->SendBuffer & (PAGE_SIZE-1)) == 0); // page-aligned buffer | |
451 | + | |
452 | + DPRINT_INFO(NETVSC, "Establishing send buffer's GPADL..."); | |
453 | + | |
454 | + // Establish the gpadl handle for this buffer on this channel. | |
455 | + // Note: This call uses the vmbus connection rather than the channel to establish | |
456 | + // the gpadl handle. | |
457 | + ret = Device->Driver->VmbusChannelInterface.EstablishGpadl(Device, | |
458 | + netDevice->SendBuffer, | |
459 | + netDevice->SendBufferSize, | |
460 | + &netDevice->SendBufferGpadlHandle); | |
461 | + | |
462 | + if (ret != 0) | |
463 | + { | |
464 | + DPRINT_ERR(NETVSC, "unable to establish send buffer's gpadl"); | |
465 | + goto Cleanup; | |
466 | + } | |
467 | + | |
468 | + //WaitEventWait(ext->ChannelInitEvent); | |
469 | + | |
470 | + // Notify the NetVsp of the gpadl handle | |
471 | + DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendSendBuffer..."); | |
472 | + | |
473 | + initPacket = &netDevice->ChannelInitPacket; | |
474 | + | |
475 | + memset(initPacket, 0, sizeof(NVSP_MESSAGE)); | |
476 | + | |
477 | + initPacket->Header.MessageType = NvspMessage1TypeSendSendBuffer; | |
478 | + initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->SendBufferGpadlHandle; | |
479 | + initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_SEND_BUFFER_ID; | |
480 | + | |
481 | + // Send the gpadl notification request | |
482 | + ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, | |
483 | + initPacket, | |
484 | + sizeof(NVSP_MESSAGE), | |
485 | + (ULONG_PTR)initPacket, | |
486 | + VmbusPacketTypeDataInBand, | |
487 | + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | |
488 | + if (ret != 0) | |
489 | + { | |
490 | + DPRINT_ERR(NETVSC, "unable to send receive buffer's gpadl to netvsp"); | |
491 | + goto Cleanup; | |
492 | + } | |
493 | + | |
494 | + WaitEventWait(netDevice->ChannelInitEvent); | |
495 | + | |
496 | + // Check the response | |
497 | + if (initPacket->Messages.Version1Messages.SendSendBufferComplete.Status != NvspStatusSuccess) | |
498 | + { | |
499 | + DPRINT_ERR(NETVSC, | |
500 | + "Unable to complete send buffer initialzation with NetVsp - status %d", | |
501 | + initPacket->Messages.Version1Messages.SendSendBufferComplete.Status); | |
502 | + ret = -1; | |
503 | + goto Cleanup; | |
504 | + } | |
505 | + | |
506 | + netDevice->SendSectionSize = initPacket->Messages.Version1Messages.SendSendBufferComplete.SectionSize; | |
507 | + | |
508 | + goto Exit; | |
509 | + | |
510 | +Cleanup: | |
511 | + NetVscDestroySendBuffer(netDevice); | |
512 | + | |
513 | +Exit: | |
514 | + PutNetDevice(Device); | |
515 | + DPRINT_EXIT(NETVSC); | |
516 | + return ret; | |
517 | +} | |
518 | + | |
519 | +static int | |
520 | +NetVscDestroyReceiveBuffer( | |
521 | + NETVSC_DEVICE *NetDevice | |
522 | + ) | |
523 | +{ | |
524 | + NVSP_MESSAGE *revokePacket; | |
525 | + int ret=0; | |
526 | + | |
527 | + | |
528 | + DPRINT_ENTER(NETVSC); | |
529 | + | |
530 | + // If we got a section count, it means we received a SendReceiveBufferComplete msg | |
531 | + // (ie sent NvspMessage1TypeSendReceiveBuffer msg) therefore, we need to send a revoke msg here | |
532 | + if (NetDevice->ReceiveSectionCount) | |
533 | + { | |
534 | + DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeRevokeReceiveBuffer..."); | |
535 | + | |
536 | + // Send the revoke receive buffer | |
537 | + revokePacket = &NetDevice->RevokePacket; | |
538 | + memset(revokePacket, 0, sizeof(NVSP_MESSAGE)); | |
539 | + | |
540 | + revokePacket->Header.MessageType = NvspMessage1TypeRevokeReceiveBuffer; | |
541 | + revokePacket->Messages.Version1Messages.RevokeReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; | |
542 | + | |
543 | + ret = NetDevice->Device->Driver->VmbusChannelInterface.SendPacket(NetDevice->Device, | |
544 | + revokePacket, | |
545 | + sizeof(NVSP_MESSAGE), | |
546 | + (ULONG_PTR)revokePacket, | |
547 | + VmbusPacketTypeDataInBand, | |
548 | + 0); | |
549 | + // If we failed here, we might as well return and have a leak rather than continue and a bugchk | |
550 | + if (ret != 0) | |
551 | + { | |
552 | + DPRINT_ERR(NETVSC, "unable to send revoke receive buffer to netvsp"); | |
553 | + DPRINT_EXIT(NETVSC); | |
554 | + return -1; | |
555 | + } | |
556 | + } | |
557 | + | |
558 | + // Teardown the gpadl on the vsp end | |
559 | + if (NetDevice->ReceiveBufferGpadlHandle) | |
560 | + { | |
561 | + DPRINT_INFO(NETVSC, "Tearing down receive buffer's GPADL..."); | |
562 | + | |
563 | + ret = NetDevice->Device->Driver->VmbusChannelInterface.TeardownGpadl(NetDevice->Device, | |
564 | + NetDevice->ReceiveBufferGpadlHandle); | |
565 | + | |
566 | + // If we failed here, we might as well return and have a leak rather than continue and a bugchk | |
567 | + if (ret != 0) | |
568 | + { | |
569 | + DPRINT_ERR(NETVSC, "unable to teardown receive buffer's gpadl"); | |
570 | + DPRINT_EXIT(NETVSC); | |
571 | + return -1; | |
572 | + } | |
573 | + NetDevice->ReceiveBufferGpadlHandle = 0; | |
574 | + } | |
575 | + | |
576 | + if (NetDevice->ReceiveBuffer) | |
577 | + { | |
578 | + DPRINT_INFO(NETVSC, "Freeing up receive buffer..."); | |
579 | + | |
580 | + // Free up the receive buffer | |
581 | + PageFree(NetDevice->ReceiveBuffer, NetDevice->ReceiveBufferSize >> PAGE_SHIFT); | |
582 | + NetDevice->ReceiveBuffer = NULL; | |
583 | + } | |
584 | + | |
585 | + if (NetDevice->ReceiveSections) | |
586 | + { | |
587 | + MemFree(NetDevice->ReceiveSections); | |
588 | + NetDevice->ReceiveSections = NULL; | |
589 | + NetDevice->ReceiveSectionCount = 0; | |
590 | + } | |
591 | + | |
592 | + DPRINT_EXIT(NETVSC); | |
593 | + | |
594 | + return ret; | |
595 | +} | |
596 | + | |
597 | + | |
598 | + | |
599 | + | |
600 | +static int | |
601 | +NetVscDestroySendBuffer( | |
602 | + NETVSC_DEVICE *NetDevice | |
603 | + ) | |
604 | +{ | |
605 | + NVSP_MESSAGE *revokePacket; | |
606 | + int ret=0; | |
607 | + | |
608 | + | |
609 | + DPRINT_ENTER(NETVSC); | |
610 | + | |
611 | + // If we got a section count, it means we received a SendReceiveBufferComplete msg | |
612 | + // (ie sent NvspMessage1TypeSendReceiveBuffer msg) therefore, we need to send a revoke msg here | |
613 | + if (NetDevice->SendSectionSize) | |
614 | + { | |
615 | + DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeRevokeSendBuffer..."); | |
616 | + | |
617 | + // Send the revoke send buffer | |
618 | + revokePacket = &NetDevice->RevokePacket; | |
619 | + memset(revokePacket, 0, sizeof(NVSP_MESSAGE)); | |
620 | + | |
621 | + revokePacket->Header.MessageType = NvspMessage1TypeRevokeSendBuffer; | |
622 | + revokePacket->Messages.Version1Messages.RevokeSendBuffer.Id = NETVSC_SEND_BUFFER_ID; | |
623 | + | |
624 | + ret = NetDevice->Device->Driver->VmbusChannelInterface.SendPacket(NetDevice->Device, | |
625 | + revokePacket, | |
626 | + sizeof(NVSP_MESSAGE), | |
627 | + (ULONG_PTR)revokePacket, | |
628 | + VmbusPacketTypeDataInBand, | |
629 | + 0); | |
630 | + // If we failed here, we might as well return and have a leak rather than continue and a bugchk | |
631 | + if (ret != 0) | |
632 | + { | |
633 | + DPRINT_ERR(NETVSC, "unable to send revoke send buffer to netvsp"); | |
634 | + DPRINT_EXIT(NETVSC); | |
635 | + return -1; | |
636 | + } | |
637 | + } | |
638 | + | |
639 | + // Teardown the gpadl on the vsp end | |
640 | + if (NetDevice->SendBufferGpadlHandle) | |
641 | + { | |
642 | + DPRINT_INFO(NETVSC, "Tearing down send buffer's GPADL..."); | |
643 | + | |
644 | + ret = NetDevice->Device->Driver->VmbusChannelInterface.TeardownGpadl(NetDevice->Device, | |
645 | + NetDevice->SendBufferGpadlHandle); | |
646 | + | |
647 | + // If we failed here, we might as well return and have a leak rather than continue and a bugchk | |
648 | + if (ret != 0) | |
649 | + { | |
650 | + DPRINT_ERR(NETVSC, "unable to teardown send buffer's gpadl"); | |
651 | + DPRINT_EXIT(NETVSC); | |
652 | + return -1; | |
653 | + } | |
654 | + NetDevice->SendBufferGpadlHandle = 0; | |
655 | + } | |
656 | + | |
657 | + if (NetDevice->SendBuffer) | |
658 | + { | |
659 | + DPRINT_INFO(NETVSC, "Freeing up send buffer..."); | |
660 | + | |
661 | + // Free up the receive buffer | |
662 | + PageFree(NetDevice->SendBuffer, NetDevice->SendBufferSize >> PAGE_SHIFT); | |
663 | + NetDevice->SendBuffer = NULL; | |
664 | + } | |
665 | + | |
666 | + DPRINT_EXIT(NETVSC); | |
667 | + | |
668 | + return ret; | |
669 | +} | |
670 | + | |
671 | + | |
672 | + | |
673 | +static int | |
674 | +NetVscConnectToVsp( | |
675 | + DEVICE_OBJECT *Device | |
676 | + ) | |
677 | +{ | |
678 | + int ret=0; | |
679 | + NETVSC_DEVICE *netDevice; | |
680 | + NVSP_MESSAGE *initPacket; | |
681 | + int ndisVersion; | |
682 | + | |
683 | + DPRINT_ENTER(NETVSC); | |
684 | + | |
685 | + netDevice = GetOutboundNetDevice(Device); | |
686 | + if (!netDevice) | |
687 | + { | |
688 | + DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); | |
689 | + DPRINT_EXIT(NETVSC); | |
690 | + return -1; | |
691 | + } | |
692 | + | |
693 | + initPacket = &netDevice->ChannelInitPacket; | |
694 | + | |
695 | + memset(initPacket, 0, sizeof(NVSP_MESSAGE)); | |
696 | + initPacket->Header.MessageType = NvspMessageTypeInit; | |
697 | + initPacket->Messages.InitMessages.Init.MinProtocolVersion = NVSP_MIN_PROTOCOL_VERSION; | |
698 | + initPacket->Messages.InitMessages.Init.MaxProtocolVersion = NVSP_MAX_PROTOCOL_VERSION; | |
699 | + | |
700 | + DPRINT_INFO(NETVSC, "Sending NvspMessageTypeInit..."); | |
701 | + | |
702 | + // Send the init request | |
703 | + ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, | |
704 | + initPacket, | |
705 | + sizeof(NVSP_MESSAGE), | |
706 | + (ULONG_PTR)initPacket, | |
707 | + VmbusPacketTypeDataInBand, | |
708 | + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | |
709 | + | |
710 | + if( ret != 0) | |
711 | + { | |
712 | + DPRINT_ERR(NETVSC, "unable to send NvspMessageTypeInit"); | |
713 | + goto Cleanup; | |
714 | + } | |
715 | + | |
716 | + WaitEventWait(netDevice->ChannelInitEvent); | |
717 | + | |
718 | + // Now, check the response | |
719 | + //ASSERT(initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength <= MAX_MULTIPAGE_BUFFER_COUNT); | |
720 | + DPRINT_INFO(NETVSC, "NvspMessageTypeInit status(%d) max mdl chain (%d)", | |
721 | + initPacket->Messages.InitMessages.InitComplete.Status, | |
722 | + initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength); | |
723 | + | |
724 | + if (initPacket->Messages.InitMessages.InitComplete.Status != NvspStatusSuccess) | |
725 | + { | |
726 | + DPRINT_ERR(NETVSC, "unable to initialize with netvsp (status 0x%x)", initPacket->Messages.InitMessages.InitComplete.Status); | |
727 | + ret = -1; | |
728 | + goto Cleanup; | |
729 | + } | |
730 | + | |
731 | + if (initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion != NVSP_PROTOCOL_VERSION_1) | |
732 | + { | |
733 | + DPRINT_ERR(NETVSC, "unable to initialize with netvsp (version expected 1 got %d)", | |
734 | + initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion); | |
735 | + ret = -1; | |
736 | + goto Cleanup; | |
737 | + } | |
738 | + DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendNdisVersion..."); | |
739 | + | |
740 | + // Send the ndis version | |
741 | + memset(initPacket, 0, sizeof(NVSP_MESSAGE)); | |
742 | + | |
743 | + ndisVersion = 0x00050000; | |
744 | + | |
745 | + initPacket->Header.MessageType = NvspMessage1TypeSendNdisVersion; | |
746 | + initPacket->Messages.Version1Messages.SendNdisVersion.NdisMajorVersion = (ndisVersion & 0xFFFF0000) >> 16; | |
747 | + initPacket->Messages.Version1Messages.SendNdisVersion.NdisMinorVersion = ndisVersion & 0xFFFF; | |
748 | + | |
749 | + // Send the init request | |
750 | + ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, | |
751 | + initPacket, | |
752 | + sizeof(NVSP_MESSAGE), | |
753 | + (ULONG_PTR)initPacket, | |
754 | + VmbusPacketTypeDataInBand, | |
755 | + 0); | |
756 | + if (ret != 0) | |
757 | + { | |
758 | + DPRINT_ERR(NETVSC, "unable to send NvspMessage1TypeSendNdisVersion"); | |
759 | + ret = -1; | |
760 | + goto Cleanup; | |
761 | + } | |
762 | + // | |
763 | + // BUGBUG - We have to wait for the above msg since the netvsp uses KMCL which acknowledges packet (completion packet) | |
764 | + // since our Vmbus always set the VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag | |
765 | + //WaitEventWait(NetVscChannel->ChannelInitEvent); | |
766 | + | |
767 | + // Post the big receive buffer to NetVSP | |
768 | + ret = NetVscInitializeReceiveBufferWithNetVsp(Device); | |
769 | + if (ret == 0) | |
770 | + { | |
771 | + ret = NetVscInitializeSendBufferWithNetVsp(Device); | |
772 | + } | |
773 | + | |
774 | +Cleanup: | |
775 | + PutNetDevice(Device); | |
776 | + DPRINT_EXIT(NETVSC); | |
777 | + return ret; | |
778 | +} | |
779 | + | |
780 | +static void | |
781 | +NetVscDisconnectFromVsp( | |
782 | + NETVSC_DEVICE *NetDevice | |
783 | + ) | |
784 | +{ | |
785 | + DPRINT_ENTER(NETVSC); | |
786 | + | |
787 | + NetVscDestroyReceiveBuffer(NetDevice); | |
788 | + NetVscDestroySendBuffer(NetDevice); | |
789 | + | |
790 | + DPRINT_EXIT(NETVSC); | |
791 | +} | |
792 | + | |
793 | + | |
794 | +/*++ | |
795 | + | |
796 | +Name: | |
797 | + NetVscOnDeviceAdd() | |
798 | + | |
799 | +Description: | |
800 | + Callback when the device belonging to this driver is added | |
801 | + | |
802 | +--*/ | |
803 | +int | |
804 | +NetVscOnDeviceAdd( | |
805 | + DEVICE_OBJECT *Device, | |
806 | + void *AdditionalInfo | |
807 | + ) | |
808 | +{ | |
809 | + int ret=0; | |
810 | + int i; | |
811 | + | |
812 | + NETVSC_DEVICE* netDevice; | |
813 | + NETVSC_PACKET* packet; | |
814 | + LIST_ENTRY *entry; | |
815 | + | |
816 | + NETVSC_DRIVER_OBJECT *netDriver = (NETVSC_DRIVER_OBJECT*) Device->Driver;; | |
817 | + | |
818 | + DPRINT_ENTER(NETVSC); | |
819 | + | |
820 | + netDevice = AllocNetDevice(Device); | |
821 | + if (!netDevice) | |
822 | + { | |
823 | + ret = -1; | |
824 | + goto Cleanup; | |
825 | + } | |
826 | + | |
827 | + DPRINT_DBG(NETVSC, "netvsc channel object allocated - %p", netDevice); | |
828 | + | |
829 | + // Initialize the NetVSC channel extension | |
830 | + netDevice->ReceiveBufferSize = NETVSC_RECEIVE_BUFFER_SIZE; | |
831 | + netDevice->ReceivePacketListLock = SpinlockCreate(); | |
832 | + | |
833 | + netDevice->SendBufferSize = NETVSC_SEND_BUFFER_SIZE; | |
834 | + | |
835 | + INITIALIZE_LIST_HEAD(&netDevice->ReceivePacketList); | |
836 | + | |
837 | + for (i=0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) | |
838 | + { | |
839 | + packet = MemAllocZeroed(sizeof(NETVSC_PACKET) + (NETVSC_RECEIVE_SG_COUNT* sizeof(PAGE_BUFFER))); | |
840 | + if (!packet) | |
841 | + { | |
842 | + DPRINT_DBG(NETVSC, "unable to allocate netvsc pkts for receive pool (wanted %d got %d)", NETVSC_RECEIVE_PACKETLIST_COUNT, i); | |
843 | + break; | |
844 | + } | |
845 | + | |
846 | + INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &packet->ListEntry); | |
847 | + } | |
848 | + netDevice->ChannelInitEvent = WaitEventCreate(); | |
849 | + | |
850 | + // Open the channel | |
851 | + ret = Device->Driver->VmbusChannelInterface.Open(Device, | |
852 | + netDriver->RingBufferSize, | |
853 | + netDriver->RingBufferSize, | |
854 | + NULL, 0, | |
855 | + NetVscOnChannelCallback, | |
856 | + Device | |
857 | + ); | |
858 | + | |
859 | + if (ret != 0) | |
860 | + { | |
861 | + DPRINT_ERR(NETVSC, "unable to open channel: %d", ret); | |
862 | + ret = -1; | |
863 | + goto Cleanup; | |
864 | + } | |
865 | + | |
866 | + // Channel is opened | |
867 | + DPRINT_INFO(NETVSC, "*** NetVSC channel opened successfully! ***"); | |
868 | + | |
869 | + // Connect with the NetVsp | |
870 | + ret = NetVscConnectToVsp(Device); | |
871 | + if (ret != 0) | |
872 | + { | |
873 | + DPRINT_ERR(NETVSC, "unable to connect to NetVSP - %d", ret); | |
874 | + ret = -1; | |
875 | + goto Close; | |
876 | + } | |
877 | + | |
878 | + DPRINT_INFO(NETVSC, "*** NetVSC channel handshake result - %d ***", ret); | |
879 | + | |
880 | + DPRINT_EXIT(NETVSC); | |
881 | + return ret; | |
882 | + | |
883 | +Close: | |
884 | + // Now, we can close the channel safely | |
885 | + Device->Driver->VmbusChannelInterface.Close(Device); | |
886 | + | |
887 | +Cleanup: | |
888 | + | |
889 | + if (netDevice) | |
890 | + { | |
891 | + WaitEventClose(netDevice->ChannelInitEvent); | |
892 | + | |
893 | + while (!IsListEmpty(&netDevice->ReceivePacketList)) | |
894 | + { | |
895 | + entry = REMOVE_HEAD_LIST(&netDevice->ReceivePacketList); | |
896 | + packet = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry); | |
897 | + MemFree(packet); | |
898 | + } | |
899 | + | |
900 | + SpinlockClose(netDevice->ReceivePacketListLock); | |
901 | + | |
902 | + ReleaseOutboundNetDevice(Device); | |
903 | + ReleaseInboundNetDevice(Device); | |
904 | + | |
905 | + FreeNetDevice(netDevice); | |
906 | + } | |
907 | + | |
908 | + DPRINT_EXIT(NETVSC); | |
909 | + return ret; | |
910 | +} | |
911 | + | |
912 | + | |
913 | +/*++ | |
914 | + | |
915 | +Name: | |
916 | + NetVscOnDeviceRemove() | |
917 | + | |
918 | +Description: | |
919 | + Callback when the root bus device is removed | |
920 | + | |
921 | +--*/ | |
922 | +int | |
923 | +NetVscOnDeviceRemove( | |
924 | + DEVICE_OBJECT *Device | |
925 | + ) | |
926 | +{ | |
927 | + NETVSC_DEVICE *netDevice; | |
928 | + NETVSC_PACKET *netvscPacket; | |
929 | + int ret=0; | |
930 | + LIST_ENTRY *entry; | |
931 | + | |
932 | + DPRINT_ENTER(NETVSC); | |
933 | + | |
934 | + DPRINT_INFO(NETVSC, "Disabling outbound traffic on net device (%p)...", Device->Extension); | |
935 | + | |
936 | + // Stop outbound traffic ie sends and receives completions | |
937 | + netDevice = ReleaseOutboundNetDevice(Device); | |
938 | + if (!netDevice) | |
939 | + { | |
940 | + DPRINT_ERR(NETVSC, "No net device present!!"); | |
941 | + return -1; | |
942 | + } | |
943 | + | |
944 | + // Wait for all send completions | |
945 | + while (netDevice->NumOutstandingSends) | |
946 | + { | |
947 | + DPRINT_INFO(NETVSC, "waiting for %d requests to complete...", netDevice->NumOutstandingSends); | |
948 | + | |
949 | + Sleep(100); | |
950 | + } | |
951 | + | |
952 | + DPRINT_INFO(NETVSC, "Disconnecting from netvsp..."); | |
953 | + | |
954 | + NetVscDisconnectFromVsp(netDevice); | |
955 | + | |
956 | + DPRINT_INFO(NETVSC, "Disabling inbound traffic on net device (%p)...", Device->Extension); | |
957 | + | |
958 | + // Stop inbound traffic ie receives and sends completions | |
959 | + netDevice = ReleaseInboundNetDevice(Device); | |
960 | + | |
961 | + // At this point, no one should be accessing netDevice except in here | |
962 | + DPRINT_INFO(NETVSC, "net device (%p) safe to remove", netDevice); | |
963 | + | |
964 | + // Now, we can close the channel safely | |
965 | + Device->Driver->VmbusChannelInterface.Close(Device); | |
966 | + | |
967 | + // Release all resources | |
968 | + while (!IsListEmpty(&netDevice->ReceivePacketList)) | |
969 | + { | |
970 | + entry = REMOVE_HEAD_LIST(&netDevice->ReceivePacketList); | |
971 | + netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry); | |
972 | + | |
973 | + MemFree(netvscPacket); | |
974 | + } | |
975 | + | |
976 | + SpinlockClose(netDevice->ReceivePacketListLock); | |
977 | + WaitEventClose(netDevice->ChannelInitEvent); | |
978 | + FreeNetDevice(netDevice); | |
979 | + | |
980 | + DPRINT_EXIT(NETVSC); | |
981 | + return ret; | |
982 | +} | |
983 | + | |
984 | + | |
985 | + | |
986 | +/*++ | |
987 | + | |
988 | +Name: | |
989 | + NetVscOnCleanup() | |
990 | + | |
991 | +Description: | |
992 | + Perform any cleanup when the driver is removed | |
993 | + | |
994 | +--*/ | |
995 | +void | |
996 | +NetVscOnCleanup( | |
997 | + DRIVER_OBJECT *drv | |
998 | + ) | |
999 | +{ | |
1000 | + DPRINT_ENTER(NETVSC); | |
1001 | + | |
1002 | + DPRINT_EXIT(NETVSC); | |
1003 | +} | |
1004 | + | |
1005 | +static void | |
1006 | +NetVscOnSendCompletion( | |
1007 | + DEVICE_OBJECT *Device, | |
1008 | + VMPACKET_DESCRIPTOR *Packet | |
1009 | + ) | |
1010 | +{ | |
1011 | + NETVSC_DEVICE* netDevice; | |
1012 | + NVSP_MESSAGE *nvspPacket; | |
1013 | + NETVSC_PACKET *nvscPacket; | |
1014 | + | |
1015 | + DPRINT_ENTER(NETVSC); | |
1016 | + | |
1017 | + netDevice = GetInboundNetDevice(Device); | |
1018 | + if (!netDevice) | |
1019 | + { | |
1020 | + DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); | |
1021 | + DPRINT_EXIT(NETVSC); | |
1022 | + return; | |
1023 | + } | |
1024 | + | |
1025 | + nvspPacket = (NVSP_MESSAGE*)((ULONG_PTR)Packet + (Packet->DataOffset8 << 3)); | |
1026 | + | |
1027 | + DPRINT_DBG(NETVSC, "send completion packet - type %d", nvspPacket->Header.MessageType); | |
1028 | + | |
1029 | + if (nvspPacket->Header.MessageType == NvspMessageTypeInitComplete || | |
1030 | + nvspPacket->Header.MessageType == NvspMessage1TypeSendReceiveBufferComplete || | |
1031 | + nvspPacket->Header.MessageType == NvspMessage1TypeSendSendBufferComplete) | |
1032 | + { | |
1033 | + // Copy the response back | |
1034 | + memcpy(&netDevice->ChannelInitPacket, nvspPacket, sizeof(NVSP_MESSAGE)); | |
1035 | + WaitEventSet(netDevice->ChannelInitEvent); | |
1036 | + } | |
1037 | + else if (nvspPacket->Header.MessageType == NvspMessage1TypeSendRNDISPacketComplete) | |
1038 | + { | |
1039 | + // Get the send context | |
1040 | + nvscPacket = (NETVSC_PACKET *)(ULONG_PTR)Packet->TransactionId; | |
1041 | + ASSERT(nvscPacket); | |
1042 | + | |
1043 | + // Notify the layer above us | |
1044 | + nvscPacket->Completion.Send.OnSendCompletion(nvscPacket->Completion.Send.SendCompletionContext); | |
1045 | + | |
1046 | + InterlockedDecrement(&netDevice->NumOutstandingSends); | |
1047 | + } | |
1048 | + else | |
1049 | + { | |
1050 | + DPRINT_ERR(NETVSC, "Unknown send completion packet type - %d received!!", nvspPacket->Header.MessageType); | |
1051 | + } | |
1052 | + | |
1053 | + PutNetDevice(Device); | |
1054 | + DPRINT_EXIT(NETVSC); | |
1055 | +} | |
1056 | + | |
1057 | + | |
1058 | + | |
1059 | +static int | |
1060 | +NetVscOnSend( | |
1061 | + DEVICE_OBJECT *Device, | |
1062 | + NETVSC_PACKET *Packet | |
1063 | + ) | |
1064 | +{ | |
1065 | + NETVSC_DEVICE* netDevice; | |
1066 | + int ret=0; | |
1067 | + | |
1068 | + NVSP_MESSAGE sendMessage; | |
1069 | + | |
1070 | + DPRINT_ENTER(NETVSC); | |
1071 | + | |
1072 | + netDevice = GetOutboundNetDevice(Device); | |
1073 | + if (!netDevice) | |
1074 | + { | |
1075 | + DPRINT_ERR(NETVSC, "net device (%p) shutting down...ignoring outbound packets", netDevice); | |
1076 | + DPRINT_EXIT(NETVSC); | |
1077 | + return -2; | |
1078 | + } | |
1079 | + | |
1080 | + sendMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacket; | |
1081 | + if (Packet->IsDataPacket) | |
1082 | + sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 0;// 0 is RMC_DATA; | |
1083 | + else | |
1084 | + sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 1;// 1 is RMC_CONTROL; | |
1085 | + | |
1086 | + // Not using send buffer section | |
1087 | + sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionIndex = 0xFFFFFFFF; | |
1088 | + sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionSize = 0; | |
1089 | + | |
1090 | + if (Packet->PageBufferCount) | |
1091 | + { | |
1092 | + ret = Device->Driver->VmbusChannelInterface.SendPacketPageBuffer(Device, | |
1093 | + Packet->PageBuffers, | |
1094 | + Packet->PageBufferCount, | |
1095 | + &sendMessage, | |
1096 | + sizeof(NVSP_MESSAGE), | |
1097 | + (ULONG_PTR)Packet); | |
1098 | + } | |
1099 | + else | |
1100 | + { | |
1101 | + ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, | |
1102 | + &sendMessage, | |
1103 | + sizeof(NVSP_MESSAGE), | |
1104 | + (ULONG_PTR)Packet, | |
1105 | + VmbusPacketTypeDataInBand, | |
1106 | + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | |
1107 | + | |
1108 | + } | |
1109 | + | |
1110 | + if (ret != 0) | |
1111 | + { | |
1112 | + DPRINT_ERR(NETVSC, "Unable to send packet %p ret %d", Packet, ret); | |
1113 | + } | |
1114 | + | |
1115 | + InterlockedIncrement(&netDevice->NumOutstandingSends); | |
1116 | + PutNetDevice(Device); | |
1117 | + | |
1118 | + DPRINT_EXIT(NETVSC); | |
1119 | + return ret; | |
1120 | +} | |
1121 | + | |
1122 | + | |
1123 | +static void | |
1124 | +NetVscOnReceive( | |
1125 | + DEVICE_OBJECT *Device, | |
1126 | + VMPACKET_DESCRIPTOR *Packet | |
1127 | + ) | |
1128 | +{ | |
1129 | + NETVSC_DEVICE* netDevice; | |
1130 | + VMTRANSFER_PAGE_PACKET_HEADER *vmxferpagePacket; | |
1131 | + NVSP_MESSAGE *nvspPacket; | |
1132 | + NETVSC_PACKET *netvscPacket=NULL; | |
1133 | + LIST_ENTRY* entry; | |
1134 | + ULONG_PTR start; | |
1135 | + ULONG_PTR end, endVirtual; | |
1136 | + //NETVSC_DRIVER_OBJECT *netvscDriver; | |
1137 | + XFERPAGE_PACKET *xferpagePacket=NULL; | |
1138 | + LIST_ENTRY listHead; | |
1139 | + | |
1140 | + int i=0, j=0; | |
1141 | + int count=0, bytesRemain=0; | |
1142 | + | |
1143 | + DPRINT_ENTER(NETVSC); | |
1144 | + | |
1145 | + netDevice = GetInboundNetDevice(Device); | |
1146 | + if (!netDevice) | |
1147 | + { | |
1148 | + DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); | |
1149 | + DPRINT_EXIT(NETVSC); | |
1150 | + return; | |
1151 | + } | |
1152 | + | |
1153 | + // All inbound packets other than send completion should be xfer page packet | |
1154 | + if (Packet->Type != VmbusPacketTypeDataUsingTransferPages) | |
1155 | + { | |
1156 | + DPRINT_ERR(NETVSC, "Unknown packet type received - %d", Packet->Type); | |
1157 | + PutNetDevice(Device); | |
1158 | + return; | |
1159 | + } | |
1160 | + | |
1161 | + nvspPacket = (NVSP_MESSAGE*)((ULONG_PTR)Packet + (Packet->DataOffset8 << 3)); | |
1162 | + | |
1163 | + // Make sure this is a valid nvsp packet | |
1164 | + if (nvspPacket->Header.MessageType != NvspMessage1TypeSendRNDISPacket ) | |
1165 | + { | |
1166 | + DPRINT_ERR(NETVSC, "Unknown nvsp packet type received - %d", nvspPacket->Header.MessageType); | |
1167 | + PutNetDevice(Device); | |
1168 | + return; | |
1169 | + } | |
1170 | + | |
1171 | + DPRINT_DBG(NETVSC, "NVSP packet received - type %d", nvspPacket->Header.MessageType); | |
1172 | + | |
1173 | + vmxferpagePacket = (VMTRANSFER_PAGE_PACKET_HEADER*)Packet; | |
1174 | + | |
1175 | + if (vmxferpagePacket->TransferPageSetId != NETVSC_RECEIVE_BUFFER_ID) | |
1176 | + { | |
1177 | + DPRINT_ERR(NETVSC, "Invalid xfer page set id - expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID, vmxferpagePacket->TransferPageSetId); | |
1178 | + PutNetDevice(Device); | |
1179 | + return; | |
1180 | + } | |
1181 | + | |
1182 | + DPRINT_DBG(NETVSC, "xfer page - range count %d", vmxferpagePacket->RangeCount); | |
1183 | + | |
1184 | + INITIALIZE_LIST_HEAD(&listHead); | |
1185 | + | |
1186 | + // Grab free packets (range count + 1) to represent this xfer page packet. +1 to represent | |
1187 | + // the xfer page packet itself. We grab it here so that we know exactly how many we can fulfil | |
1188 | + SpinlockAcquire(netDevice->ReceivePacketListLock); | |
1189 | + while (!IsListEmpty(&netDevice->ReceivePacketList)) | |
1190 | + { | |
1191 | + entry = REMOVE_HEAD_LIST(&netDevice->ReceivePacketList); | |
1192 | + netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry); | |
1193 | + | |
1194 | + INSERT_TAIL_LIST(&listHead, &netvscPacket->ListEntry); | |
1195 | + | |
1196 | + if (++count == vmxferpagePacket->RangeCount + 1) | |
1197 | + break; | |
1198 | + } | |
1199 | + SpinlockRelease(netDevice->ReceivePacketListLock); | |
1200 | + | |
1201 | + // We need at least 2 netvsc pkts (1 to represent the xfer page and at least 1 for the range) | |
1202 | + // i.e. we can handled some of the xfer page packet ranges... | |
1203 | + if (count < 2) | |
1204 | + { | |
1205 | + DPRINT_ERR(NETVSC, "Got only %d netvsc pkt...needed %d pkts. Dropping this xfer page packet completely!", count, vmxferpagePacket->RangeCount+1); | |
1206 | + | |
1207 | + // Return it to the freelist | |
1208 | + SpinlockAcquire(netDevice->ReceivePacketListLock); | |
1209 | + for (i=count; i != 0; i--) | |
1210 | + { | |
1211 | + entry = REMOVE_HEAD_LIST(&listHead); | |
1212 | + netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry); | |
1213 | + | |
1214 | + INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &netvscPacket->ListEntry); | |
1215 | + } | |
1216 | + SpinlockRelease(netDevice->ReceivePacketListLock); | |
1217 | + | |
1218 | + NetVscSendReceiveCompletion(Device, vmxferpagePacket->d.TransactionId); | |
1219 | + | |
1220 | + PutNetDevice(Device); | |
1221 | + return; | |
1222 | + } | |
1223 | + | |
1224 | + // Remove the 1st packet to represent the xfer page packet itself | |
1225 | + entry = REMOVE_HEAD_LIST(&listHead); | |
1226 | + xferpagePacket = CONTAINING_RECORD(entry, XFERPAGE_PACKET, ListEntry); | |
1227 | + xferpagePacket->Count = count - 1; // This is how much we can satisfy | |
1228 | + ASSERT(xferpagePacket->Count > 0 && xferpagePacket->Count <= vmxferpagePacket->RangeCount); | |
1229 | + | |
1230 | + if (xferpagePacket->Count != vmxferpagePacket->RangeCount) | |
1231 | + { | |
1232 | + DPRINT_INFO(NETVSC, "Needed %d netvsc pkts to satisy this xfer page...got %d", vmxferpagePacket->RangeCount, xferpagePacket->Count); | |
1233 | + } | |
1234 | + | |
1235 | + // Each range represents 1 RNDIS pkt that contains 1 ethernet frame | |
1236 | + for (i=0; i < (count - 1); i++) | |
1237 | + { | |
1238 | + entry = REMOVE_HEAD_LIST(&listHead); | |
1239 | + netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry); | |
1240 | + | |
1241 | + // Initialize the netvsc packet | |
1242 | + netvscPacket->XferPagePacket = xferpagePacket; | |
1243 | + netvscPacket->Completion.Recv.OnReceiveCompletion = NetVscOnReceiveCompletion; | |
1244 | + netvscPacket->Completion.Recv.ReceiveCompletionContext = netvscPacket; | |
1245 | + netvscPacket->Device = Device; | |
1246 | + netvscPacket->Completion.Recv.ReceiveCompletionTid = vmxferpagePacket->d.TransactionId; // Save this so that we can send it back | |
1247 | + | |
1248 | + netvscPacket->TotalDataBufferLength = vmxferpagePacket->Ranges[i].ByteCount; | |
1249 | + netvscPacket->PageBufferCount = 1; | |
1250 | + | |
1251 | + ASSERT(vmxferpagePacket->Ranges[i].ByteOffset + vmxferpagePacket->Ranges[i].ByteCount < netDevice->ReceiveBufferSize); | |
1252 | + | |
1253 | + netvscPacket->PageBuffers[0].Length = vmxferpagePacket->Ranges[i].ByteCount; | |
1254 | + | |
1255 | + start = GetPhysicalAddress((void*)((ULONG_PTR)netDevice->ReceiveBuffer + vmxferpagePacket->Ranges[i].ByteOffset)); | |
1256 | + | |
1257 | + netvscPacket->PageBuffers[0].Pfn = start >> PAGE_SHIFT; | |
1258 | + endVirtual = (ULONG_PTR)netDevice->ReceiveBuffer | |
1259 | + + vmxferpagePacket->Ranges[i].ByteOffset | |
1260 | + + vmxferpagePacket->Ranges[i].ByteCount -1; | |
1261 | + end = GetPhysicalAddress((void*)endVirtual); | |
1262 | + | |
1263 | + // Calculate the page relative offset | |
1264 | + netvscPacket->PageBuffers[0].Offset = vmxferpagePacket->Ranges[i].ByteOffset & (PAGE_SIZE -1); | |
1265 | + if ((end >> PAGE_SHIFT) != (start>>PAGE_SHIFT)) { | |
1266 | + //Handle frame across multiple pages: | |
1267 | + netvscPacket->PageBuffers[0].Length = | |
1268 | + (netvscPacket->PageBuffers[0].Pfn <<PAGE_SHIFT) + PAGE_SIZE - start; | |
1269 | + bytesRemain = netvscPacket->TotalDataBufferLength - netvscPacket->PageBuffers[0].Length; | |
1270 | + for (j=1; j<NETVSC_PACKET_MAXPAGE; j++) { | |
1271 | + netvscPacket->PageBuffers[j].Offset = 0; | |
1272 | + if (bytesRemain <= PAGE_SIZE) { | |
1273 | + netvscPacket->PageBuffers[j].Length = bytesRemain; | |
1274 | + bytesRemain = 0; | |
1275 | + } else { | |
1276 | + netvscPacket->PageBuffers[j].Length = PAGE_SIZE; | |
1277 | + bytesRemain -= PAGE_SIZE; | |
1278 | + } | |
1279 | + netvscPacket->PageBuffers[j].Pfn = | |
1280 | + GetPhysicalAddress((void*)(endVirtual - bytesRemain)) >> PAGE_SHIFT; | |
1281 | + netvscPacket->PageBufferCount++; | |
1282 | + if (bytesRemain == 0) | |
1283 | + break; | |
1284 | + } | |
1285 | + ASSERT(bytesRemain == 0); | |
1286 | + } | |
1287 | + DPRINT_DBG(NETVSC, "[%d] - (abs offset %u len %u) => (pfn %llx, offset %u, len %u)", | |
1288 | + i, | |
1289 | + vmxferpagePacket->Ranges[i].ByteOffset, | |
1290 | + vmxferpagePacket->Ranges[i].ByteCount, | |
1291 | + netvscPacket->PageBuffers[0].Pfn, | |
1292 | + netvscPacket->PageBuffers[0].Offset, | |
1293 | + netvscPacket->PageBuffers[0].Length); | |
1294 | + | |
1295 | + // Pass it to the upper layer | |
1296 | + ((NETVSC_DRIVER_OBJECT*)Device->Driver)->OnReceiveCallback(Device, netvscPacket); | |
1297 | + | |
1298 | + NetVscOnReceiveCompletion(netvscPacket->Completion.Recv.ReceiveCompletionContext); | |
1299 | + } | |
1300 | + | |
1301 | + ASSERT(IsListEmpty(&listHead)); | |
1302 | + | |
1303 | + PutNetDevice(Device); | |
1304 | + DPRINT_EXIT(NETVSC); | |
1305 | +} | |
1306 | + | |
1307 | + | |
1308 | +static void | |
1309 | +NetVscSendReceiveCompletion( | |
1310 | + DEVICE_OBJECT *Device, | |
1311 | + UINT64 TransactionId | |
1312 | + ) | |
1313 | +{ | |
1314 | + NVSP_MESSAGE recvcompMessage; | |
1315 | + int retries=0; | |
1316 | + int ret=0; | |
1317 | + | |
1318 | + DPRINT_DBG(NETVSC, "Sending receive completion pkt - %llx", TransactionId); | |
1319 | + | |
1320 | + recvcompMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacketComplete; | |
1321 | + | |
1322 | + // FIXME: Pass in the status | |
1323 | + recvcompMessage.Messages.Version1Messages.SendRNDISPacketComplete.Status = NvspStatusSuccess; | |
1324 | + | |
1325 | +retry_send_cmplt: | |
1326 | + // Send the completion | |
1327 | + ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, | |
1328 | + &recvcompMessage, | |
1329 | + sizeof(NVSP_MESSAGE), | |
1330 | + TransactionId, | |
1331 | + VmbusPacketTypeCompletion, | |
1332 | + 0); | |
1333 | + if (ret == 0) // success | |
1334 | + { | |
1335 | + // no-op | |
1336 | + } | |
1337 | + else if (ret == -1) // no more room...wait a bit and attempt to retry 3 times | |
1338 | + { | |
1339 | + retries++; | |
1340 | + DPRINT_ERR(NETVSC, "unable to send receive completion pkt (tid %llx)...retrying %d", TransactionId, retries); | |
1341 | + | |
1342 | + if (retries < 4) | |
1343 | + { | |
1344 | + Sleep(100); | |
1345 | + goto retry_send_cmplt; | |
1346 | + } | |
1347 | + else | |
1348 | + { | |
1349 | + DPRINT_ERR(NETVSC, "unable to send receive completion pkt (tid %llx)...give up retrying", TransactionId); | |
1350 | + } | |
1351 | + } | |
1352 | + else | |
1353 | + { | |
1354 | + DPRINT_ERR(NETVSC, "unable to send receive completion pkt - %llx", TransactionId); | |
1355 | + } | |
1356 | +} | |
1357 | + | |
1358 | +// | |
1359 | +// Send a receive completion packet to RNDIS device (ie NetVsp) | |
1360 | +// | |
1361 | +static void | |
1362 | +NetVscOnReceiveCompletion( | |
1363 | + PVOID Context) | |
1364 | +{ | |
1365 | + NETVSC_PACKET *packet = (NETVSC_PACKET*)Context; | |
1366 | + DEVICE_OBJECT *device = (DEVICE_OBJECT*)packet->Device; | |
1367 | + NETVSC_DEVICE* netDevice; | |
1368 | + UINT64 transactionId=0; | |
1369 | + BOOL fSendReceiveComp = FALSE; | |
1370 | + | |
1371 | + DPRINT_ENTER(NETVSC); | |
1372 | + | |
1373 | + ASSERT(packet->XferPagePacket); | |
1374 | + | |
1375 | + // Even though it seems logical to do a GetOutboundNetDevice() here to send out receive completion, | |
1376 | + // we are using GetInboundNetDevice() since we may have disable outbound traffic already. | |
1377 | + netDevice = GetInboundNetDevice(device); | |
1378 | + if (!netDevice) | |
1379 | + { | |
1380 | + DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); | |
1381 | + DPRINT_EXIT(NETVSC); | |
1382 | + return; | |
1383 | + } | |
1384 | + | |
1385 | + // Overloading use of the lock. | |
1386 | + SpinlockAcquire(netDevice->ReceivePacketListLock); | |
1387 | + | |
1388 | + ASSERT(packet->XferPagePacket->Count > 0); | |
1389 | + packet->XferPagePacket->Count--; | |
1390 | + | |
1391 | + // Last one in the line that represent 1 xfer page packet. | |
1392 | + // Return the xfer page packet itself to the freelist | |
1393 | + if (packet->XferPagePacket->Count == 0) | |
1394 | + { | |
1395 | + fSendReceiveComp = TRUE; | |
1396 | + transactionId = packet->Completion.Recv.ReceiveCompletionTid; | |
1397 | + | |
1398 | + INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &packet->XferPagePacket->ListEntry); | |
1399 | + } | |
1400 | + | |
1401 | + // Put the packet back | |
1402 | + INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &packet->ListEntry); | |
1403 | + SpinlockRelease(netDevice->ReceivePacketListLock); | |
1404 | + | |
1405 | + // Send a receive completion for the xfer page packet | |
1406 | + if (fSendReceiveComp) | |
1407 | + { | |
1408 | + NetVscSendReceiveCompletion(device, transactionId); | |
1409 | + } | |
1410 | + | |
1411 | + PutNetDevice(device); | |
1412 | + DPRINT_EXIT(NETVSC); | |
1413 | +} | |
1414 | + | |
1415 | + | |
1416 | + | |
1417 | +void | |
1418 | +NetVscOnChannelCallback( | |
1419 | + PVOID Context | |
1420 | + ) | |
1421 | +{ | |
1422 | + const int netPacketSize=2048; | |
1423 | + int ret=0; | |
1424 | + DEVICE_OBJECT *device=(DEVICE_OBJECT*)Context; | |
1425 | + NETVSC_DEVICE *netDevice; | |
1426 | + | |
1427 | + UINT32 bytesRecvd; | |
1428 | + UINT64 requestId; | |
1429 | + UCHAR packet[netPacketSize]; | |
1430 | + VMPACKET_DESCRIPTOR *desc; | |
1431 | + UCHAR *buffer=packet; | |
1432 | + int bufferlen=netPacketSize; | |
1433 | + | |
1434 | + | |
1435 | + DPRINT_ENTER(NETVSC); | |
1436 | + | |
1437 | + ASSERT(device); | |
1438 | + | |
1439 | + netDevice = GetInboundNetDevice(device); | |
1440 | + if (!netDevice) | |
1441 | + { | |
1442 | + DPRINT_ERR(NETVSC, "net device (%p) shutting down...ignoring inbound packets", netDevice); | |
1443 | + DPRINT_EXIT(NETVSC); | |
1444 | + return; | |
1445 | + } | |
1446 | + | |
1447 | + do | |
1448 | + { | |
1449 | + ret = device->Driver->VmbusChannelInterface.RecvPacketRaw(device, | |
1450 | + buffer, | |
1451 | + bufferlen, | |
1452 | + &bytesRecvd, | |
1453 | + &requestId); | |
1454 | + | |
1455 | + if (ret == 0) | |
1456 | + { | |
1457 | + if (bytesRecvd > 0) | |
1458 | + { | |
1459 | + DPRINT_DBG(NETVSC, "receive %d bytes, tid %llx", bytesRecvd, requestId); | |
1460 | + | |
1461 | + desc = (VMPACKET_DESCRIPTOR*)buffer; | |
1462 | + switch (desc->Type) | |
1463 | + { | |
1464 | + case VmbusPacketTypeCompletion: | |
1465 | + NetVscOnSendCompletion(device, desc); | |
1466 | + break; | |
1467 | + | |
1468 | + case VmbusPacketTypeDataUsingTransferPages: | |
1469 | + NetVscOnReceive(device, desc); | |
1470 | + break; | |
1471 | + | |
1472 | + default: | |
1473 | + DPRINT_ERR(NETVSC, "unhandled packet type %d, tid %llx len %d\n", desc->Type, requestId, bytesRecvd); | |
1474 | + break; | |
1475 | + } | |
1476 | + | |
1477 | + // reset | |
1478 | + if (bufferlen > netPacketSize) | |
1479 | + { | |
1480 | + MemFree(buffer); | |
1481 | + | |
1482 | + buffer = packet; | |
1483 | + bufferlen = netPacketSize; | |
1484 | + } | |
1485 | + } | |
1486 | + else | |
1487 | + { | |
1488 | + //DPRINT_DBG(NETVSC, "nothing else to read..."); | |
1489 | + | |
1490 | + // reset | |
1491 | + if (bufferlen > netPacketSize) | |
1492 | + { | |
1493 | + MemFree(buffer); | |
1494 | + | |
1495 | + buffer = packet; | |
1496 | + bufferlen = netPacketSize; | |
1497 | + } | |
1498 | + | |
1499 | + break; | |
1500 | + } | |
1501 | + } | |
1502 | + else if (ret == -2) // Handle large packet | |
1503 | + { | |
1504 | + buffer = MemAllocAtomic(bytesRecvd); | |
1505 | + if (buffer == NULL) | |
1506 | + { | |
1507 | + // Try again next time around | |
1508 | + DPRINT_ERR(NETVSC, "unable to allocate buffer of size (%d)!!", bytesRecvd); | |
1509 | + break; | |
1510 | + } | |
1511 | + | |
1512 | + bufferlen = bytesRecvd; | |
1513 | + } | |
1514 | + else | |
1515 | + { | |
1516 | + ASSERT(0); | |
1517 | + } | |
1518 | + } while (1); | |
1519 | + | |
1520 | + PutNetDevice(device); | |
1521 | + DPRINT_EXIT(NETVSC); | |
1522 | + return; | |
1523 | +} | |
1524 | --- /dev/null | |
1525 | +++ b/drivers/staging/hv/netvsc_drv.c | |
1526 | @@ -0,0 +1,720 @@ | |
1527 | +/* | |
1528 | + * | |
1529 | + * Copyright (c) 2009, Microsoft Corporation. | |
1530 | + * | |
1531 | + * This program is free software; you can redistribute it and/or modify it | |
1532 | + * under the terms and conditions of the GNU General Public License, | |
1533 | + * version 2, as published by the Free Software Foundation. | |
1534 | + * | |
1535 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
1536 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
1537 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
1538 | + * more details. | |
1539 | + * | |
1540 | + * You should have received a copy of the GNU General Public License along with | |
1541 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
1542 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
1543 | + * | |
1544 | + * Authors: | |
1545 | + * Hank Janssen <hjanssen@microsoft.com> | |
1546 | + * | |
1547 | + */ | |
1548 | + | |
1549 | + | |
1550 | +#include <linux/init.h> | |
1551 | +#include <linux/module.h> | |
1552 | +#include <linux/highmem.h> | |
1553 | +#include <linux/device.h> | |
1554 | +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) | |
1555 | +#include <asm/io.h> | |
1556 | +#else | |
1557 | +#include <linux/io.h> | |
1558 | +#endif | |
1559 | +#include <linux/delay.h> | |
1560 | +#include <linux/netdevice.h> | |
1561 | +#include <linux/inetdevice.h> | |
1562 | +#include <linux/etherdevice.h> | |
1563 | +#include <linux/skbuff.h> | |
1564 | +#include <linux/in.h> | |
1565 | +#include <net/arp.h> | |
1566 | +#include <net/route.h> | |
1567 | +#include <net/sock.h> | |
1568 | +#include <net/pkt_sched.h> | |
1569 | + | |
1570 | +#include "logging.h" | |
1571 | +#include "vmbus.h" | |
1572 | + | |
1573 | +#include "NetVscApi.h" | |
1574 | + | |
1575 | +MODULE_LICENSE("GPL"); | |
1576 | + | |
1577 | +// | |
1578 | +// Static decl | |
1579 | +// | |
1580 | +static int netvsc_probe(struct device *device); | |
1581 | +static int netvsc_remove(struct device *device); | |
1582 | +static int netvsc_open(struct net_device *net); | |
1583 | +static void netvsc_xmit_completion(void *context); | |
1584 | +static int netvsc_start_xmit (struct sk_buff *skb, struct net_device *net); | |
1585 | +static int netvsc_recv_callback(DEVICE_OBJECT *device_obj, NETVSC_PACKET* Packet); | |
1586 | +static int netvsc_close(struct net_device *net); | |
1587 | +static struct net_device_stats *netvsc_get_stats(struct net_device *net); | |
1588 | +static void netvsc_linkstatus_callback(DEVICE_OBJECT *device_obj, unsigned int status); | |
1589 | + | |
1590 | +// | |
1591 | +// Data types | |
1592 | +// | |
1593 | +struct net_device_context { | |
1594 | + struct device_context *device_ctx; // point back to our device context | |
1595 | + struct net_device_stats stats; | |
1596 | +}; | |
1597 | + | |
1598 | +struct netvsc_driver_context { | |
1599 | + // !! These must be the first 2 fields !! | |
1600 | + struct driver_context drv_ctx; | |
1601 | + NETVSC_DRIVER_OBJECT drv_obj; | |
1602 | +}; | |
1603 | + | |
1604 | +// | |
1605 | +// Globals | |
1606 | +// | |
1607 | + | |
1608 | +static int netvsc_ringbuffer_size = NETVSC_DEVICE_RING_BUFFER_SIZE; | |
1609 | + | |
1610 | +// The one and only one | |
1611 | +static struct netvsc_driver_context g_netvsc_drv; | |
1612 | + | |
1613 | +// | |
1614 | +// Routines | |
1615 | +// | |
1616 | + | |
1617 | +/*++ | |
1618 | + | |
1619 | +Name: netvsc_drv_init() | |
1620 | + | |
1621 | +Desc: NetVsc driver initialization | |
1622 | + | |
1623 | +--*/ | |
1624 | +int netvsc_drv_init(PFN_DRIVERINITIALIZE pfn_drv_init) | |
1625 | +{ | |
1626 | + int ret=0; | |
1627 | + NETVSC_DRIVER_OBJECT *net_drv_obj=&g_netvsc_drv.drv_obj; | |
1628 | + struct driver_context *drv_ctx=&g_netvsc_drv.drv_ctx; | |
1629 | + | |
1630 | + DPRINT_ENTER(NETVSC_DRV); | |
1631 | + | |
1632 | + vmbus_get_interface(&net_drv_obj->Base.VmbusChannelInterface); | |
1633 | + | |
1634 | + net_drv_obj->RingBufferSize = netvsc_ringbuffer_size; | |
1635 | + net_drv_obj->OnReceiveCallback = netvsc_recv_callback; | |
1636 | + net_drv_obj->OnLinkStatusChanged = netvsc_linkstatus_callback; | |
1637 | + | |
1638 | + // Callback to client driver to complete the initialization | |
1639 | + pfn_drv_init(&net_drv_obj->Base); | |
1640 | + | |
1641 | + drv_ctx->driver.name = net_drv_obj->Base.name; | |
1642 | + memcpy(&drv_ctx->class_id, &net_drv_obj->Base.deviceType, sizeof(GUID)); | |
1643 | + | |
1644 | +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) | |
1645 | + drv_ctx->driver.probe = netvsc_probe; | |
1646 | + drv_ctx->driver.remove = netvsc_remove; | |
1647 | +#else | |
1648 | + drv_ctx->probe = netvsc_probe; | |
1649 | + drv_ctx->remove = netvsc_remove; | |
1650 | +#endif | |
1651 | + | |
1652 | + // The driver belongs to vmbus | |
1653 | + vmbus_child_driver_register(drv_ctx); | |
1654 | + | |
1655 | + DPRINT_EXIT(NETVSC_DRV); | |
1656 | + | |
1657 | + return ret; | |
1658 | +} | |
1659 | + | |
1660 | +/*++ | |
1661 | + | |
1662 | +Name: netvsc_get_stats() | |
1663 | + | |
1664 | +Desc: Get the network stats | |
1665 | + | |
1666 | +--*/ | |
1667 | +static struct net_device_stats *netvsc_get_stats(struct net_device *net) | |
1668 | +{ | |
1669 | + struct net_device_context *net_device_ctx = netdev_priv(net); | |
1670 | + | |
1671 | + return &net_device_ctx->stats; | |
1672 | +} | |
1673 | + | |
1674 | +/*++ | |
1675 | + | |
1676 | +Name: netvsc_set_multicast_list() | |
1677 | + | |
1678 | +Desc: Set the multicast list | |
1679 | + | |
1680 | +Remark: No-op here | |
1681 | +--*/ | |
1682 | +static void netvsc_set_multicast_list(UNUSED_VAR(struct net_device *net)) | |
1683 | +{ | |
1684 | +} | |
1685 | + | |
1686 | + | |
1687 | +/*++ | |
1688 | + | |
1689 | +Name: netvsc_probe() | |
1690 | + | |
1691 | +Desc: Add the specified new device to this driver | |
1692 | + | |
1693 | +--*/ | |
1694 | +static int netvsc_probe(struct device *device) | |
1695 | +{ | |
1696 | + int ret=0; | |
1697 | + | |
1698 | + struct driver_context *driver_ctx = driver_to_driver_context(device->driver); | |
1699 | + struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx; | |
1700 | + NETVSC_DRIVER_OBJECT *net_drv_obj = &net_drv_ctx->drv_obj; | |
1701 | + | |
1702 | + struct device_context *device_ctx = device_to_device_context(device); | |
1703 | + DEVICE_OBJECT *device_obj = &device_ctx->device_obj; | |
1704 | + | |
1705 | + struct net_device *net = NULL; | |
1706 | + struct net_device_context *net_device_ctx; | |
1707 | + NETVSC_DEVICE_INFO device_info; | |
1708 | + | |
1709 | + DPRINT_ENTER(NETVSC_DRV); | |
1710 | + | |
1711 | + if (!net_drv_obj->Base.OnDeviceAdd) | |
1712 | + { | |
1713 | + return -1; | |
1714 | + } | |
1715 | + | |
1716 | + net = alloc_netdev(sizeof(struct net_device_context), "seth%d", ether_setup); | |
1717 | + //net = alloc_etherdev(sizeof(struct net_device_context)); | |
1718 | + if (!net) | |
1719 | + { | |
1720 | + return -1; | |
1721 | + } | |
1722 | + | |
1723 | + // Set initial state | |
1724 | + netif_carrier_off(net); | |
1725 | + netif_stop_queue(net); | |
1726 | + | |
1727 | + net_device_ctx = netdev_priv(net); | |
1728 | + net_device_ctx->device_ctx = device_ctx; | |
1729 | + device->driver_data = net; | |
1730 | + | |
1731 | + // Notify the netvsc driver of the new device | |
1732 | + ret = net_drv_obj->Base.OnDeviceAdd(device_obj, (void*)&device_info); | |
1733 | + if (ret != 0) | |
1734 | + { | |
1735 | + free_netdev(net); | |
1736 | + device->driver_data = NULL; | |
1737 | + | |
1738 | + DPRINT_ERR(NETVSC_DRV, "unable to add netvsc device (ret %d)", ret); | |
1739 | + return ret; | |
1740 | + } | |
1741 | + | |
1742 | + // If carrier is still off ie we did not get a link status callback, update it if necessary | |
1743 | + // FIXME: We should use a atomic or test/set instead to avoid getting out of sync with the device's link status | |
1744 | + if (!netif_carrier_ok(net)) | |
1745 | + { | |
1746 | + if (!device_info.LinkState) | |
1747 | + { | |
1748 | + netif_carrier_on(net); | |
1749 | + } | |
1750 | + } | |
1751 | + | |
1752 | + memcpy(net->dev_addr, device_info.MacAddr, ETH_ALEN); | |
1753 | + | |
1754 | + net->open = netvsc_open; | |
1755 | + net->hard_start_xmit = netvsc_start_xmit; | |
1756 | + net->stop = netvsc_close; | |
1757 | + net->get_stats = netvsc_get_stats; | |
1758 | + net->set_multicast_list = netvsc_set_multicast_list; | |
1759 | + | |
1760 | +#if !defined(KERNEL_2_6_27) | |
1761 | + SET_MODULE_OWNER(net); | |
1762 | +#endif | |
1763 | + SET_NETDEV_DEV(net, device); | |
1764 | + | |
1765 | + ret = register_netdev(net); | |
1766 | + if (ret != 0) | |
1767 | + { | |
1768 | + // Remove the device and release the resource | |
1769 | + net_drv_obj->Base.OnDeviceRemove(device_obj); | |
1770 | + free_netdev(net); | |
1771 | + } | |
1772 | + | |
1773 | + DPRINT_EXIT(NETVSC_DRV); | |
1774 | + | |
1775 | + return ret; | |
1776 | +} | |
1777 | + | |
1778 | +static int netvsc_remove(struct device *device) | |
1779 | +{ | |
1780 | + int ret=0; | |
1781 | + struct driver_context *driver_ctx = driver_to_driver_context(device->driver); | |
1782 | + struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx; | |
1783 | + NETVSC_DRIVER_OBJECT *net_drv_obj = &net_drv_ctx->drv_obj; | |
1784 | + | |
1785 | + struct device_context *device_ctx = device_to_device_context(device); | |
1786 | + struct net_device *net = (struct net_device *)device_ctx->device.driver_data; | |
1787 | + DEVICE_OBJECT *device_obj = &device_ctx->device_obj; | |
1788 | + | |
1789 | + DPRINT_ENTER(NETVSC_DRV); | |
1790 | + | |
1791 | + if (net == NULL) | |
1792 | + { | |
1793 | + DPRINT_INFO(NETVSC, "no net device to remove"); | |
1794 | + DPRINT_EXIT(NETVSC_DRV); | |
1795 | + return 0; | |
1796 | + } | |
1797 | + | |
1798 | + if (!net_drv_obj->Base.OnDeviceRemove) | |
1799 | + { | |
1800 | + DPRINT_EXIT(NETVSC_DRV); | |
1801 | + return -1; | |
1802 | + } | |
1803 | + | |
1804 | + // Stop outbound asap | |
1805 | + netif_stop_queue(net); | |
1806 | + //netif_carrier_off(net); | |
1807 | + | |
1808 | + unregister_netdev(net); | |
1809 | + | |
1810 | + // Call to the vsc driver to let it know that the device is being removed | |
1811 | + ret = net_drv_obj->Base.OnDeviceRemove(device_obj); | |
1812 | + if (ret != 0) | |
1813 | + { | |
1814 | + // TODO: | |
1815 | + DPRINT_ERR(NETVSC, "unable to remove vsc device (ret %d)", ret); | |
1816 | + } | |
1817 | + | |
1818 | + free_netdev(net); | |
1819 | + | |
1820 | + DPRINT_EXIT(NETVSC_DRV); | |
1821 | + | |
1822 | + return ret; | |
1823 | +} | |
1824 | + | |
1825 | +/*++ | |
1826 | + | |
1827 | +Name: netvsc_open() | |
1828 | + | |
1829 | +Desc: Open the specified interface device | |
1830 | + | |
1831 | +--*/ | |
1832 | +static int netvsc_open(struct net_device *net) | |
1833 | +{ | |
1834 | + int ret=0; | |
1835 | + struct net_device_context *net_device_ctx = netdev_priv(net); | |
1836 | + struct driver_context *driver_ctx = driver_to_driver_context(net_device_ctx->device_ctx->device.driver); | |
1837 | + struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx; | |
1838 | + NETVSC_DRIVER_OBJECT *net_drv_obj = &net_drv_ctx->drv_obj; | |
1839 | + | |
1840 | + DEVICE_OBJECT *device_obj = &net_device_ctx->device_ctx->device_obj; | |
1841 | + | |
1842 | + DPRINT_ENTER(NETVSC_DRV); | |
1843 | + | |
1844 | + if (netif_carrier_ok(net)) | |
1845 | + { | |
1846 | + memset(&net_device_ctx->stats, 0 , sizeof(struct net_device_stats)); | |
1847 | + | |
1848 | + // Open up the device | |
1849 | + ret = net_drv_obj->OnOpen(device_obj); | |
1850 | + if (ret != 0) | |
1851 | + { | |
1852 | + DPRINT_ERR(NETVSC_DRV, "unable to open device (ret %d).", ret); | |
1853 | + return ret; | |
1854 | + } | |
1855 | + | |
1856 | + netif_start_queue(net); | |
1857 | + } | |
1858 | + else | |
1859 | + { | |
1860 | + DPRINT_ERR(NETVSC_DRV, "unable to open device...link is down."); | |
1861 | + } | |
1862 | + | |
1863 | + DPRINT_EXIT(NETVSC_DRV); | |
1864 | + return ret; | |
1865 | +} | |
1866 | + | |
1867 | +/*++ | |
1868 | + | |
1869 | +Name: netvsc_close() | |
1870 | + | |
1871 | +Desc: Close the specified interface device | |
1872 | + | |
1873 | +--*/ | |
1874 | +static int netvsc_close(struct net_device *net) | |
1875 | +{ | |
1876 | + int ret=0; | |
1877 | + struct net_device_context *net_device_ctx = netdev_priv(net); | |
1878 | + struct driver_context *driver_ctx = driver_to_driver_context(net_device_ctx->device_ctx->device.driver); | |
1879 | + struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx; | |
1880 | + NETVSC_DRIVER_OBJECT *net_drv_obj = &net_drv_ctx->drv_obj; | |
1881 | + | |
1882 | + DEVICE_OBJECT *device_obj = &net_device_ctx->device_ctx->device_obj; | |
1883 | + | |
1884 | + DPRINT_ENTER(NETVSC_DRV); | |
1885 | + | |
1886 | + netif_stop_queue(net); | |
1887 | + | |
1888 | + ret = net_drv_obj->OnClose(device_obj); | |
1889 | + if (ret != 0) | |
1890 | + { | |
1891 | + DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret); | |
1892 | + } | |
1893 | + | |
1894 | + DPRINT_EXIT(NETVSC_DRV); | |
1895 | + | |
1896 | + return ret; | |
1897 | +} | |
1898 | + | |
1899 | + | |
1900 | +/*++ | |
1901 | + | |
1902 | +Name: netvsc_xmit_completion() | |
1903 | + | |
1904 | +Desc: Send completion processing | |
1905 | + | |
1906 | +--*/ | |
1907 | +static void netvsc_xmit_completion(void *context) | |
1908 | +{ | |
1909 | + NETVSC_PACKET *packet = (NETVSC_PACKET *)context; | |
1910 | + struct sk_buff *skb = (struct sk_buff *)(ULONG_PTR)packet->Completion.Send.SendCompletionTid; | |
1911 | + struct net_device* net; | |
1912 | + | |
1913 | + DPRINT_ENTER(NETVSC_DRV); | |
1914 | + | |
1915 | + kfree(packet); | |
1916 | + | |
1917 | + if (skb) | |
1918 | + { | |
1919 | + net = skb->dev; | |
1920 | + | |
1921 | + dev_kfree_skb_any(skb); | |
1922 | + | |
1923 | + if (netif_queue_stopped(net)) | |
1924 | + { | |
1925 | + DPRINT_INFO(NETVSC_DRV, "net device (%p) waking up...", net); | |
1926 | + | |
1927 | + netif_wake_queue(net); | |
1928 | + } | |
1929 | + } | |
1930 | + | |
1931 | + DPRINT_EXIT(NETVSC_DRV); | |
1932 | +} | |
1933 | + | |
1934 | +/*++ | |
1935 | + | |
1936 | +Name: netvsc_start_xmit() | |
1937 | + | |
1938 | +Desc: Start a send | |
1939 | + | |
1940 | +--*/ | |
1941 | +static int netvsc_start_xmit (struct sk_buff *skb, struct net_device *net) | |
1942 | +{ | |
1943 | + int ret=0; | |
1944 | + struct net_device_context *net_device_ctx = netdev_priv(net); | |
1945 | + struct driver_context *driver_ctx = driver_to_driver_context(net_device_ctx->device_ctx->device.driver); | |
1946 | + struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx; | |
1947 | + NETVSC_DRIVER_OBJECT *net_drv_obj = &net_drv_ctx->drv_obj; | |
1948 | + | |
1949 | + int i=0; | |
1950 | + NETVSC_PACKET* packet; | |
1951 | + int num_frags; | |
1952 | + int retries=0; | |
1953 | + | |
1954 | + DPRINT_ENTER(NETVSC_DRV); | |
1955 | + | |
1956 | + // Support only 1 chain of frags | |
1957 | + ASSERT(skb_shinfo(skb)->frag_list == NULL); | |
1958 | + ASSERT(skb->dev == net); | |
1959 | + | |
1960 | + DPRINT_DBG(NETVSC_DRV, "xmit packet - len %d data_len %d", skb->len, skb->data_len); | |
1961 | + | |
1962 | + // Add 1 for skb->data and any additional ones requested | |
1963 | + num_frags = skb_shinfo(skb)->nr_frags + 1 + net_drv_obj->AdditionalRequestPageBufferCount; | |
1964 | + | |
1965 | + // Allocate a netvsc packet based on # of frags. | |
1966 | + packet = kzalloc(sizeof(NETVSC_PACKET) + (num_frags * sizeof(PAGE_BUFFER)) + net_drv_obj->RequestExtSize, GFP_ATOMIC); | |
1967 | + if (!packet) | |
1968 | + { | |
1969 | + DPRINT_ERR(NETVSC_DRV, "unable to allocate NETVSC_PACKET"); | |
1970 | + return -1; | |
1971 | + } | |
1972 | + | |
1973 | + packet->Extension = (void*)(unsigned long)packet + sizeof(NETVSC_PACKET) + (num_frags * sizeof(PAGE_BUFFER)) ; | |
1974 | + | |
1975 | + // Setup the rndis header | |
1976 | + packet->PageBufferCount = num_frags; | |
1977 | + | |
1978 | + // TODO: Flush all write buffers/ memory fence ??? | |
1979 | + //wmb(); | |
1980 | + | |
1981 | + // Initialize it from the skb | |
1982 | + ASSERT(skb->data); | |
1983 | + packet->TotalDataBufferLength = skb->len; | |
1984 | + | |
1985 | + // Start filling in the page buffers starting at AdditionalRequestPageBufferCount offset | |
1986 | + packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; | |
1987 | + packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Offset = (unsigned long)skb->data & (PAGE_SIZE -1); | |
1988 | + packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Length = skb->len - skb->data_len; | |
1989 | + | |
1990 | + ASSERT((skb->len - skb->data_len) <= PAGE_SIZE); | |
1991 | + | |
1992 | + for (i=net_drv_obj->AdditionalRequestPageBufferCount+1; i<num_frags; i++) | |
1993 | + { | |
1994 | + packet->PageBuffers[i].Pfn = page_to_pfn(skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page); | |
1995 | + packet->PageBuffers[i].Offset = skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page_offset; | |
1996 | + packet->PageBuffers[i].Length = skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].size; | |
1997 | + } | |
1998 | + | |
1999 | + // Set the completion routine | |
2000 | + packet->Completion.Send.OnSendCompletion = netvsc_xmit_completion; | |
2001 | + packet->Completion.Send.SendCompletionContext = packet; | |
2002 | + packet->Completion.Send.SendCompletionTid = (ULONG_PTR)skb; | |
2003 | + | |
2004 | +retry_send: | |
2005 | + ret = net_drv_obj->OnSend(&net_device_ctx->device_ctx->device_obj, packet); | |
2006 | + | |
2007 | + if (ret == 0) | |
2008 | + { | |
2009 | +#ifdef KERNEL_2_6_5 | |
2010 | +#define NETDEV_TX_OK 0 | |
2011 | +#define NETDEV_TX_BUSY 0 | |
2012 | +#endif | |
2013 | + ret = NETDEV_TX_OK; | |
2014 | + net_device_ctx->stats.tx_bytes += skb->len; | |
2015 | + net_device_ctx->stats.tx_packets++; | |
2016 | + } | |
2017 | + else | |
2018 | + { | |
2019 | + retries++; | |
2020 | + if (retries < 4) | |
2021 | + { | |
2022 | + DPRINT_ERR(NETVSC_DRV, "unable to send...retrying %d...", retries); | |
2023 | + udelay(100); | |
2024 | + goto retry_send; | |
2025 | + } | |
2026 | + | |
2027 | + // no more room or we are shutting down | |
2028 | + DPRINT_ERR(NETVSC_DRV, "unable to send (%d)...marking net device (%p) busy", ret, net); | |
2029 | + DPRINT_INFO(NETVSC_DRV, "net device (%p) stopping", net); | |
2030 | + | |
2031 | + ret = NETDEV_TX_BUSY; | |
2032 | + net_device_ctx->stats.tx_dropped++; | |
2033 | + | |
2034 | + netif_stop_queue(net); | |
2035 | + | |
2036 | + // Null it since the caller will free it instead of the completion routine | |
2037 | + packet->Completion.Send.SendCompletionTid = 0; | |
2038 | + | |
2039 | + // Release the resources since we will not get any send completion | |
2040 | + netvsc_xmit_completion((void*)packet); | |
2041 | + } | |
2042 | + | |
2043 | + DPRINT_DBG(NETVSC_DRV, "# of xmits %lu total size %lu", net_device_ctx->stats.tx_packets, net_device_ctx->stats.tx_bytes); | |
2044 | + | |
2045 | + DPRINT_EXIT(NETVSC_DRV); | |
2046 | + return ret; | |
2047 | +} | |
2048 | + | |
2049 | + | |
2050 | +/*++ | |
2051 | + | |
2052 | +Name: netvsc_linkstatus_callback() | |
2053 | + | |
2054 | +Desc: Link up/down notification | |
2055 | + | |
2056 | +--*/ | |
2057 | +static void netvsc_linkstatus_callback(DEVICE_OBJECT *device_obj, unsigned int status) | |
2058 | +{ | |
2059 | + struct device_context* device_ctx = to_device_context(device_obj); | |
2060 | + struct net_device* net = (struct net_device *)device_ctx->device.driver_data; | |
2061 | + | |
2062 | + DPRINT_ENTER(NETVSC_DRV); | |
2063 | + | |
2064 | + if (!net) | |
2065 | + { | |
2066 | + DPRINT_ERR(NETVSC_DRV, "got link status but net device not initialized yet"); | |
2067 | + return; | |
2068 | + } | |
2069 | + | |
2070 | + if (status == 1) | |
2071 | + { | |
2072 | + netif_carrier_on(net); | |
2073 | + netif_wake_queue(net); | |
2074 | + } | |
2075 | + else | |
2076 | + { | |
2077 | + netif_carrier_off(net); | |
2078 | + netif_stop_queue(net); | |
2079 | + } | |
2080 | + DPRINT_EXIT(NETVSC_DRV); | |
2081 | +} | |
2082 | + | |
2083 | + | |
2084 | +/*++ | |
2085 | + | |
2086 | +Name: netvsc_recv_callback() | |
2087 | + | |
2088 | +Desc: Callback when we receive a packet from the "wire" on the specify device | |
2089 | + | |
2090 | +--*/ | |
2091 | +static int netvsc_recv_callback(DEVICE_OBJECT *device_obj, NETVSC_PACKET* packet) | |
2092 | +{ | |
2093 | + int ret=0; | |
2094 | + struct device_context *device_ctx = to_device_context(device_obj); | |
2095 | + struct net_device *net = (struct net_device *)device_ctx->device.driver_data; | |
2096 | + struct net_device_context *net_device_ctx; | |
2097 | + | |
2098 | + struct sk_buff *skb; | |
2099 | + void *data; | |
2100 | + int i=0; | |
2101 | + unsigned long flags; | |
2102 | + | |
2103 | + DPRINT_ENTER(NETVSC_DRV); | |
2104 | + | |
2105 | + if (!net) | |
2106 | + { | |
2107 | + DPRINT_ERR(NETVSC_DRV, "got receive callback but net device not initialized yet"); | |
2108 | + return 0; | |
2109 | + } | |
2110 | + | |
2111 | + net_device_ctx = netdev_priv(net); | |
2112 | + | |
2113 | + // Allocate a skb - TODO preallocate this | |
2114 | + //skb = alloc_skb(packet->TotalDataBufferLength, GFP_ATOMIC); | |
2115 | + skb = dev_alloc_skb(packet->TotalDataBufferLength + 2); // Pad 2-bytes to align IP header to 16 bytes | |
2116 | + ASSERT(skb); | |
2117 | + skb_reserve(skb, 2); | |
2118 | + skb->dev = net; | |
2119 | + | |
2120 | + // for kmap_atomic | |
2121 | + local_irq_save(flags); | |
2122 | + | |
2123 | + // Copy to skb. This copy is needed here since the memory pointed by NETVSC_PACKET | |
2124 | + // cannot be deallocated | |
2125 | + for (i=0; i<packet->PageBufferCount; i++) | |
2126 | + { | |
2127 | + data = kmap_atomic(pfn_to_page(packet->PageBuffers[i].Pfn), KM_IRQ1); | |
2128 | + data = (void*)(unsigned long)data + packet->PageBuffers[i].Offset; | |
2129 | + | |
2130 | + memcpy(skb_put(skb, packet->PageBuffers[i].Length), data, packet->PageBuffers[i].Length); | |
2131 | + | |
2132 | + kunmap_atomic((void*)((unsigned long)data - packet->PageBuffers[i].Offset), KM_IRQ1); | |
2133 | + } | |
2134 | + | |
2135 | + local_irq_restore(flags); | |
2136 | + | |
2137 | + skb->protocol = eth_type_trans(skb, net); | |
2138 | + | |
2139 | + skb->ip_summed = CHECKSUM_NONE; | |
2140 | + | |
2141 | + // Pass the skb back up. Network stack will deallocate the skb when it is done | |
2142 | + ret = netif_rx(skb); | |
2143 | + | |
2144 | + switch (ret) | |
2145 | + { | |
2146 | + case NET_RX_DROP: | |
2147 | + net_device_ctx->stats.rx_dropped++; | |
2148 | + break; | |
2149 | + default: | |
2150 | + net_device_ctx->stats.rx_packets++; | |
2151 | + net_device_ctx->stats.rx_bytes += skb->len; | |
2152 | + break; | |
2153 | + | |
2154 | + } | |
2155 | + DPRINT_DBG(NETVSC_DRV, "# of recvs %lu total size %lu", net_device_ctx->stats.rx_packets, net_device_ctx->stats.rx_bytes); | |
2156 | + | |
2157 | + DPRINT_EXIT(NETVSC_DRV); | |
2158 | + | |
2159 | + return 0; | |
2160 | +} | |
2161 | + | |
2162 | +static int netvsc_drv_exit_cb(struct device *dev, void *data) | |
2163 | +{ | |
2164 | + struct device **curr = (struct device **)data; | |
2165 | + *curr = dev; | |
2166 | + return 1; // stop iterating | |
2167 | +} | |
2168 | + | |
2169 | +/*++ | |
2170 | + | |
2171 | +Name: netvsc_drv_exit() | |
2172 | + | |
2173 | +Desc: | |
2174 | + | |
2175 | +--*/ | |
2176 | +void netvsc_drv_exit(void) | |
2177 | +{ | |
2178 | + NETVSC_DRIVER_OBJECT *netvsc_drv_obj=&g_netvsc_drv.drv_obj; | |
2179 | + struct driver_context *drv_ctx=&g_netvsc_drv.drv_ctx; | |
2180 | + | |
2181 | + struct device *current_dev=NULL; | |
2182 | +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) | |
2183 | +#define driver_for_each_device(drv, start, data, fn) \ | |
2184 | + struct list_head *ptr, *n; \ | |
2185 | + list_for_each_safe(ptr, n, &((drv)->devices)) {\ | |
2186 | + struct device *curr_dev;\ | |
2187 | + curr_dev = list_entry(ptr, struct device, driver_list);\ | |
2188 | + fn(curr_dev, data);\ | |
2189 | + } | |
2190 | +#endif | |
2191 | + | |
2192 | + DPRINT_ENTER(NETVSC_DRV); | |
2193 | + | |
2194 | + while (1) | |
2195 | + { | |
2196 | + current_dev = NULL; | |
2197 | + | |
2198 | + // Get the device | |
2199 | + driver_for_each_device(&drv_ctx->driver, NULL, (void*)¤t_dev, netvsc_drv_exit_cb); | |
2200 | + | |
2201 | + if (current_dev == NULL) | |
2202 | + break; | |
2203 | + | |
2204 | + // Initiate removal from the top-down | |
2205 | + DPRINT_INFO(NETVSC_DRV, "unregistering device (%p)...", current_dev); | |
2206 | + | |
2207 | + device_unregister(current_dev); | |
2208 | + } | |
2209 | + | |
2210 | + if (netvsc_drv_obj->Base.OnCleanup) | |
2211 | + netvsc_drv_obj->Base.OnCleanup(&netvsc_drv_obj->Base); | |
2212 | + | |
2213 | + vmbus_child_driver_unregister(drv_ctx); | |
2214 | + | |
2215 | + DPRINT_EXIT(NETVSC_DRV); | |
2216 | + | |
2217 | + return; | |
2218 | +} | |
2219 | + | |
2220 | +static int __init netvsc_init(void) | |
2221 | +{ | |
2222 | + int ret; | |
2223 | + | |
2224 | + DPRINT_ENTER(NETVSC_DRV); | |
2225 | + DPRINT_INFO(NETVSC_DRV, "Netvsc initializing...."); | |
2226 | + | |
2227 | + ret = netvsc_drv_init(NetVscInitialize); | |
2228 | + | |
2229 | + DPRINT_EXIT(NETVSC_DRV); | |
2230 | + | |
2231 | + return ret; | |
2232 | +} | |
2233 | + | |
2234 | +static void __exit netvsc_exit(void) | |
2235 | +{ | |
2236 | + DPRINT_ENTER(NETVSC_DRV); | |
2237 | + | |
2238 | + netvsc_drv_exit(); | |
2239 | + | |
2240 | + DPRINT_EXIT(NETVSC_DRV); | |
2241 | +} | |
2242 | + | |
2243 | +module_param(netvsc_ringbuffer_size, int, S_IRUGO); | |
2244 | + | |
2245 | +module_init(netvsc_init); | |
2246 | +module_exit(netvsc_exit); | |
2247 | --- /dev/null | |
2248 | +++ b/drivers/staging/hv/NetVsc.h | |
2249 | @@ -0,0 +1,91 @@ | |
2250 | +/* | |
2251 | + * | |
2252 | + * Copyright (c) 2009, Microsoft Corporation. | |
2253 | + * | |
2254 | + * This program is free software; you can redistribute it and/or modify it | |
2255 | + * under the terms and conditions of the GNU General Public License, | |
2256 | + * version 2, as published by the Free Software Foundation. | |
2257 | + * | |
2258 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
2259 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
2260 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
2261 | + * more details. | |
2262 | + * | |
2263 | + * You should have received a copy of the GNU General Public License along with | |
2264 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
2265 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
2266 | + * | |
2267 | + * Authors: | |
2268 | + * Hank Janssen <hjanssen@microsoft.com> | |
2269 | + * | |
2270 | + */ | |
2271 | + | |
2272 | + | |
2273 | +#ifndef _NETVSC_H_ | |
2274 | +#define _NETVSC_H_ | |
2275 | + | |
2276 | +#include "VmbusPacketFormat.h" | |
2277 | +#include "nvspprotocol.h" | |
2278 | + | |
2279 | +#include "List.h" | |
2280 | + | |
2281 | +#include "NetVscApi.h" | |
2282 | +// | |
2283 | +// #defines | |
2284 | +// | |
2285 | +//#define NVSC_MIN_PROTOCOL_VERSION 1 | |
2286 | +//#define NVSC_MAX_PROTOCOL_VERSION 1 | |
2287 | + | |
2288 | +#define NETVSC_SEND_BUFFER_SIZE 64*1024 // 64K | |
2289 | +#define NETVSC_SEND_BUFFER_ID 0xface | |
2290 | + | |
2291 | + | |
2292 | +#define NETVSC_RECEIVE_BUFFER_SIZE 1024*1024 // 1MB | |
2293 | + | |
2294 | +#define NETVSC_RECEIVE_BUFFER_ID 0xcafe | |
2295 | + | |
2296 | +#define NETVSC_RECEIVE_SG_COUNT 1 | |
2297 | + | |
2298 | +// Preallocated receive packets | |
2299 | +#define NETVSC_RECEIVE_PACKETLIST_COUNT 256 | |
2300 | + | |
2301 | +// | |
2302 | +// Data types | |
2303 | +// | |
2304 | + | |
2305 | +// Per netvsc channel-specific | |
2306 | +typedef struct _NETVSC_DEVICE { | |
2307 | + DEVICE_OBJECT *Device; | |
2308 | + | |
2309 | + int RefCount; | |
2310 | + | |
2311 | + int NumOutstandingSends; | |
2312 | + // List of free preallocated NETVSC_PACKET to represent receive packet | |
2313 | + LIST_ENTRY ReceivePacketList; | |
2314 | + HANDLE ReceivePacketListLock; | |
2315 | + | |
2316 | + // Send buffer allocated by us but manages by NetVSP | |
2317 | + PVOID SendBuffer; | |
2318 | + UINT32 SendBufferSize; | |
2319 | + UINT32 SendBufferGpadlHandle; | |
2320 | + UINT32 SendSectionSize; | |
2321 | + | |
2322 | + // Receive buffer allocated by us but manages by NetVSP | |
2323 | + PVOID ReceiveBuffer; | |
2324 | + UINT32 ReceiveBufferSize; | |
2325 | + UINT32 ReceiveBufferGpadlHandle; | |
2326 | + UINT32 ReceiveSectionCount; | |
2327 | + PNVSP_1_RECEIVE_BUFFER_SECTION ReceiveSections; | |
2328 | + | |
2329 | + // Used for NetVSP initialization protocol | |
2330 | + HANDLE ChannelInitEvent; | |
2331 | + NVSP_MESSAGE ChannelInitPacket; | |
2332 | + | |
2333 | + NVSP_MESSAGE RevokePacket; | |
2334 | + //UCHAR HwMacAddr[HW_MACADDR_LEN]; | |
2335 | + | |
2336 | + // Holds rndis device info | |
2337 | + void *Extension; | |
2338 | +} NETVSC_DEVICE; | |
2339 | + | |
2340 | +#endif // _NETVSC_H_ | |
2341 | --- /dev/null | |
2342 | +++ b/drivers/staging/hv/RndisFilter.c | |
2343 | @@ -0,0 +1,1162 @@ | |
2344 | +/* | |
2345 | + * | |
2346 | + * Copyright (c) 2009, Microsoft Corporation. | |
2347 | + * | |
2348 | + * This program is free software; you can redistribute it and/or modify it | |
2349 | + * under the terms and conditions of the GNU General Public License, | |
2350 | + * version 2, as published by the Free Software Foundation. | |
2351 | + * | |
2352 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
2353 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
2354 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
2355 | + * more details. | |
2356 | + * | |
2357 | + * You should have received a copy of the GNU General Public License along with | |
2358 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
2359 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
2360 | + * | |
2361 | + * Authors: | |
2362 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
2363 | + * Hank Janssen <hjanssen@microsoft.com> | |
2364 | + * | |
2365 | + */ | |
2366 | + | |
2367 | + | |
2368 | +#include "logging.h" | |
2369 | + | |
2370 | +#include "NetVscApi.h" | |
2371 | +#include "RndisFilter.h" | |
2372 | + | |
2373 | +// | |
2374 | +// Data types | |
2375 | +// | |
2376 | + | |
2377 | +typedef struct _RNDIS_FILTER_DRIVER_OBJECT { | |
2378 | + // The original driver | |
2379 | + NETVSC_DRIVER_OBJECT InnerDriver; | |
2380 | + | |
2381 | +} RNDIS_FILTER_DRIVER_OBJECT; | |
2382 | + | |
2383 | +typedef enum { | |
2384 | + RNDIS_DEV_UNINITIALIZED = 0, | |
2385 | + RNDIS_DEV_INITIALIZING, | |
2386 | + RNDIS_DEV_INITIALIZED, | |
2387 | + RNDIS_DEV_DATAINITIALIZED, | |
2388 | +} RNDIS_DEVICE_STATE; | |
2389 | + | |
2390 | +typedef struct _RNDIS_DEVICE { | |
2391 | + NETVSC_DEVICE *NetDevice; | |
2392 | + | |
2393 | + RNDIS_DEVICE_STATE State; | |
2394 | + UINT32 LinkStatus; | |
2395 | + UINT32 NewRequestId; | |
2396 | + | |
2397 | + HANDLE RequestLock; | |
2398 | + LIST_ENTRY RequestList; | |
2399 | + | |
2400 | + UCHAR HwMacAddr[HW_MACADDR_LEN]; | |
2401 | +} RNDIS_DEVICE; | |
2402 | + | |
2403 | + | |
2404 | +typedef struct _RNDIS_REQUEST { | |
2405 | + LIST_ENTRY ListEntry; | |
2406 | + HANDLE WaitEvent; | |
2407 | + | |
2408 | + // FIXME: We assumed a fixed size response here. If we do ever need to handle a bigger response, | |
2409 | + // we can either define a max response message or add a response buffer variable above this field | |
2410 | + RNDIS_MESSAGE ResponseMessage; | |
2411 | + | |
2412 | + // Simplify allocation by having a netvsc packet inline | |
2413 | + NETVSC_PACKET Packet; | |
2414 | + PAGE_BUFFER Buffer; | |
2415 | + // FIXME: We assumed a fixed size request here. | |
2416 | + RNDIS_MESSAGE RequestMessage; | |
2417 | +} RNDIS_REQUEST; | |
2418 | + | |
2419 | + | |
2420 | +typedef struct _RNDIS_FILTER_PACKET { | |
2421 | + void *CompletionContext; | |
2422 | + PFN_ON_SENDRECVCOMPLETION OnCompletion; | |
2423 | + | |
2424 | + RNDIS_MESSAGE Message; | |
2425 | +} RNDIS_FILTER_PACKET; | |
2426 | + | |
2427 | +// | |
2428 | +// Internal routines | |
2429 | +// | |
2430 | +static int | |
2431 | +RndisFilterSendRequest( | |
2432 | + RNDIS_DEVICE *Device, | |
2433 | + RNDIS_REQUEST *Request | |
2434 | + ); | |
2435 | + | |
2436 | +static void | |
2437 | +RndisFilterReceiveResponse( | |
2438 | + RNDIS_DEVICE *Device, | |
2439 | + RNDIS_MESSAGE *Response | |
2440 | + ); | |
2441 | + | |
2442 | +static void | |
2443 | +RndisFilterReceiveIndicateStatus( | |
2444 | + RNDIS_DEVICE *Device, | |
2445 | + RNDIS_MESSAGE *Response | |
2446 | + ); | |
2447 | + | |
2448 | +static void | |
2449 | +RndisFilterReceiveData( | |
2450 | + RNDIS_DEVICE *Device, | |
2451 | + RNDIS_MESSAGE *Message, | |
2452 | + NETVSC_PACKET *Packet | |
2453 | + ); | |
2454 | + | |
2455 | +static int | |
2456 | +RndisFilterOnReceive( | |
2457 | + DEVICE_OBJECT *Device, | |
2458 | + NETVSC_PACKET *Packet | |
2459 | + ); | |
2460 | + | |
2461 | +static int | |
2462 | +RndisFilterQueryDevice( | |
2463 | + RNDIS_DEVICE *Device, | |
2464 | + UINT32 Oid, | |
2465 | + VOID *Result, | |
2466 | + UINT32 *ResultSize | |
2467 | + ); | |
2468 | + | |
2469 | +static inline int | |
2470 | +RndisFilterQueryDeviceMac( | |
2471 | + RNDIS_DEVICE *Device | |
2472 | + ); | |
2473 | + | |
2474 | +static inline int | |
2475 | +RndisFilterQueryDeviceLinkStatus( | |
2476 | + RNDIS_DEVICE *Device | |
2477 | + ); | |
2478 | + | |
2479 | +static int | |
2480 | +RndisFilterSetPacketFilter( | |
2481 | + RNDIS_DEVICE *Device, | |
2482 | + UINT32 NewFilter | |
2483 | + ); | |
2484 | + | |
2485 | +static int | |
2486 | +RndisFilterInitDevice( | |
2487 | + RNDIS_DEVICE *Device | |
2488 | + ); | |
2489 | + | |
2490 | +static int | |
2491 | +RndisFilterOpenDevice( | |
2492 | + RNDIS_DEVICE *Device | |
2493 | + ); | |
2494 | + | |
2495 | +static int | |
2496 | +RndisFilterCloseDevice( | |
2497 | + RNDIS_DEVICE *Device | |
2498 | + ); | |
2499 | + | |
2500 | +static int | |
2501 | +RndisFilterOnDeviceAdd( | |
2502 | + DEVICE_OBJECT *Device, | |
2503 | + void *AdditionalInfo | |
2504 | + ); | |
2505 | + | |
2506 | +static int | |
2507 | +RndisFilterOnDeviceRemove( | |
2508 | + DEVICE_OBJECT *Device | |
2509 | + ); | |
2510 | + | |
2511 | +static void | |
2512 | +RndisFilterOnCleanup( | |
2513 | + DRIVER_OBJECT *Driver | |
2514 | + ); | |
2515 | + | |
2516 | +static int | |
2517 | +RndisFilterOnOpen( | |
2518 | + DEVICE_OBJECT *Device | |
2519 | + ); | |
2520 | + | |
2521 | +static int | |
2522 | +RndisFilterOnClose( | |
2523 | + DEVICE_OBJECT *Device | |
2524 | + ); | |
2525 | + | |
2526 | +static int | |
2527 | +RndisFilterOnSend( | |
2528 | + DEVICE_OBJECT *Device, | |
2529 | + NETVSC_PACKET *Packet | |
2530 | + ); | |
2531 | + | |
2532 | +static void | |
2533 | +RndisFilterOnSendCompletion( | |
2534 | + void *Context | |
2535 | + ); | |
2536 | + | |
2537 | +static void | |
2538 | +RndisFilterOnSendRequestCompletion( | |
2539 | + void *Context | |
2540 | + ); | |
2541 | + | |
2542 | +// | |
2543 | +// Global var | |
2544 | +// | |
2545 | + | |
2546 | +// The one and only | |
2547 | +RNDIS_FILTER_DRIVER_OBJECT gRndisFilter; | |
2548 | + | |
2549 | +static inline RNDIS_DEVICE* GetRndisDevice(void) | |
2550 | +{ | |
2551 | + RNDIS_DEVICE *device; | |
2552 | + | |
2553 | + device = MemAllocZeroed(sizeof(RNDIS_DEVICE)); | |
2554 | + if (!device) | |
2555 | + { | |
2556 | + return NULL; | |
2557 | + } | |
2558 | + | |
2559 | + device->RequestLock = SpinlockCreate(); | |
2560 | + if (!device->RequestLock) | |
2561 | + { | |
2562 | + MemFree(device); | |
2563 | + return NULL; | |
2564 | + } | |
2565 | + | |
2566 | + INITIALIZE_LIST_HEAD(&device->RequestList); | |
2567 | + | |
2568 | + device->State = RNDIS_DEV_UNINITIALIZED; | |
2569 | + | |
2570 | + return device; | |
2571 | +} | |
2572 | + | |
2573 | +static inline void PutRndisDevice(RNDIS_DEVICE *Device) | |
2574 | +{ | |
2575 | + SpinlockClose(Device->RequestLock); | |
2576 | + MemFree(Device); | |
2577 | +} | |
2578 | + | |
2579 | +static inline RNDIS_REQUEST* GetRndisRequest(RNDIS_DEVICE *Device, UINT32 MessageType, UINT32 MessageLength) | |
2580 | +{ | |
2581 | + RNDIS_REQUEST *request; | |
2582 | + RNDIS_MESSAGE *rndisMessage; | |
2583 | + RNDIS_SET_REQUEST *set; | |
2584 | + | |
2585 | + request = MemAllocZeroed(sizeof(RNDIS_REQUEST)); | |
2586 | + if (!request) | |
2587 | + { | |
2588 | + return NULL; | |
2589 | + } | |
2590 | + | |
2591 | + request->WaitEvent = WaitEventCreate(); | |
2592 | + if (!request->WaitEvent) | |
2593 | + { | |
2594 | + MemFree(request); | |
2595 | + return NULL; | |
2596 | + } | |
2597 | + | |
2598 | + rndisMessage = &request->RequestMessage; | |
2599 | + rndisMessage->NdisMessageType = MessageType; | |
2600 | + rndisMessage->MessageLength = MessageLength; | |
2601 | + | |
2602 | + // Set the request id. This field is always after the rndis header for request/response packet types so | |
2603 | + // we just used the SetRequest as a template | |
2604 | + set = &rndisMessage->Message.SetRequest; | |
2605 | + set->RequestId = InterlockedIncrement((int*)&Device->NewRequestId); | |
2606 | + | |
2607 | + // Add to the request list | |
2608 | + SpinlockAcquire(Device->RequestLock); | |
2609 | + INSERT_TAIL_LIST(&Device->RequestList, &request->ListEntry); | |
2610 | + SpinlockRelease(Device->RequestLock); | |
2611 | + | |
2612 | + return request; | |
2613 | +} | |
2614 | + | |
2615 | +static inline void PutRndisRequest(RNDIS_DEVICE *Device, RNDIS_REQUEST *Request) | |
2616 | +{ | |
2617 | + SpinlockAcquire(Device->RequestLock); | |
2618 | + REMOVE_ENTRY_LIST(&Request->ListEntry); | |
2619 | + SpinlockRelease(Device->RequestLock); | |
2620 | + | |
2621 | + WaitEventClose(Request->WaitEvent); | |
2622 | + MemFree(Request); | |
2623 | +} | |
2624 | + | |
2625 | +static inline void DumpRndisMessage(RNDIS_MESSAGE *RndisMessage) | |
2626 | +{ | |
2627 | + switch (RndisMessage->NdisMessageType) | |
2628 | + { | |
2629 | + case REMOTE_NDIS_PACKET_MSG: | |
2630 | + DPRINT_DBG(NETVSC, "REMOTE_NDIS_PACKET_MSG (len %u, data offset %u data len %u, # oob %u, oob offset %u, oob len %u, pkt offset %u, pkt len %u", | |
2631 | + RndisMessage->MessageLength, | |
2632 | + RndisMessage->Message.Packet.DataOffset, | |
2633 | + RndisMessage->Message.Packet.DataLength, | |
2634 | + RndisMessage->Message.Packet.NumOOBDataElements, | |
2635 | + RndisMessage->Message.Packet.OOBDataOffset, | |
2636 | + RndisMessage->Message.Packet.OOBDataLength, | |
2637 | + RndisMessage->Message.Packet.PerPacketInfoOffset, | |
2638 | + RndisMessage->Message.Packet.PerPacketInfoLength); | |
2639 | + break; | |
2640 | + | |
2641 | + case REMOTE_NDIS_INITIALIZE_CMPLT: | |
2642 | + DPRINT_DBG(NETVSC, "REMOTE_NDIS_INITIALIZE_CMPLT (len %u, id 0x%x, status 0x%x, major %d, minor %d, device flags %d, max xfer size 0x%x, max pkts %u, pkt aligned %u)", | |
2643 | + RndisMessage->MessageLength, | |
2644 | + RndisMessage->Message.InitializeComplete.RequestId, | |
2645 | + RndisMessage->Message.InitializeComplete.Status, | |
2646 | + RndisMessage->Message.InitializeComplete.MajorVersion, | |
2647 | + RndisMessage->Message.InitializeComplete.MinorVersion, | |
2648 | + RndisMessage->Message.InitializeComplete.DeviceFlags, | |
2649 | + RndisMessage->Message.InitializeComplete.MaxTransferSize, | |
2650 | + RndisMessage->Message.InitializeComplete.MaxPacketsPerMessage, | |
2651 | + RndisMessage->Message.InitializeComplete.PacketAlignmentFactor); | |
2652 | + break; | |
2653 | + | |
2654 | + case REMOTE_NDIS_QUERY_CMPLT: | |
2655 | + DPRINT_DBG(NETVSC, "REMOTE_NDIS_QUERY_CMPLT (len %u, id 0x%x, status 0x%x, buf len %u, buf offset %u)", | |
2656 | + RndisMessage->MessageLength, | |
2657 | + RndisMessage->Message.QueryComplete.RequestId, | |
2658 | + RndisMessage->Message.QueryComplete.Status, | |
2659 | + RndisMessage->Message.QueryComplete.InformationBufferLength, | |
2660 | + RndisMessage->Message.QueryComplete.InformationBufferOffset); | |
2661 | + break; | |
2662 | + | |
2663 | + case REMOTE_NDIS_SET_CMPLT: | |
2664 | + DPRINT_DBG(NETVSC, "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)", | |
2665 | + RndisMessage->MessageLength, | |
2666 | + RndisMessage->Message.SetComplete.RequestId, | |
2667 | + RndisMessage->Message.SetComplete.Status); | |
2668 | + break; | |
2669 | + | |
2670 | + case REMOTE_NDIS_INDICATE_STATUS_MSG: | |
2671 | + DPRINT_DBG(NETVSC, "REMOTE_NDIS_INDICATE_STATUS_MSG (len %u, status 0x%x, buf len %u, buf offset %u)", | |
2672 | + RndisMessage->MessageLength, | |
2673 | + RndisMessage->Message.IndicateStatus.Status, | |
2674 | + RndisMessage->Message.IndicateStatus.StatusBufferLength, | |
2675 | + RndisMessage->Message.IndicateStatus.StatusBufferOffset); | |
2676 | + break; | |
2677 | + | |
2678 | + default: | |
2679 | + DPRINT_DBG(NETVSC, "0x%x (len %u)", | |
2680 | + RndisMessage->NdisMessageType, | |
2681 | + RndisMessage->MessageLength); | |
2682 | + break; | |
2683 | + } | |
2684 | +} | |
2685 | + | |
2686 | +static int | |
2687 | +RndisFilterSendRequest( | |
2688 | + RNDIS_DEVICE *Device, | |
2689 | + RNDIS_REQUEST *Request | |
2690 | + ) | |
2691 | +{ | |
2692 | + int ret=0; | |
2693 | + NETVSC_PACKET *packet; | |
2694 | + | |
2695 | + DPRINT_ENTER(NETVSC); | |
2696 | + | |
2697 | + // Setup the packet to send it | |
2698 | + packet = &Request->Packet; | |
2699 | + | |
2700 | + packet->IsDataPacket = FALSE; | |
2701 | + packet->TotalDataBufferLength = Request->RequestMessage.MessageLength; | |
2702 | + packet->PageBufferCount = 1; | |
2703 | + | |
2704 | + packet->PageBuffers[0].Pfn = GetPhysicalAddress(&Request->RequestMessage) >> PAGE_SHIFT; | |
2705 | + packet->PageBuffers[0].Length = Request->RequestMessage.MessageLength; | |
2706 | + packet->PageBuffers[0].Offset = (ULONG_PTR)&Request->RequestMessage & (PAGE_SIZE -1); | |
2707 | + | |
2708 | + packet->Completion.Send.SendCompletionContext = Request;//packet; | |
2709 | + packet->Completion.Send.OnSendCompletion = RndisFilterOnSendRequestCompletion; | |
2710 | + packet->Completion.Send.SendCompletionTid = (ULONG_PTR)Device; | |
2711 | + | |
2712 | + ret = gRndisFilter.InnerDriver.OnSend(Device->NetDevice->Device, packet); | |
2713 | + DPRINT_EXIT(NETVSC); | |
2714 | + return ret; | |
2715 | +} | |
2716 | + | |
2717 | + | |
2718 | +static void | |
2719 | +RndisFilterReceiveResponse( | |
2720 | + RNDIS_DEVICE *Device, | |
2721 | + RNDIS_MESSAGE *Response | |
2722 | + ) | |
2723 | +{ | |
2724 | + LIST_ENTRY *anchor; | |
2725 | + LIST_ENTRY *curr; | |
2726 | + RNDIS_REQUEST *request=NULL; | |
2727 | + BOOL found=FALSE; | |
2728 | + | |
2729 | + DPRINT_ENTER(NETVSC); | |
2730 | + | |
2731 | + SpinlockAcquire(Device->RequestLock); | |
2732 | + ITERATE_LIST_ENTRIES(anchor, curr, &Device->RequestList) | |
2733 | + { | |
2734 | + request = CONTAINING_RECORD(curr, RNDIS_REQUEST, ListEntry); | |
2735 | + | |
2736 | + // All request/response message contains RequestId as the 1st field | |
2737 | + if (request->RequestMessage.Message.InitializeRequest.RequestId == Response->Message.InitializeComplete.RequestId) | |
2738 | + { | |
2739 | + DPRINT_DBG(NETVSC, "found rndis request for this response (id 0x%x req type 0x%x res type 0x%x)", | |
2740 | + request->RequestMessage.Message.InitializeRequest.RequestId, request->RequestMessage.NdisMessageType, Response->NdisMessageType); | |
2741 | + | |
2742 | + found = TRUE; | |
2743 | + break; | |
2744 | + } | |
2745 | + } | |
2746 | + SpinlockRelease(Device->RequestLock); | |
2747 | + | |
2748 | + if (found) | |
2749 | + { | |
2750 | + if (Response->MessageLength <= sizeof(RNDIS_MESSAGE)) | |
2751 | + { | |
2752 | + memcpy(&request->ResponseMessage, Response, Response->MessageLength); | |
2753 | + } | |
2754 | + else | |
2755 | + { | |
2756 | + DPRINT_ERR(NETVSC, "rndis response buffer overflow detected (size %u max %u)", Response->MessageLength, sizeof(RNDIS_FILTER_PACKET)); | |
2757 | + | |
2758 | + if (Response->NdisMessageType == REMOTE_NDIS_RESET_CMPLT) // does not have a request id field | |
2759 | + { | |
2760 | + request->ResponseMessage.Message.ResetComplete.Status = STATUS_BUFFER_OVERFLOW; | |
2761 | + } | |
2762 | + else | |
2763 | + { | |
2764 | + request->ResponseMessage.Message.InitializeComplete.Status = STATUS_BUFFER_OVERFLOW; | |
2765 | + } | |
2766 | + } | |
2767 | + | |
2768 | + WaitEventSet(request->WaitEvent); | |
2769 | + } | |
2770 | + else | |
2771 | + { | |
2772 | + DPRINT_ERR(NETVSC, "no rndis request found for this response (id 0x%x res type 0x%x)", | |
2773 | + Response->Message.InitializeComplete.RequestId, Response->NdisMessageType); | |
2774 | + } | |
2775 | + | |
2776 | + DPRINT_EXIT(NETVSC); | |
2777 | +} | |
2778 | + | |
2779 | +static void | |
2780 | +RndisFilterReceiveIndicateStatus( | |
2781 | + RNDIS_DEVICE *Device, | |
2782 | + RNDIS_MESSAGE *Response | |
2783 | + ) | |
2784 | +{ | |
2785 | + RNDIS_INDICATE_STATUS *indicate = &Response->Message.IndicateStatus; | |
2786 | + | |
2787 | + if (indicate->Status == RNDIS_STATUS_MEDIA_CONNECT) | |
2788 | + { | |
2789 | + gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 1); | |
2790 | + } | |
2791 | + else if (indicate->Status == RNDIS_STATUS_MEDIA_DISCONNECT) | |
2792 | + { | |
2793 | + gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 0); | |
2794 | + } | |
2795 | + else | |
2796 | + { | |
2797 | + // TODO: | |
2798 | + } | |
2799 | +} | |
2800 | + | |
2801 | +static void | |
2802 | +RndisFilterReceiveData( | |
2803 | + RNDIS_DEVICE *Device, | |
2804 | + RNDIS_MESSAGE *Message, | |
2805 | + NETVSC_PACKET *Packet | |
2806 | + ) | |
2807 | +{ | |
2808 | + RNDIS_PACKET *rndisPacket; | |
2809 | + UINT32 dataOffset; | |
2810 | + | |
2811 | + DPRINT_ENTER(NETVSC); | |
2812 | + | |
2813 | + // empty ethernet frame ?? | |
2814 | + ASSERT(Packet->PageBuffers[0].Length > RNDIS_MESSAGE_SIZE(RNDIS_PACKET)); | |
2815 | + | |
2816 | + rndisPacket = &Message->Message.Packet; | |
2817 | + | |
2818 | + // FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this | |
2819 | + // netvsc packet (ie TotalDataBufferLength != MessageLength) | |
2820 | + | |
2821 | + // Remove the rndis header and pass it back up the stack | |
2822 | + dataOffset = RNDIS_HEADER_SIZE + rndisPacket->DataOffset; | |
2823 | + | |
2824 | + Packet->TotalDataBufferLength -= dataOffset; | |
2825 | + Packet->PageBuffers[0].Offset += dataOffset; | |
2826 | + Packet->PageBuffers[0].Length -= dataOffset; | |
2827 | + | |
2828 | + Packet->IsDataPacket = TRUE; | |
2829 | + | |
2830 | + gRndisFilter.InnerDriver.OnReceiveCallback(Device->NetDevice->Device, Packet); | |
2831 | + | |
2832 | + DPRINT_EXIT(NETVSC); | |
2833 | +} | |
2834 | + | |
2835 | +static int | |
2836 | +RndisFilterOnReceive( | |
2837 | + DEVICE_OBJECT *Device, | |
2838 | + NETVSC_PACKET *Packet | |
2839 | + ) | |
2840 | +{ | |
2841 | + NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension; | |
2842 | + RNDIS_DEVICE *rndisDevice; | |
2843 | + RNDIS_MESSAGE rndisMessage; | |
2844 | + RNDIS_MESSAGE *rndisHeader; | |
2845 | + | |
2846 | + DPRINT_ENTER(NETVSC); | |
2847 | + | |
2848 | + ASSERT(netDevice); | |
2849 | + //Make sure the rndis device state is initialized | |
2850 | + if (!netDevice->Extension) | |
2851 | + { | |
2852 | + DPRINT_ERR(NETVSC, "got rndis message but no rndis device...dropping this message!"); | |
2853 | + DPRINT_EXIT(NETVSC); | |
2854 | + return -1; | |
2855 | + } | |
2856 | + | |
2857 | + rndisDevice = (RNDIS_DEVICE*)netDevice->Extension; | |
2858 | + if (rndisDevice->State == RNDIS_DEV_UNINITIALIZED) | |
2859 | + { | |
2860 | + DPRINT_ERR(NETVSC, "got rndis message but rndis device uninitialized...dropping this message!"); | |
2861 | + DPRINT_EXIT(NETVSC); | |
2862 | + return -1; | |
2863 | + } | |
2864 | + | |
2865 | + rndisHeader = (RNDIS_MESSAGE*)PageMapVirtualAddress(Packet->PageBuffers[0].Pfn); | |
2866 | + | |
2867 | + rndisHeader = (void*)((ULONG_PTR)rndisHeader + Packet->PageBuffers[0].Offset); | |
2868 | + | |
2869 | + // Make sure we got a valid rndis message | |
2870 | + // FIXME: There seems to be a bug in set completion msg where its MessageLength is 16 bytes but | |
2871 | + // the ByteCount field in the xfer page range shows 52 bytes | |
2872 | +#if 0 | |
2873 | + if ( Packet->TotalDataBufferLength != rndisHeader->MessageLength ) | |
2874 | + { | |
2875 | + PageUnmapVirtualAddress((void*)(ULONG_PTR)rndisHeader - Packet->PageBuffers[0].Offset); | |
2876 | + | |
2877 | + DPRINT_ERR(NETVSC, "invalid rndis message? (expected %u bytes got %u)...dropping this message!", | |
2878 | + rndisHeader->MessageLength, Packet->TotalDataBufferLength); | |
2879 | + DPRINT_EXIT(NETVSC); | |
2880 | + return -1; | |
2881 | + } | |
2882 | +#endif | |
2883 | + | |
2884 | + if ((rndisHeader->NdisMessageType != REMOTE_NDIS_PACKET_MSG) && (rndisHeader->MessageLength > sizeof(RNDIS_MESSAGE))) | |
2885 | + { | |
2886 | + DPRINT_ERR(NETVSC, "incoming rndis message buffer overflow detected (got %u, max %u)...marking it an error!", | |
2887 | + rndisHeader->MessageLength, sizeof(RNDIS_MESSAGE)); | |
2888 | + } | |
2889 | + | |
2890 | + memcpy(&rndisMessage, rndisHeader, (rndisHeader->MessageLength > sizeof(RNDIS_MESSAGE))?sizeof(RNDIS_MESSAGE):rndisHeader->MessageLength); | |
2891 | + | |
2892 | + PageUnmapVirtualAddress((void*)(ULONG_PTR)rndisHeader - Packet->PageBuffers[0].Offset); | |
2893 | + | |
2894 | + DumpRndisMessage(&rndisMessage); | |
2895 | + | |
2896 | + switch (rndisMessage.NdisMessageType) | |
2897 | + { | |
2898 | + // data msg | |
2899 | + case REMOTE_NDIS_PACKET_MSG: | |
2900 | + RndisFilterReceiveData(rndisDevice, &rndisMessage, Packet); | |
2901 | + break; | |
2902 | + | |
2903 | + // completion msgs | |
2904 | + case REMOTE_NDIS_INITIALIZE_CMPLT: | |
2905 | + case REMOTE_NDIS_QUERY_CMPLT: | |
2906 | + case REMOTE_NDIS_SET_CMPLT: | |
2907 | + //case REMOTE_NDIS_RESET_CMPLT: | |
2908 | + //case REMOTE_NDIS_KEEPALIVE_CMPLT: | |
2909 | + RndisFilterReceiveResponse(rndisDevice, &rndisMessage); | |
2910 | + break; | |
2911 | + | |
2912 | + // notification msgs | |
2913 | + case REMOTE_NDIS_INDICATE_STATUS_MSG: | |
2914 | + RndisFilterReceiveIndicateStatus(rndisDevice, &rndisMessage); | |
2915 | + break; | |
2916 | + default: | |
2917 | + DPRINT_ERR(NETVSC, "unhandled rndis message (type %u len %u)", rndisMessage.NdisMessageType, rndisMessage.MessageLength); | |
2918 | + break; | |
2919 | + } | |
2920 | + | |
2921 | + DPRINT_EXIT(NETVSC); | |
2922 | + return 0; | |
2923 | +} | |
2924 | + | |
2925 | + | |
2926 | +static int | |
2927 | +RndisFilterQueryDevice( | |
2928 | + RNDIS_DEVICE *Device, | |
2929 | + UINT32 Oid, | |
2930 | + VOID *Result, | |
2931 | + UINT32 *ResultSize | |
2932 | + ) | |
2933 | +{ | |
2934 | + RNDIS_REQUEST *request; | |
2935 | + UINT32 inresultSize = *ResultSize; | |
2936 | + RNDIS_QUERY_REQUEST *query; | |
2937 | + RNDIS_QUERY_COMPLETE *queryComplete; | |
2938 | + int ret=0; | |
2939 | + | |
2940 | + DPRINT_ENTER(NETVSC); | |
2941 | + | |
2942 | + ASSERT(Result); | |
2943 | + | |
2944 | + *ResultSize = 0; | |
2945 | + request = GetRndisRequest(Device, REMOTE_NDIS_QUERY_MSG, RNDIS_MESSAGE_SIZE(RNDIS_QUERY_REQUEST)); | |
2946 | + if (!request) | |
2947 | + { | |
2948 | + ret = -1; | |
2949 | + goto Cleanup; | |
2950 | + } | |
2951 | + | |
2952 | + // Setup the rndis query | |
2953 | + query = &request->RequestMessage.Message.QueryRequest; | |
2954 | + query->Oid = Oid; | |
2955 | + query->InformationBufferOffset = sizeof(RNDIS_QUERY_REQUEST); | |
2956 | + query->InformationBufferLength = 0; | |
2957 | + query->DeviceVcHandle = 0; | |
2958 | + | |
2959 | + ret = RndisFilterSendRequest(Device, request); | |
2960 | + if (ret != 0) | |
2961 | + { | |
2962 | + goto Cleanup; | |
2963 | + } | |
2964 | + | |
2965 | + WaitEventWait(request->WaitEvent); | |
2966 | + | |
2967 | + // Copy the response back | |
2968 | + queryComplete = &request->ResponseMessage.Message.QueryComplete; | |
2969 | + | |
2970 | + if (queryComplete->InformationBufferLength > inresultSize) | |
2971 | + { | |
2972 | + ret = -1; | |
2973 | + goto Cleanup; | |
2974 | + } | |
2975 | + | |
2976 | + memcpy(Result, | |
2977 | + (void*)((ULONG_PTR)queryComplete + queryComplete->InformationBufferOffset), | |
2978 | + queryComplete->InformationBufferLength); | |
2979 | + | |
2980 | + *ResultSize = queryComplete->InformationBufferLength; | |
2981 | + | |
2982 | +Cleanup: | |
2983 | + if (request) | |
2984 | + { | |
2985 | + PutRndisRequest(Device, request); | |
2986 | + } | |
2987 | + DPRINT_EXIT(NETVSC); | |
2988 | + | |
2989 | + return ret; | |
2990 | +} | |
2991 | + | |
2992 | +static inline int | |
2993 | +RndisFilterQueryDeviceMac( | |
2994 | + RNDIS_DEVICE *Device | |
2995 | + ) | |
2996 | +{ | |
2997 | + UINT32 size=HW_MACADDR_LEN; | |
2998 | + | |
2999 | + return RndisFilterQueryDevice(Device, | |
3000 | + RNDIS_OID_802_3_PERMANENT_ADDRESS, | |
3001 | + Device->HwMacAddr, | |
3002 | + &size); | |
3003 | +} | |
3004 | + | |
3005 | +static inline int | |
3006 | +RndisFilterQueryDeviceLinkStatus( | |
3007 | + RNDIS_DEVICE *Device | |
3008 | + ) | |
3009 | +{ | |
3010 | + UINT32 size=sizeof(UINT32); | |
3011 | + | |
3012 | + return RndisFilterQueryDevice(Device, | |
3013 | + RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, | |
3014 | + &Device->LinkStatus, | |
3015 | + &size); | |
3016 | +} | |
3017 | + | |
3018 | +static int | |
3019 | +RndisFilterSetPacketFilter( | |
3020 | + RNDIS_DEVICE *Device, | |
3021 | + UINT32 NewFilter | |
3022 | + ) | |
3023 | +{ | |
3024 | + RNDIS_REQUEST *request; | |
3025 | + RNDIS_SET_REQUEST *set; | |
3026 | + RNDIS_SET_COMPLETE *setComplete; | |
3027 | + UINT32 status; | |
3028 | + int ret; | |
3029 | + | |
3030 | + DPRINT_ENTER(NETVSC); | |
3031 | + | |
3032 | + ASSERT(RNDIS_MESSAGE_SIZE(RNDIS_SET_REQUEST) + sizeof(UINT32) <= sizeof(RNDIS_MESSAGE)); | |
3033 | + | |
3034 | + request = GetRndisRequest(Device, REMOTE_NDIS_SET_MSG, RNDIS_MESSAGE_SIZE(RNDIS_SET_REQUEST) + sizeof(UINT32)); | |
3035 | + if (!request) | |
3036 | + { | |
3037 | + ret = -1; | |
3038 | + goto Cleanup; | |
3039 | + } | |
3040 | + | |
3041 | + // Setup the rndis set | |
3042 | + set = &request->RequestMessage.Message.SetRequest; | |
3043 | + set->Oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; | |
3044 | + set->InformationBufferLength = sizeof(UINT32); | |
3045 | + set->InformationBufferOffset = sizeof(RNDIS_SET_REQUEST); | |
3046 | + | |
3047 | + memcpy((void*)(ULONG_PTR)set + sizeof(RNDIS_SET_REQUEST), &NewFilter, sizeof(UINT32)); | |
3048 | + | |
3049 | + ret = RndisFilterSendRequest(Device, request); | |
3050 | + if (ret != 0) | |
3051 | + { | |
3052 | + goto Cleanup; | |
3053 | + } | |
3054 | + | |
3055 | + ret = WaitEventWaitEx(request->WaitEvent, 2000/*2sec*/); | |
3056 | + if (!ret) | |
3057 | + { | |
3058 | + ret = -1; | |
3059 | + DPRINT_ERR(NETVSC, "timeout before we got a set response..."); | |
3060 | + // We cant deallocate the request since we may still receive a send completion for it. | |
3061 | + goto Exit; | |
3062 | + } | |
3063 | + else | |
3064 | + { | |
3065 | + if (ret > 0) | |
3066 | + { | |
3067 | + ret = 0; | |
3068 | + } | |
3069 | + setComplete = &request->ResponseMessage.Message.SetComplete; | |
3070 | + status = setComplete->Status; | |
3071 | + } | |
3072 | + | |
3073 | +Cleanup: | |
3074 | + if (request) | |
3075 | + { | |
3076 | + PutRndisRequest(Device, request); | |
3077 | + } | |
3078 | +Exit: | |
3079 | + DPRINT_EXIT(NETVSC); | |
3080 | + | |
3081 | + return ret; | |
3082 | +} | |
3083 | + | |
3084 | +int | |
3085 | +RndisFilterInit( | |
3086 | + NETVSC_DRIVER_OBJECT *Driver | |
3087 | + ) | |
3088 | +{ | |
3089 | + DPRINT_ENTER(NETVSC); | |
3090 | + | |
3091 | + DPRINT_DBG(NETVSC, "sizeof(RNDIS_FILTER_PACKET) == %d", sizeof(RNDIS_FILTER_PACKET)); | |
3092 | + | |
3093 | + Driver->RequestExtSize = sizeof(RNDIS_FILTER_PACKET); | |
3094 | + Driver->AdditionalRequestPageBufferCount = 1; // For rndis header | |
3095 | + | |
3096 | + //Driver->Context = rndisDriver; | |
3097 | + | |
3098 | + memset(&gRndisFilter, 0, sizeof(RNDIS_FILTER_DRIVER_OBJECT)); | |
3099 | + | |
3100 | + /*rndisDriver->Driver = Driver; | |
3101 | + | |
3102 | + ASSERT(Driver->OnLinkStatusChanged); | |
3103 | + rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/ | |
3104 | + | |
3105 | + // Save the original dispatch handlers before we override it | |
3106 | + gRndisFilter.InnerDriver.Base.OnDeviceAdd = Driver->Base.OnDeviceAdd; | |
3107 | + gRndisFilter.InnerDriver.Base.OnDeviceRemove = Driver->Base.OnDeviceRemove; | |
3108 | + gRndisFilter.InnerDriver.Base.OnCleanup = Driver->Base.OnCleanup; | |
3109 | + | |
3110 | + ASSERT(Driver->OnSend); | |
3111 | + ASSERT(Driver->OnReceiveCallback); | |
3112 | + gRndisFilter.InnerDriver.OnSend = Driver->OnSend; | |
3113 | + gRndisFilter.InnerDriver.OnReceiveCallback = Driver->OnReceiveCallback; | |
3114 | + gRndisFilter.InnerDriver.OnLinkStatusChanged = Driver->OnLinkStatusChanged; | |
3115 | + | |
3116 | + // Override | |
3117 | + Driver->Base.OnDeviceAdd = RndisFilterOnDeviceAdd; | |
3118 | + Driver->Base.OnDeviceRemove = RndisFilterOnDeviceRemove; | |
3119 | + Driver->Base.OnCleanup = RndisFilterOnCleanup; | |
3120 | + Driver->OnSend = RndisFilterOnSend; | |
3121 | + Driver->OnOpen = RndisFilterOnOpen; | |
3122 | + Driver->OnClose = RndisFilterOnClose; | |
3123 | + //Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; | |
3124 | + Driver->OnReceiveCallback = RndisFilterOnReceive; | |
3125 | + | |
3126 | + DPRINT_EXIT(NETVSC); | |
3127 | + | |
3128 | + return 0; | |
3129 | +} | |
3130 | + | |
3131 | +static int | |
3132 | +RndisFilterInitDevice( | |
3133 | + RNDIS_DEVICE *Device | |
3134 | + ) | |
3135 | +{ | |
3136 | + RNDIS_REQUEST *request; | |
3137 | + RNDIS_INITIALIZE_REQUEST *init; | |
3138 | + RNDIS_INITIALIZE_COMPLETE *initComplete; | |
3139 | + UINT32 status; | |
3140 | + int ret; | |
3141 | + | |
3142 | + DPRINT_ENTER(NETVSC); | |
3143 | + | |
3144 | + request = GetRndisRequest(Device, REMOTE_NDIS_INITIALIZE_MSG, RNDIS_MESSAGE_SIZE(RNDIS_INITIALIZE_REQUEST)); | |
3145 | + if (!request) | |
3146 | + { | |
3147 | + ret = -1; | |
3148 | + goto Cleanup; | |
3149 | + } | |
3150 | + | |
3151 | + // Setup the rndis set | |
3152 | + init = &request->RequestMessage.Message.InitializeRequest; | |
3153 | + init->MajorVersion = RNDIS_MAJOR_VERSION; | |
3154 | + init->MinorVersion = RNDIS_MINOR_VERSION; | |
3155 | + init->MaxTransferSize = 2048; // FIXME: Use 1536 - rounded ethernet frame size | |
3156 | + | |
3157 | + Device->State = RNDIS_DEV_INITIALIZING; | |
3158 | + | |
3159 | + ret = RndisFilterSendRequest(Device, request); | |
3160 | + if (ret != 0) | |
3161 | + { | |
3162 | + Device->State = RNDIS_DEV_UNINITIALIZED; | |
3163 | + goto Cleanup; | |
3164 | + } | |
3165 | + | |
3166 | + WaitEventWait(request->WaitEvent); | |
3167 | + | |
3168 | + initComplete = &request->ResponseMessage.Message.InitializeComplete; | |
3169 | + status = initComplete->Status; | |
3170 | + if (status == RNDIS_STATUS_SUCCESS) | |
3171 | + { | |
3172 | + Device->State = RNDIS_DEV_INITIALIZED; | |
3173 | + ret = 0; | |
3174 | + } | |
3175 | + else | |
3176 | + { | |
3177 | + Device->State = RNDIS_DEV_UNINITIALIZED; | |
3178 | + ret = -1; | |
3179 | + } | |
3180 | + | |
3181 | +Cleanup: | |
3182 | + if (request) | |
3183 | + { | |
3184 | + PutRndisRequest(Device, request); | |
3185 | + } | |
3186 | + DPRINT_EXIT(NETVSC); | |
3187 | + | |
3188 | + return ret; | |
3189 | +} | |
3190 | + | |
3191 | +static void | |
3192 | +RndisFilterHaltDevice( | |
3193 | + RNDIS_DEVICE *Device | |
3194 | + ) | |
3195 | +{ | |
3196 | + RNDIS_REQUEST *request; | |
3197 | + RNDIS_HALT_REQUEST *halt; | |
3198 | + | |
3199 | + DPRINT_ENTER(NETVSC); | |
3200 | + | |
3201 | + // Attempt to do a rndis device halt | |
3202 | + request = GetRndisRequest(Device, REMOTE_NDIS_HALT_MSG, RNDIS_MESSAGE_SIZE(RNDIS_HALT_REQUEST)); | |
3203 | + if (!request) | |
3204 | + { | |
3205 | + goto Cleanup; | |
3206 | + } | |
3207 | + | |
3208 | + // Setup the rndis set | |
3209 | + halt = &request->RequestMessage.Message.HaltRequest; | |
3210 | + halt->RequestId = InterlockedIncrement((int*)&Device->NewRequestId); | |
3211 | + | |
3212 | + // Ignore return since this msg is optional. | |
3213 | + RndisFilterSendRequest(Device, request); | |
3214 | + | |
3215 | + Device->State = RNDIS_DEV_UNINITIALIZED; | |
3216 | + | |
3217 | +Cleanup: | |
3218 | + if (request) | |
3219 | + { | |
3220 | + PutRndisRequest(Device, request); | |
3221 | + } | |
3222 | + DPRINT_EXIT(NETVSC); | |
3223 | + return; | |
3224 | +} | |
3225 | + | |
3226 | + | |
3227 | +static int | |
3228 | +RndisFilterOpenDevice( | |
3229 | + RNDIS_DEVICE *Device | |
3230 | + ) | |
3231 | +{ | |
3232 | + int ret=0; | |
3233 | + | |
3234 | + DPRINT_ENTER(NETVSC); | |
3235 | + | |
3236 | + if (Device->State != RNDIS_DEV_INITIALIZED) | |
3237 | + return 0; | |
3238 | + | |
3239 | + ret = RndisFilterSetPacketFilter(Device, NDIS_PACKET_TYPE_BROADCAST|NDIS_PACKET_TYPE_DIRECTED); | |
3240 | + if (ret == 0) | |
3241 | + { | |
3242 | + Device->State = RNDIS_DEV_DATAINITIALIZED; | |
3243 | + } | |
3244 | + | |
3245 | + DPRINT_EXIT(NETVSC); | |
3246 | + return ret; | |
3247 | +} | |
3248 | + | |
3249 | +static int | |
3250 | +RndisFilterCloseDevice( | |
3251 | + RNDIS_DEVICE *Device | |
3252 | + ) | |
3253 | +{ | |
3254 | + int ret; | |
3255 | + | |
3256 | + DPRINT_ENTER(NETVSC); | |
3257 | + | |
3258 | + if (Device->State != RNDIS_DEV_DATAINITIALIZED) | |
3259 | + return 0; | |
3260 | + | |
3261 | + ret = RndisFilterSetPacketFilter(Device, 0); | |
3262 | + if (ret == 0) | |
3263 | + { | |
3264 | + Device->State = RNDIS_DEV_INITIALIZED; | |
3265 | + } | |
3266 | + | |
3267 | + DPRINT_EXIT(NETVSC); | |
3268 | + | |
3269 | + return ret; | |
3270 | +} | |
3271 | + | |
3272 | + | |
3273 | +int | |
3274 | +RndisFilterOnDeviceAdd( | |
3275 | + DEVICE_OBJECT *Device, | |
3276 | + void *AdditionalInfo | |
3277 | + ) | |
3278 | +{ | |
3279 | + int ret; | |
3280 | + NETVSC_DEVICE *netDevice; | |
3281 | + RNDIS_DEVICE *rndisDevice; | |
3282 | + NETVSC_DEVICE_INFO *deviceInfo = (NETVSC_DEVICE_INFO*)AdditionalInfo; | |
3283 | + | |
3284 | + DPRINT_ENTER(NETVSC); | |
3285 | + | |
3286 | + //rndisDevice = MemAlloc(sizeof(RNDIS_DEVICE)); | |
3287 | + rndisDevice = GetRndisDevice(); | |
3288 | + if (!rndisDevice) | |
3289 | + { | |
3290 | + DPRINT_EXIT(NETVSC); | |
3291 | + return -1; | |
3292 | + } | |
3293 | + | |
3294 | + DPRINT_DBG(NETVSC, "rndis device object allocated - %p", rndisDevice); | |
3295 | + | |
3296 | + // Let the inner driver handle this first to create the netvsc channel | |
3297 | + // NOTE! Once the channel is created, we may get a receive callback | |
3298 | + // (RndisFilterOnReceive()) before this call is completed | |
3299 | + ret = gRndisFilter.InnerDriver.Base.OnDeviceAdd(Device, AdditionalInfo); | |
3300 | + if (ret != 0) | |
3301 | + { | |
3302 | + PutRndisDevice(rndisDevice); | |
3303 | + DPRINT_EXIT(NETVSC); | |
3304 | + return ret; | |
3305 | + } | |
3306 | + | |
3307 | + // | |
3308 | + // Initialize the rndis device | |
3309 | + // | |
3310 | + netDevice = (NETVSC_DEVICE*)Device->Extension; | |
3311 | + ASSERT(netDevice); | |
3312 | + ASSERT(netDevice->Device); | |
3313 | + | |
3314 | + netDevice->Extension = rndisDevice; | |
3315 | + rndisDevice->NetDevice = netDevice; | |
3316 | + | |
3317 | + // Send the rndis initialization message | |
3318 | + ret = RndisFilterInitDevice(rndisDevice); | |
3319 | + if (ret != 0) | |
3320 | + { | |
3321 | + // TODO: If rndis init failed, we will need to shut down the channel | |
3322 | + } | |
3323 | + | |
3324 | + // Get the mac address | |
3325 | + ret = RndisFilterQueryDeviceMac(rndisDevice); | |
3326 | + if (ret != 0) | |
3327 | + { | |
3328 | + // TODO: shutdown rndis device and the channel | |
3329 | + } | |
3330 | + | |
3331 | + DPRINT_INFO(NETVSC, "Device 0x%p mac addr %02x%02x%02x%02x%02x%02x", | |
3332 | + rndisDevice, | |
3333 | + rndisDevice->HwMacAddr[0], | |
3334 | + rndisDevice->HwMacAddr[1], | |
3335 | + rndisDevice->HwMacAddr[2], | |
3336 | + rndisDevice->HwMacAddr[3], | |
3337 | + rndisDevice->HwMacAddr[4], | |
3338 | + rndisDevice->HwMacAddr[5]); | |
3339 | + | |
3340 | + memcpy(deviceInfo->MacAddr, rndisDevice->HwMacAddr, HW_MACADDR_LEN); | |
3341 | + | |
3342 | + RndisFilterQueryDeviceLinkStatus(rndisDevice); | |
3343 | + | |
3344 | + deviceInfo->LinkState = rndisDevice->LinkStatus; | |
3345 | + DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice, ((deviceInfo->LinkState)?("down"):("up"))); | |
3346 | + | |
3347 | + DPRINT_EXIT(NETVSC); | |
3348 | + | |
3349 | + return ret; | |
3350 | +} | |
3351 | + | |
3352 | + | |
3353 | +static int | |
3354 | +RndisFilterOnDeviceRemove( | |
3355 | + DEVICE_OBJECT *Device | |
3356 | + ) | |
3357 | +{ | |
3358 | + NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension; | |
3359 | + RNDIS_DEVICE *rndisDevice = (RNDIS_DEVICE*)netDevice->Extension; | |
3360 | + | |
3361 | + DPRINT_ENTER(NETVSC); | |
3362 | + | |
3363 | + // Halt and release the rndis device | |
3364 | + RndisFilterHaltDevice(rndisDevice); | |
3365 | + | |
3366 | + PutRndisDevice(rndisDevice); | |
3367 | + netDevice->Extension = NULL; | |
3368 | + | |
3369 | + // Pass control to inner driver to remove the device | |
3370 | + gRndisFilter.InnerDriver.Base.OnDeviceRemove(Device); | |
3371 | + | |
3372 | + DPRINT_EXIT(NETVSC); | |
3373 | + | |
3374 | + return 0; | |
3375 | +} | |
3376 | + | |
3377 | + | |
3378 | +static void | |
3379 | +RndisFilterOnCleanup( | |
3380 | + DRIVER_OBJECT *Driver | |
3381 | + ) | |
3382 | +{ | |
3383 | + DPRINT_ENTER(NETVSC); | |
3384 | + | |
3385 | + DPRINT_EXIT(NETVSC); | |
3386 | +} | |
3387 | + | |
3388 | +static int | |
3389 | +RndisFilterOnOpen( | |
3390 | + DEVICE_OBJECT *Device | |
3391 | + ) | |
3392 | +{ | |
3393 | + int ret; | |
3394 | + NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension; | |
3395 | + | |
3396 | + DPRINT_ENTER(NETVSC); | |
3397 | + | |
3398 | + ASSERT(netDevice); | |
3399 | + ret = RndisFilterOpenDevice((RNDIS_DEVICE*)netDevice->Extension); | |
3400 | + | |
3401 | + DPRINT_EXIT(NETVSC); | |
3402 | + | |
3403 | + return ret; | |
3404 | +} | |
3405 | + | |
3406 | +static int | |
3407 | +RndisFilterOnClose( | |
3408 | + DEVICE_OBJECT *Device | |
3409 | + ) | |
3410 | +{ | |
3411 | + int ret; | |
3412 | + NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension; | |
3413 | + | |
3414 | + DPRINT_ENTER(NETVSC); | |
3415 | + | |
3416 | + ASSERT(netDevice); | |
3417 | + ret = RndisFilterCloseDevice((RNDIS_DEVICE*)netDevice->Extension); | |
3418 | + | |
3419 | + DPRINT_EXIT(NETVSC); | |
3420 | + | |
3421 | + return ret; | |
3422 | +} | |
3423 | + | |
3424 | + | |
3425 | +static int | |
3426 | +RndisFilterOnSend( | |
3427 | + DEVICE_OBJECT *Device, | |
3428 | + NETVSC_PACKET *Packet | |
3429 | + ) | |
3430 | +{ | |
3431 | + int ret=0; | |
3432 | + RNDIS_FILTER_PACKET *filterPacket; | |
3433 | + RNDIS_MESSAGE *rndisMessage; | |
3434 | + RNDIS_PACKET *rndisPacket; | |
3435 | + UINT32 rndisMessageSize; | |
3436 | + | |
3437 | + DPRINT_ENTER(NETVSC); | |
3438 | + | |
3439 | + // Add the rndis header | |
3440 | + filterPacket = (RNDIS_FILTER_PACKET*)Packet->Extension; | |
3441 | + ASSERT(filterPacket); | |
3442 | + | |
3443 | + memset(filterPacket, 0, sizeof(RNDIS_FILTER_PACKET)); | |
3444 | + | |
3445 | + rndisMessage = &filterPacket->Message; | |
3446 | + rndisMessageSize = RNDIS_MESSAGE_SIZE(RNDIS_PACKET); | |
3447 | + | |
3448 | + rndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG; | |
3449 | + rndisMessage->MessageLength = Packet->TotalDataBufferLength + rndisMessageSize; | |
3450 | + | |
3451 | + rndisPacket = &rndisMessage->Message.Packet; | |
3452 | + rndisPacket->DataOffset = sizeof(RNDIS_PACKET); | |
3453 | + rndisPacket->DataLength = Packet->TotalDataBufferLength; | |
3454 | + | |
3455 | + Packet->IsDataPacket = TRUE; | |
3456 | + Packet->PageBuffers[0].Pfn = GetPhysicalAddress(rndisMessage) >> PAGE_SHIFT; | |
3457 | + Packet->PageBuffers[0].Offset = (ULONG_PTR)rndisMessage & (PAGE_SIZE-1); | |
3458 | + Packet->PageBuffers[0].Length = rndisMessageSize; | |
3459 | + | |
3460 | + // Save the packet send completion and context | |
3461 | + filterPacket->OnCompletion = Packet->Completion.Send.OnSendCompletion; | |
3462 | + filterPacket->CompletionContext = Packet->Completion.Send.SendCompletionContext; | |
3463 | + | |
3464 | + // Use ours | |
3465 | + Packet->Completion.Send.OnSendCompletion = RndisFilterOnSendCompletion; | |
3466 | + Packet->Completion.Send.SendCompletionContext = filterPacket; | |
3467 | + | |
3468 | + ret = gRndisFilter.InnerDriver.OnSend(Device, Packet); | |
3469 | + if (ret != 0) | |
3470 | + { | |
3471 | + // Reset the completion to originals to allow retries from above | |
3472 | + Packet->Completion.Send.OnSendCompletion = filterPacket->OnCompletion; | |
3473 | + Packet->Completion.Send.SendCompletionContext = filterPacket->CompletionContext; | |
3474 | + } | |
3475 | + | |
3476 | + DPRINT_EXIT(NETVSC); | |
3477 | + | |
3478 | + return ret; | |
3479 | +} | |
3480 | + | |
3481 | +static void | |
3482 | +RndisFilterOnSendCompletion( | |
3483 | + void *Context) | |
3484 | +{ | |
3485 | + RNDIS_FILTER_PACKET *filterPacket = (RNDIS_FILTER_PACKET *)Context; | |
3486 | + | |
3487 | + DPRINT_ENTER(NETVSC); | |
3488 | + | |
3489 | + // Pass it back to the original handler | |
3490 | + filterPacket->OnCompletion(filterPacket->CompletionContext); | |
3491 | + | |
3492 | + DPRINT_EXIT(NETVSC); | |
3493 | +} | |
3494 | + | |
3495 | + | |
3496 | +static void | |
3497 | +RndisFilterOnSendRequestCompletion( | |
3498 | + void *Context | |
3499 | + ) | |
3500 | +{ | |
3501 | + DPRINT_ENTER(NETVSC); | |
3502 | + | |
3503 | + // Noop | |
3504 | + DPRINT_EXIT(NETVSC); | |
3505 | +} | |
3506 | --- /dev/null | |
3507 | +++ b/drivers/staging/hv/RndisFilter.h | |
3508 | @@ -0,0 +1,61 @@ | |
3509 | +/* | |
3510 | + * | |
3511 | + * Copyright (c) 2009, Microsoft Corporation. | |
3512 | + * | |
3513 | + * This program is free software; you can redistribute it and/or modify it | |
3514 | + * under the terms and conditions of the GNU General Public License, | |
3515 | + * version 2, as published by the Free Software Foundation. | |
3516 | + * | |
3517 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
3518 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
3519 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
3520 | + * more details. | |
3521 | + * | |
3522 | + * You should have received a copy of the GNU General Public License along with | |
3523 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
3524 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
3525 | + * | |
3526 | + * Authors: | |
3527 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
3528 | + * Hank Janssen <hjanssen@microsoft.com> | |
3529 | + * | |
3530 | + */ | |
3531 | + | |
3532 | + | |
3533 | +#ifndef _RNDISFILTER_H_ | |
3534 | +#define _RNDISFILTER_H_ | |
3535 | + | |
3536 | +#define __struct_bcount(x) | |
3537 | + | |
3538 | +#include "osd.h" | |
3539 | +#include "NetVsc.h" | |
3540 | + | |
3541 | +#include "rndis.h" | |
3542 | + | |
3543 | +#define RNDIS_HEADER_SIZE (sizeof(RNDIS_MESSAGE) - sizeof(RNDIS_MESSAGE_CONTAINER)) | |
3544 | + | |
3545 | +#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 | |
3546 | +#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 | |
3547 | +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 | |
3548 | +#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 | |
3549 | +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 | |
3550 | +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 | |
3551 | +#define NDIS_PACKET_TYPE_SMT 0x00000040 | |
3552 | +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 | |
3553 | +#define NDIS_PACKET_TYPE_GROUP 0x00000100 | |
3554 | +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200 | |
3555 | +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 | |
3556 | +#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 | |
3557 | + | |
3558 | + | |
3559 | + | |
3560 | +// | |
3561 | +// Interface | |
3562 | +// | |
3563 | +int | |
3564 | +RndisFilterInit( | |
3565 | + NETVSC_DRIVER_OBJECT *Driver | |
3566 | + ); | |
3567 | + | |
3568 | + | |
3569 | +#endif // _RNDISFILTER_H_ |