]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/staging/hv/RndisFilter.c
Staging: hv: add the Hyper-V virtual network driver
[mirror_ubuntu-artful-kernel.git] / drivers / staging / hv / RndisFilter.c
CommitLineData
fceaf24a
HJ
1/*
2 *
3 * Copyright (c) 2009, Microsoft Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 *
18 * Authors:
19 * Haiyang Zhang <haiyangz@microsoft.com>
20 * Hank Janssen <hjanssen@microsoft.com>
21 *
22 */
23
24
25#include "logging.h"
26
27#include "NetVscApi.h"
28#include "RndisFilter.h"
29
30//
31// Data types
32//
33
34typedef struct _RNDIS_FILTER_DRIVER_OBJECT {
35 // The original driver
36 NETVSC_DRIVER_OBJECT InnerDriver;
37
38} RNDIS_FILTER_DRIVER_OBJECT;
39
40typedef enum {
41 RNDIS_DEV_UNINITIALIZED = 0,
42 RNDIS_DEV_INITIALIZING,
43 RNDIS_DEV_INITIALIZED,
44 RNDIS_DEV_DATAINITIALIZED,
45} RNDIS_DEVICE_STATE;
46
47typedef struct _RNDIS_DEVICE {
48 NETVSC_DEVICE *NetDevice;
49
50 RNDIS_DEVICE_STATE State;
51 UINT32 LinkStatus;
52 UINT32 NewRequestId;
53
54 HANDLE RequestLock;
55 LIST_ENTRY RequestList;
56
57 UCHAR HwMacAddr[HW_MACADDR_LEN];
58} RNDIS_DEVICE;
59
60
61typedef struct _RNDIS_REQUEST {
62 LIST_ENTRY ListEntry;
63 HANDLE WaitEvent;
64
65 // FIXME: We assumed a fixed size response here. If we do ever need to handle a bigger response,
66 // we can either define a max response message or add a response buffer variable above this field
67 RNDIS_MESSAGE ResponseMessage;
68
69 // Simplify allocation by having a netvsc packet inline
70 NETVSC_PACKET Packet;
71 PAGE_BUFFER Buffer;
72 // FIXME: We assumed a fixed size request here.
73 RNDIS_MESSAGE RequestMessage;
74} RNDIS_REQUEST;
75
76
77typedef struct _RNDIS_FILTER_PACKET {
78 void *CompletionContext;
79 PFN_ON_SENDRECVCOMPLETION OnCompletion;
80
81 RNDIS_MESSAGE Message;
82} RNDIS_FILTER_PACKET;
83
84//
85// Internal routines
86//
87static int
88RndisFilterSendRequest(
89 RNDIS_DEVICE *Device,
90 RNDIS_REQUEST *Request
91 );
92
93static void
94RndisFilterReceiveResponse(
95 RNDIS_DEVICE *Device,
96 RNDIS_MESSAGE *Response
97 );
98
99static void
100RndisFilterReceiveIndicateStatus(
101 RNDIS_DEVICE *Device,
102 RNDIS_MESSAGE *Response
103 );
104
105static void
106RndisFilterReceiveData(
107 RNDIS_DEVICE *Device,
108 RNDIS_MESSAGE *Message,
109 NETVSC_PACKET *Packet
110 );
111
112static int
113RndisFilterOnReceive(
114 DEVICE_OBJECT *Device,
115 NETVSC_PACKET *Packet
116 );
117
118static int
119RndisFilterQueryDevice(
120 RNDIS_DEVICE *Device,
121 UINT32 Oid,
122 VOID *Result,
123 UINT32 *ResultSize
124 );
125
126static inline int
127RndisFilterQueryDeviceMac(
128 RNDIS_DEVICE *Device
129 );
130
131static inline int
132RndisFilterQueryDeviceLinkStatus(
133 RNDIS_DEVICE *Device
134 );
135
136static int
137RndisFilterSetPacketFilter(
138 RNDIS_DEVICE *Device,
139 UINT32 NewFilter
140 );
141
142static int
143RndisFilterInitDevice(
144 RNDIS_DEVICE *Device
145 );
146
147static int
148RndisFilterOpenDevice(
149 RNDIS_DEVICE *Device
150 );
151
152static int
153RndisFilterCloseDevice(
154 RNDIS_DEVICE *Device
155 );
156
157static int
158RndisFilterOnDeviceAdd(
159 DEVICE_OBJECT *Device,
160 void *AdditionalInfo
161 );
162
163static int
164RndisFilterOnDeviceRemove(
165 DEVICE_OBJECT *Device
166 );
167
168static void
169RndisFilterOnCleanup(
170 DRIVER_OBJECT *Driver
171 );
172
173static int
174RndisFilterOnOpen(
175 DEVICE_OBJECT *Device
176 );
177
178static int
179RndisFilterOnClose(
180 DEVICE_OBJECT *Device
181 );
182
183static int
184RndisFilterOnSend(
185 DEVICE_OBJECT *Device,
186 NETVSC_PACKET *Packet
187 );
188
189static void
190RndisFilterOnSendCompletion(
191 void *Context
192 );
193
194static void
195RndisFilterOnSendRequestCompletion(
196 void *Context
197 );
198
199//
200// Global var
201//
202
203// The one and only
204RNDIS_FILTER_DRIVER_OBJECT gRndisFilter;
205
206static inline RNDIS_DEVICE* GetRndisDevice(void)
207{
208 RNDIS_DEVICE *device;
209
210 device = MemAllocZeroed(sizeof(RNDIS_DEVICE));
211 if (!device)
212 {
213 return NULL;
214 }
215
216 device->RequestLock = SpinlockCreate();
217 if (!device->RequestLock)
218 {
219 MemFree(device);
220 return NULL;
221 }
222
223 INITIALIZE_LIST_HEAD(&device->RequestList);
224
225 device->State = RNDIS_DEV_UNINITIALIZED;
226
227 return device;
228}
229
230static inline void PutRndisDevice(RNDIS_DEVICE *Device)
231{
232 SpinlockClose(Device->RequestLock);
233 MemFree(Device);
234}
235
236static inline RNDIS_REQUEST* GetRndisRequest(RNDIS_DEVICE *Device, UINT32 MessageType, UINT32 MessageLength)
237{
238 RNDIS_REQUEST *request;
239 RNDIS_MESSAGE *rndisMessage;
240 RNDIS_SET_REQUEST *set;
241
242 request = MemAllocZeroed(sizeof(RNDIS_REQUEST));
243 if (!request)
244 {
245 return NULL;
246 }
247
248 request->WaitEvent = WaitEventCreate();
249 if (!request->WaitEvent)
250 {
251 MemFree(request);
252 return NULL;
253 }
254
255 rndisMessage = &request->RequestMessage;
256 rndisMessage->NdisMessageType = MessageType;
257 rndisMessage->MessageLength = MessageLength;
258
259 // Set the request id. This field is always after the rndis header for request/response packet types so
260 // we just used the SetRequest as a template
261 set = &rndisMessage->Message.SetRequest;
262 set->RequestId = InterlockedIncrement((int*)&Device->NewRequestId);
263
264 // Add to the request list
265 SpinlockAcquire(Device->RequestLock);
266 INSERT_TAIL_LIST(&Device->RequestList, &request->ListEntry);
267 SpinlockRelease(Device->RequestLock);
268
269 return request;
270}
271
272static inline void PutRndisRequest(RNDIS_DEVICE *Device, RNDIS_REQUEST *Request)
273{
274 SpinlockAcquire(Device->RequestLock);
275 REMOVE_ENTRY_LIST(&Request->ListEntry);
276 SpinlockRelease(Device->RequestLock);
277
278 WaitEventClose(Request->WaitEvent);
279 MemFree(Request);
280}
281
282static inline void DumpRndisMessage(RNDIS_MESSAGE *RndisMessage)
283{
284 switch (RndisMessage->NdisMessageType)
285 {
286 case REMOTE_NDIS_PACKET_MSG:
287 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",
288 RndisMessage->MessageLength,
289 RndisMessage->Message.Packet.DataOffset,
290 RndisMessage->Message.Packet.DataLength,
291 RndisMessage->Message.Packet.NumOOBDataElements,
292 RndisMessage->Message.Packet.OOBDataOffset,
293 RndisMessage->Message.Packet.OOBDataLength,
294 RndisMessage->Message.Packet.PerPacketInfoOffset,
295 RndisMessage->Message.Packet.PerPacketInfoLength);
296 break;
297
298 case REMOTE_NDIS_INITIALIZE_CMPLT:
299 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)",
300 RndisMessage->MessageLength,
301 RndisMessage->Message.InitializeComplete.RequestId,
302 RndisMessage->Message.InitializeComplete.Status,
303 RndisMessage->Message.InitializeComplete.MajorVersion,
304 RndisMessage->Message.InitializeComplete.MinorVersion,
305 RndisMessage->Message.InitializeComplete.DeviceFlags,
306 RndisMessage->Message.InitializeComplete.MaxTransferSize,
307 RndisMessage->Message.InitializeComplete.MaxPacketsPerMessage,
308 RndisMessage->Message.InitializeComplete.PacketAlignmentFactor);
309 break;
310
311 case REMOTE_NDIS_QUERY_CMPLT:
312 DPRINT_DBG(NETVSC, "REMOTE_NDIS_QUERY_CMPLT (len %u, id 0x%x, status 0x%x, buf len %u, buf offset %u)",
313 RndisMessage->MessageLength,
314 RndisMessage->Message.QueryComplete.RequestId,
315 RndisMessage->Message.QueryComplete.Status,
316 RndisMessage->Message.QueryComplete.InformationBufferLength,
317 RndisMessage->Message.QueryComplete.InformationBufferOffset);
318 break;
319
320 case REMOTE_NDIS_SET_CMPLT:
321 DPRINT_DBG(NETVSC, "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)",
322 RndisMessage->MessageLength,
323 RndisMessage->Message.SetComplete.RequestId,
324 RndisMessage->Message.SetComplete.Status);
325 break;
326
327 case REMOTE_NDIS_INDICATE_STATUS_MSG:
328 DPRINT_DBG(NETVSC, "REMOTE_NDIS_INDICATE_STATUS_MSG (len %u, status 0x%x, buf len %u, buf offset %u)",
329 RndisMessage->MessageLength,
330 RndisMessage->Message.IndicateStatus.Status,
331 RndisMessage->Message.IndicateStatus.StatusBufferLength,
332 RndisMessage->Message.IndicateStatus.StatusBufferOffset);
333 break;
334
335 default:
336 DPRINT_DBG(NETVSC, "0x%x (len %u)",
337 RndisMessage->NdisMessageType,
338 RndisMessage->MessageLength);
339 break;
340 }
341}
342
343static int
344RndisFilterSendRequest(
345 RNDIS_DEVICE *Device,
346 RNDIS_REQUEST *Request
347 )
348{
349 int ret=0;
350 NETVSC_PACKET *packet;
351
352 DPRINT_ENTER(NETVSC);
353
354 // Setup the packet to send it
355 packet = &Request->Packet;
356
357 packet->IsDataPacket = FALSE;
358 packet->TotalDataBufferLength = Request->RequestMessage.MessageLength;
359 packet->PageBufferCount = 1;
360
361 packet->PageBuffers[0].Pfn = GetPhysicalAddress(&Request->RequestMessage) >> PAGE_SHIFT;
362 packet->PageBuffers[0].Length = Request->RequestMessage.MessageLength;
363 packet->PageBuffers[0].Offset = (ULONG_PTR)&Request->RequestMessage & (PAGE_SIZE -1);
364
365 packet->Completion.Send.SendCompletionContext = Request;//packet;
366 packet->Completion.Send.OnSendCompletion = RndisFilterOnSendRequestCompletion;
367 packet->Completion.Send.SendCompletionTid = (ULONG_PTR)Device;
368
369 ret = gRndisFilter.InnerDriver.OnSend(Device->NetDevice->Device, packet);
370 DPRINT_EXIT(NETVSC);
371 return ret;
372}
373
374
375static void
376RndisFilterReceiveResponse(
377 RNDIS_DEVICE *Device,
378 RNDIS_MESSAGE *Response
379 )
380{
381 LIST_ENTRY *anchor;
382 LIST_ENTRY *curr;
383 RNDIS_REQUEST *request=NULL;
384 BOOL found=FALSE;
385
386 DPRINT_ENTER(NETVSC);
387
388 SpinlockAcquire(Device->RequestLock);
389 ITERATE_LIST_ENTRIES(anchor, curr, &Device->RequestList)
390 {
391 request = CONTAINING_RECORD(curr, RNDIS_REQUEST, ListEntry);
392
393 // All request/response message contains RequestId as the 1st field
394 if (request->RequestMessage.Message.InitializeRequest.RequestId == Response->Message.InitializeComplete.RequestId)
395 {
396 DPRINT_DBG(NETVSC, "found rndis request for this response (id 0x%x req type 0x%x res type 0x%x)",
397 request->RequestMessage.Message.InitializeRequest.RequestId, request->RequestMessage.NdisMessageType, Response->NdisMessageType);
398
399 found = TRUE;
400 break;
401 }
402 }
403 SpinlockRelease(Device->RequestLock);
404
405 if (found)
406 {
407 if (Response->MessageLength <= sizeof(RNDIS_MESSAGE))
408 {
409 memcpy(&request->ResponseMessage, Response, Response->MessageLength);
410 }
411 else
412 {
413 DPRINT_ERR(NETVSC, "rndis response buffer overflow detected (size %u max %u)", Response->MessageLength, sizeof(RNDIS_FILTER_PACKET));
414
415 if (Response->NdisMessageType == REMOTE_NDIS_RESET_CMPLT) // does not have a request id field
416 {
417 request->ResponseMessage.Message.ResetComplete.Status = STATUS_BUFFER_OVERFLOW;
418 }
419 else
420 {
421 request->ResponseMessage.Message.InitializeComplete.Status = STATUS_BUFFER_OVERFLOW;
422 }
423 }
424
425 WaitEventSet(request->WaitEvent);
426 }
427 else
428 {
429 DPRINT_ERR(NETVSC, "no rndis request found for this response (id 0x%x res type 0x%x)",
430 Response->Message.InitializeComplete.RequestId, Response->NdisMessageType);
431 }
432
433 DPRINT_EXIT(NETVSC);
434}
435
436static void
437RndisFilterReceiveIndicateStatus(
438 RNDIS_DEVICE *Device,
439 RNDIS_MESSAGE *Response
440 )
441{
442 RNDIS_INDICATE_STATUS *indicate = &Response->Message.IndicateStatus;
443
444 if (indicate->Status == RNDIS_STATUS_MEDIA_CONNECT)
445 {
446 gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 1);
447 }
448 else if (indicate->Status == RNDIS_STATUS_MEDIA_DISCONNECT)
449 {
450 gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 0);
451 }
452 else
453 {
454 // TODO:
455 }
456}
457
458static void
459RndisFilterReceiveData(
460 RNDIS_DEVICE *Device,
461 RNDIS_MESSAGE *Message,
462 NETVSC_PACKET *Packet
463 )
464{
465 RNDIS_PACKET *rndisPacket;
466 UINT32 dataOffset;
467
468 DPRINT_ENTER(NETVSC);
469
470 // empty ethernet frame ??
471 ASSERT(Packet->PageBuffers[0].Length > RNDIS_MESSAGE_SIZE(RNDIS_PACKET));
472
473 rndisPacket = &Message->Message.Packet;
474
475 // FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this
476 // netvsc packet (ie TotalDataBufferLength != MessageLength)
477
478 // Remove the rndis header and pass it back up the stack
479 dataOffset = RNDIS_HEADER_SIZE + rndisPacket->DataOffset;
480
481 Packet->TotalDataBufferLength -= dataOffset;
482 Packet->PageBuffers[0].Offset += dataOffset;
483 Packet->PageBuffers[0].Length -= dataOffset;
484
485 Packet->IsDataPacket = TRUE;
486
487 gRndisFilter.InnerDriver.OnReceiveCallback(Device->NetDevice->Device, Packet);
488
489 DPRINT_EXIT(NETVSC);
490}
491
492static int
493RndisFilterOnReceive(
494 DEVICE_OBJECT *Device,
495 NETVSC_PACKET *Packet
496 )
497{
498 NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension;
499 RNDIS_DEVICE *rndisDevice;
500 RNDIS_MESSAGE rndisMessage;
501 RNDIS_MESSAGE *rndisHeader;
502
503 DPRINT_ENTER(NETVSC);
504
505 ASSERT(netDevice);
506 //Make sure the rndis device state is initialized
507 if (!netDevice->Extension)
508 {
509 DPRINT_ERR(NETVSC, "got rndis message but no rndis device...dropping this message!");
510 DPRINT_EXIT(NETVSC);
511 return -1;
512 }
513
514 rndisDevice = (RNDIS_DEVICE*)netDevice->Extension;
515 if (rndisDevice->State == RNDIS_DEV_UNINITIALIZED)
516 {
517 DPRINT_ERR(NETVSC, "got rndis message but rndis device uninitialized...dropping this message!");
518 DPRINT_EXIT(NETVSC);
519 return -1;
520 }
521
522 rndisHeader = (RNDIS_MESSAGE*)PageMapVirtualAddress(Packet->PageBuffers[0].Pfn);
523
524 rndisHeader = (void*)((ULONG_PTR)rndisHeader + Packet->PageBuffers[0].Offset);
525
526 // Make sure we got a valid rndis message
527 // FIXME: There seems to be a bug in set completion msg where its MessageLength is 16 bytes but
528 // the ByteCount field in the xfer page range shows 52 bytes
529#if 0
530 if ( Packet->TotalDataBufferLength != rndisHeader->MessageLength )
531 {
532 PageUnmapVirtualAddress((void*)(ULONG_PTR)rndisHeader - Packet->PageBuffers[0].Offset);
533
534 DPRINT_ERR(NETVSC, "invalid rndis message? (expected %u bytes got %u)...dropping this message!",
535 rndisHeader->MessageLength, Packet->TotalDataBufferLength);
536 DPRINT_EXIT(NETVSC);
537 return -1;
538 }
539#endif
540
541 if ((rndisHeader->NdisMessageType != REMOTE_NDIS_PACKET_MSG) && (rndisHeader->MessageLength > sizeof(RNDIS_MESSAGE)))
542 {
543 DPRINT_ERR(NETVSC, "incoming rndis message buffer overflow detected (got %u, max %u)...marking it an error!",
544 rndisHeader->MessageLength, sizeof(RNDIS_MESSAGE));
545 }
546
547 memcpy(&rndisMessage, rndisHeader, (rndisHeader->MessageLength > sizeof(RNDIS_MESSAGE))?sizeof(RNDIS_MESSAGE):rndisHeader->MessageLength);
548
549 PageUnmapVirtualAddress((void*)(ULONG_PTR)rndisHeader - Packet->PageBuffers[0].Offset);
550
551 DumpRndisMessage(&rndisMessage);
552
553 switch (rndisMessage.NdisMessageType)
554 {
555 // data msg
556 case REMOTE_NDIS_PACKET_MSG:
557 RndisFilterReceiveData(rndisDevice, &rndisMessage, Packet);
558 break;
559
560 // completion msgs
561 case REMOTE_NDIS_INITIALIZE_CMPLT:
562 case REMOTE_NDIS_QUERY_CMPLT:
563 case REMOTE_NDIS_SET_CMPLT:
564 //case REMOTE_NDIS_RESET_CMPLT:
565 //case REMOTE_NDIS_KEEPALIVE_CMPLT:
566 RndisFilterReceiveResponse(rndisDevice, &rndisMessage);
567 break;
568
569 // notification msgs
570 case REMOTE_NDIS_INDICATE_STATUS_MSG:
571 RndisFilterReceiveIndicateStatus(rndisDevice, &rndisMessage);
572 break;
573 default:
574 DPRINT_ERR(NETVSC, "unhandled rndis message (type %u len %u)", rndisMessage.NdisMessageType, rndisMessage.MessageLength);
575 break;
576 }
577
578 DPRINT_EXIT(NETVSC);
579 return 0;
580}
581
582
583static int
584RndisFilterQueryDevice(
585 RNDIS_DEVICE *Device,
586 UINT32 Oid,
587 VOID *Result,
588 UINT32 *ResultSize
589 )
590{
591 RNDIS_REQUEST *request;
592 UINT32 inresultSize = *ResultSize;
593 RNDIS_QUERY_REQUEST *query;
594 RNDIS_QUERY_COMPLETE *queryComplete;
595 int ret=0;
596
597 DPRINT_ENTER(NETVSC);
598
599 ASSERT(Result);
600
601 *ResultSize = 0;
602 request = GetRndisRequest(Device, REMOTE_NDIS_QUERY_MSG, RNDIS_MESSAGE_SIZE(RNDIS_QUERY_REQUEST));
603 if (!request)
604 {
605 ret = -1;
606 goto Cleanup;
607 }
608
609 // Setup the rndis query
610 query = &request->RequestMessage.Message.QueryRequest;
611 query->Oid = Oid;
612 query->InformationBufferOffset = sizeof(RNDIS_QUERY_REQUEST);
613 query->InformationBufferLength = 0;
614 query->DeviceVcHandle = 0;
615
616 ret = RndisFilterSendRequest(Device, request);
617 if (ret != 0)
618 {
619 goto Cleanup;
620 }
621
622 WaitEventWait(request->WaitEvent);
623
624 // Copy the response back
625 queryComplete = &request->ResponseMessage.Message.QueryComplete;
626
627 if (queryComplete->InformationBufferLength > inresultSize)
628 {
629 ret = -1;
630 goto Cleanup;
631 }
632
633 memcpy(Result,
634 (void*)((ULONG_PTR)queryComplete + queryComplete->InformationBufferOffset),
635 queryComplete->InformationBufferLength);
636
637 *ResultSize = queryComplete->InformationBufferLength;
638
639Cleanup:
640 if (request)
641 {
642 PutRndisRequest(Device, request);
643 }
644 DPRINT_EXIT(NETVSC);
645
646 return ret;
647}
648
649static inline int
650RndisFilterQueryDeviceMac(
651 RNDIS_DEVICE *Device
652 )
653{
654 UINT32 size=HW_MACADDR_LEN;
655
656 return RndisFilterQueryDevice(Device,
657 RNDIS_OID_802_3_PERMANENT_ADDRESS,
658 Device->HwMacAddr,
659 &size);
660}
661
662static inline int
663RndisFilterQueryDeviceLinkStatus(
664 RNDIS_DEVICE *Device
665 )
666{
667 UINT32 size=sizeof(UINT32);
668
669 return RndisFilterQueryDevice(Device,
670 RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
671 &Device->LinkStatus,
672 &size);
673}
674
675static int
676RndisFilterSetPacketFilter(
677 RNDIS_DEVICE *Device,
678 UINT32 NewFilter
679 )
680{
681 RNDIS_REQUEST *request;
682 RNDIS_SET_REQUEST *set;
683 RNDIS_SET_COMPLETE *setComplete;
684 UINT32 status;
685 int ret;
686
687 DPRINT_ENTER(NETVSC);
688
689 ASSERT(RNDIS_MESSAGE_SIZE(RNDIS_SET_REQUEST) + sizeof(UINT32) <= sizeof(RNDIS_MESSAGE));
690
691 request = GetRndisRequest(Device, REMOTE_NDIS_SET_MSG, RNDIS_MESSAGE_SIZE(RNDIS_SET_REQUEST) + sizeof(UINT32));
692 if (!request)
693 {
694 ret = -1;
695 goto Cleanup;
696 }
697
698 // Setup the rndis set
699 set = &request->RequestMessage.Message.SetRequest;
700 set->Oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
701 set->InformationBufferLength = sizeof(UINT32);
702 set->InformationBufferOffset = sizeof(RNDIS_SET_REQUEST);
703
704 memcpy((void*)(ULONG_PTR)set + sizeof(RNDIS_SET_REQUEST), &NewFilter, sizeof(UINT32));
705
706 ret = RndisFilterSendRequest(Device, request);
707 if (ret != 0)
708 {
709 goto Cleanup;
710 }
711
712 ret = WaitEventWaitEx(request->WaitEvent, 2000/*2sec*/);
713 if (!ret)
714 {
715 ret = -1;
716 DPRINT_ERR(NETVSC, "timeout before we got a set response...");
717 // We cant deallocate the request since we may still receive a send completion for it.
718 goto Exit;
719 }
720 else
721 {
722 if (ret > 0)
723 {
724 ret = 0;
725 }
726 setComplete = &request->ResponseMessage.Message.SetComplete;
727 status = setComplete->Status;
728 }
729
730Cleanup:
731 if (request)
732 {
733 PutRndisRequest(Device, request);
734 }
735Exit:
736 DPRINT_EXIT(NETVSC);
737
738 return ret;
739}
740
741int
742RndisFilterInit(
743 NETVSC_DRIVER_OBJECT *Driver
744 )
745{
746 DPRINT_ENTER(NETVSC);
747
748 DPRINT_DBG(NETVSC, "sizeof(RNDIS_FILTER_PACKET) == %d", sizeof(RNDIS_FILTER_PACKET));
749
750 Driver->RequestExtSize = sizeof(RNDIS_FILTER_PACKET);
751 Driver->AdditionalRequestPageBufferCount = 1; // For rndis header
752
753 //Driver->Context = rndisDriver;
754
755 memset(&gRndisFilter, 0, sizeof(RNDIS_FILTER_DRIVER_OBJECT));
756
757 /*rndisDriver->Driver = Driver;
758
759 ASSERT(Driver->OnLinkStatusChanged);
760 rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/
761
762 // Save the original dispatch handlers before we override it
763 gRndisFilter.InnerDriver.Base.OnDeviceAdd = Driver->Base.OnDeviceAdd;
764 gRndisFilter.InnerDriver.Base.OnDeviceRemove = Driver->Base.OnDeviceRemove;
765 gRndisFilter.InnerDriver.Base.OnCleanup = Driver->Base.OnCleanup;
766
767 ASSERT(Driver->OnSend);
768 ASSERT(Driver->OnReceiveCallback);
769 gRndisFilter.InnerDriver.OnSend = Driver->OnSend;
770 gRndisFilter.InnerDriver.OnReceiveCallback = Driver->OnReceiveCallback;
771 gRndisFilter.InnerDriver.OnLinkStatusChanged = Driver->OnLinkStatusChanged;
772
773 // Override
774 Driver->Base.OnDeviceAdd = RndisFilterOnDeviceAdd;
775 Driver->Base.OnDeviceRemove = RndisFilterOnDeviceRemove;
776 Driver->Base.OnCleanup = RndisFilterOnCleanup;
777 Driver->OnSend = RndisFilterOnSend;
778 Driver->OnOpen = RndisFilterOnOpen;
779 Driver->OnClose = RndisFilterOnClose;
780 //Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus;
781 Driver->OnReceiveCallback = RndisFilterOnReceive;
782
783 DPRINT_EXIT(NETVSC);
784
785 return 0;
786}
787
788static int
789RndisFilterInitDevice(
790 RNDIS_DEVICE *Device
791 )
792{
793 RNDIS_REQUEST *request;
794 RNDIS_INITIALIZE_REQUEST *init;
795 RNDIS_INITIALIZE_COMPLETE *initComplete;
796 UINT32 status;
797 int ret;
798
799 DPRINT_ENTER(NETVSC);
800
801 request = GetRndisRequest(Device, REMOTE_NDIS_INITIALIZE_MSG, RNDIS_MESSAGE_SIZE(RNDIS_INITIALIZE_REQUEST));
802 if (!request)
803 {
804 ret = -1;
805 goto Cleanup;
806 }
807
808 // Setup the rndis set
809 init = &request->RequestMessage.Message.InitializeRequest;
810 init->MajorVersion = RNDIS_MAJOR_VERSION;
811 init->MinorVersion = RNDIS_MINOR_VERSION;
812 init->MaxTransferSize = 2048; // FIXME: Use 1536 - rounded ethernet frame size
813
814 Device->State = RNDIS_DEV_INITIALIZING;
815
816 ret = RndisFilterSendRequest(Device, request);
817 if (ret != 0)
818 {
819 Device->State = RNDIS_DEV_UNINITIALIZED;
820 goto Cleanup;
821 }
822
823 WaitEventWait(request->WaitEvent);
824
825 initComplete = &request->ResponseMessage.Message.InitializeComplete;
826 status = initComplete->Status;
827 if (status == RNDIS_STATUS_SUCCESS)
828 {
829 Device->State = RNDIS_DEV_INITIALIZED;
830 ret = 0;
831 }
832 else
833 {
834 Device->State = RNDIS_DEV_UNINITIALIZED;
835 ret = -1;
836 }
837
838Cleanup:
839 if (request)
840 {
841 PutRndisRequest(Device, request);
842 }
843 DPRINT_EXIT(NETVSC);
844
845 return ret;
846}
847
848static void
849RndisFilterHaltDevice(
850 RNDIS_DEVICE *Device
851 )
852{
853 RNDIS_REQUEST *request;
854 RNDIS_HALT_REQUEST *halt;
855
856 DPRINT_ENTER(NETVSC);
857
858 // Attempt to do a rndis device halt
859 request = GetRndisRequest(Device, REMOTE_NDIS_HALT_MSG, RNDIS_MESSAGE_SIZE(RNDIS_HALT_REQUEST));
860 if (!request)
861 {
862 goto Cleanup;
863 }
864
865 // Setup the rndis set
866 halt = &request->RequestMessage.Message.HaltRequest;
867 halt->RequestId = InterlockedIncrement((int*)&Device->NewRequestId);
868
869 // Ignore return since this msg is optional.
870 RndisFilterSendRequest(Device, request);
871
872 Device->State = RNDIS_DEV_UNINITIALIZED;
873
874Cleanup:
875 if (request)
876 {
877 PutRndisRequest(Device, request);
878 }
879 DPRINT_EXIT(NETVSC);
880 return;
881}
882
883
884static int
885RndisFilterOpenDevice(
886 RNDIS_DEVICE *Device
887 )
888{
889 int ret=0;
890
891 DPRINT_ENTER(NETVSC);
892
893 if (Device->State != RNDIS_DEV_INITIALIZED)
894 return 0;
895
896 ret = RndisFilterSetPacketFilter(Device, NDIS_PACKET_TYPE_BROADCAST|NDIS_PACKET_TYPE_DIRECTED);
897 if (ret == 0)
898 {
899 Device->State = RNDIS_DEV_DATAINITIALIZED;
900 }
901
902 DPRINT_EXIT(NETVSC);
903 return ret;
904}
905
906static int
907RndisFilterCloseDevice(
908 RNDIS_DEVICE *Device
909 )
910{
911 int ret;
912
913 DPRINT_ENTER(NETVSC);
914
915 if (Device->State != RNDIS_DEV_DATAINITIALIZED)
916 return 0;
917
918 ret = RndisFilterSetPacketFilter(Device, 0);
919 if (ret == 0)
920 {
921 Device->State = RNDIS_DEV_INITIALIZED;
922 }
923
924 DPRINT_EXIT(NETVSC);
925
926 return ret;
927}
928
929
930int
931RndisFilterOnDeviceAdd(
932 DEVICE_OBJECT *Device,
933 void *AdditionalInfo
934 )
935{
936 int ret;
937 NETVSC_DEVICE *netDevice;
938 RNDIS_DEVICE *rndisDevice;
939 NETVSC_DEVICE_INFO *deviceInfo = (NETVSC_DEVICE_INFO*)AdditionalInfo;
940
941 DPRINT_ENTER(NETVSC);
942
943 //rndisDevice = MemAlloc(sizeof(RNDIS_DEVICE));
944 rndisDevice = GetRndisDevice();
945 if (!rndisDevice)
946 {
947 DPRINT_EXIT(NETVSC);
948 return -1;
949 }
950
951 DPRINT_DBG(NETVSC, "rndis device object allocated - %p", rndisDevice);
952
953 // Let the inner driver handle this first to create the netvsc channel
954 // NOTE! Once the channel is created, we may get a receive callback
955 // (RndisFilterOnReceive()) before this call is completed
956 ret = gRndisFilter.InnerDriver.Base.OnDeviceAdd(Device, AdditionalInfo);
957 if (ret != 0)
958 {
959 PutRndisDevice(rndisDevice);
960 DPRINT_EXIT(NETVSC);
961 return ret;
962 }
963
964 //
965 // Initialize the rndis device
966 //
967 netDevice = (NETVSC_DEVICE*)Device->Extension;
968 ASSERT(netDevice);
969 ASSERT(netDevice->Device);
970
971 netDevice->Extension = rndisDevice;
972 rndisDevice->NetDevice = netDevice;
973
974 // Send the rndis initialization message
975 ret = RndisFilterInitDevice(rndisDevice);
976 if (ret != 0)
977 {
978 // TODO: If rndis init failed, we will need to shut down the channel
979 }
980
981 // Get the mac address
982 ret = RndisFilterQueryDeviceMac(rndisDevice);
983 if (ret != 0)
984 {
985 // TODO: shutdown rndis device and the channel
986 }
987
988 DPRINT_INFO(NETVSC, "Device 0x%p mac addr %02x%02x%02x%02x%02x%02x",
989 rndisDevice,
990 rndisDevice->HwMacAddr[0],
991 rndisDevice->HwMacAddr[1],
992 rndisDevice->HwMacAddr[2],
993 rndisDevice->HwMacAddr[3],
994 rndisDevice->HwMacAddr[4],
995 rndisDevice->HwMacAddr[5]);
996
997 memcpy(deviceInfo->MacAddr, rndisDevice->HwMacAddr, HW_MACADDR_LEN);
998
999 RndisFilterQueryDeviceLinkStatus(rndisDevice);
1000
1001 deviceInfo->LinkState = rndisDevice->LinkStatus;
1002 DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice, ((deviceInfo->LinkState)?("down"):("up")));
1003
1004 DPRINT_EXIT(NETVSC);
1005
1006 return ret;
1007}
1008
1009
1010static int
1011RndisFilterOnDeviceRemove(
1012 DEVICE_OBJECT *Device
1013 )
1014{
1015 NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension;
1016 RNDIS_DEVICE *rndisDevice = (RNDIS_DEVICE*)netDevice->Extension;
1017
1018 DPRINT_ENTER(NETVSC);
1019
1020 // Halt and release the rndis device
1021 RndisFilterHaltDevice(rndisDevice);
1022
1023 PutRndisDevice(rndisDevice);
1024 netDevice->Extension = NULL;
1025
1026 // Pass control to inner driver to remove the device
1027 gRndisFilter.InnerDriver.Base.OnDeviceRemove(Device);
1028
1029 DPRINT_EXIT(NETVSC);
1030
1031 return 0;
1032}
1033
1034
1035static void
1036RndisFilterOnCleanup(
1037 DRIVER_OBJECT *Driver
1038 )
1039{
1040 DPRINT_ENTER(NETVSC);
1041
1042 DPRINT_EXIT(NETVSC);
1043}
1044
1045static int
1046RndisFilterOnOpen(
1047 DEVICE_OBJECT *Device
1048 )
1049{
1050 int ret;
1051 NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension;
1052
1053 DPRINT_ENTER(NETVSC);
1054
1055 ASSERT(netDevice);
1056 ret = RndisFilterOpenDevice((RNDIS_DEVICE*)netDevice->Extension);
1057
1058 DPRINT_EXIT(NETVSC);
1059
1060 return ret;
1061}
1062
1063static int
1064RndisFilterOnClose(
1065 DEVICE_OBJECT *Device
1066 )
1067{
1068 int ret;
1069 NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension;
1070
1071 DPRINT_ENTER(NETVSC);
1072
1073 ASSERT(netDevice);
1074 ret = RndisFilterCloseDevice((RNDIS_DEVICE*)netDevice->Extension);
1075
1076 DPRINT_EXIT(NETVSC);
1077
1078 return ret;
1079}
1080
1081
1082static int
1083RndisFilterOnSend(
1084 DEVICE_OBJECT *Device,
1085 NETVSC_PACKET *Packet
1086 )
1087{
1088 int ret=0;
1089 RNDIS_FILTER_PACKET *filterPacket;
1090 RNDIS_MESSAGE *rndisMessage;
1091 RNDIS_PACKET *rndisPacket;
1092 UINT32 rndisMessageSize;
1093
1094 DPRINT_ENTER(NETVSC);
1095
1096 // Add the rndis header
1097 filterPacket = (RNDIS_FILTER_PACKET*)Packet->Extension;
1098 ASSERT(filterPacket);
1099
1100 memset(filterPacket, 0, sizeof(RNDIS_FILTER_PACKET));
1101
1102 rndisMessage = &filterPacket->Message;
1103 rndisMessageSize = RNDIS_MESSAGE_SIZE(RNDIS_PACKET);
1104
1105 rndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG;
1106 rndisMessage->MessageLength = Packet->TotalDataBufferLength + rndisMessageSize;
1107
1108 rndisPacket = &rndisMessage->Message.Packet;
1109 rndisPacket->DataOffset = sizeof(RNDIS_PACKET);
1110 rndisPacket->DataLength = Packet->TotalDataBufferLength;
1111
1112 Packet->IsDataPacket = TRUE;
1113 Packet->PageBuffers[0].Pfn = GetPhysicalAddress(rndisMessage) >> PAGE_SHIFT;
1114 Packet->PageBuffers[0].Offset = (ULONG_PTR)rndisMessage & (PAGE_SIZE-1);
1115 Packet->PageBuffers[0].Length = rndisMessageSize;
1116
1117 // Save the packet send completion and context
1118 filterPacket->OnCompletion = Packet->Completion.Send.OnSendCompletion;
1119 filterPacket->CompletionContext = Packet->Completion.Send.SendCompletionContext;
1120
1121 // Use ours
1122 Packet->Completion.Send.OnSendCompletion = RndisFilterOnSendCompletion;
1123 Packet->Completion.Send.SendCompletionContext = filterPacket;
1124
1125 ret = gRndisFilter.InnerDriver.OnSend(Device, Packet);
1126 if (ret != 0)
1127 {
1128 // Reset the completion to originals to allow retries from above
1129 Packet->Completion.Send.OnSendCompletion = filterPacket->OnCompletion;
1130 Packet->Completion.Send.SendCompletionContext = filterPacket->CompletionContext;
1131 }
1132
1133 DPRINT_EXIT(NETVSC);
1134
1135 return ret;
1136}
1137
1138static void
1139RndisFilterOnSendCompletion(
1140 void *Context)
1141{
1142 RNDIS_FILTER_PACKET *filterPacket = (RNDIS_FILTER_PACKET *)Context;
1143
1144 DPRINT_ENTER(NETVSC);
1145
1146 // Pass it back to the original handler
1147 filterPacket->OnCompletion(filterPacket->CompletionContext);
1148
1149 DPRINT_EXIT(NETVSC);
1150}
1151
1152
1153static void
1154RndisFilterOnSendRequestCompletion(
1155 void *Context
1156 )
1157{
1158 DPRINT_ENTER(NETVSC);
1159
1160 // Noop
1161 DPRINT_EXIT(NETVSC);
1162}