2009-07-13 22:34:54 +00:00
/*
*
* Copyright ( c ) 2009 , Microsoft Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . , 59 Temple
* Place - Suite 330 , Boston , MA 02111 - 1307 USA .
*
* Authors :
* Haiyang Zhang < haiyangz @ microsoft . com >
* Hank Janssen < hjanssen @ microsoft . com >
*
*/
2009-07-14 22:08:20 +00:00
# include <linux/kernel.h>
2009-07-15 18:06:01 +00:00
# include <linux/mm.h>
2009-07-14 17:59:56 +00:00
# include "include/logging.h"
2009-07-13 22:34:54 +00:00
2009-07-14 17:59:56 +00:00
# include "include/NetVscApi.h"
2009-07-13 22:34:54 +00:00
# include "RndisFilter.h"
2009-07-27 20:47:24 +00:00
/* Data types */
2009-07-13 22:34:54 +00:00
typedef struct _RNDIS_FILTER_DRIVER_OBJECT {
2009-07-27 20:47:24 +00:00
/* The original driver */
2009-07-13 22:34:54 +00:00
NETVSC_DRIVER_OBJECT InnerDriver ;
} RNDIS_FILTER_DRIVER_OBJECT ;
typedef enum {
RNDIS_DEV_UNINITIALIZED = 0 ,
RNDIS_DEV_INITIALIZING ,
RNDIS_DEV_INITIALIZED ,
RNDIS_DEV_DATAINITIALIZED ,
} RNDIS_DEVICE_STATE ;
typedef struct _RNDIS_DEVICE {
NETVSC_DEVICE * NetDevice ;
RNDIS_DEVICE_STATE State ;
2009-07-14 22:09:36 +00:00
u32 LinkStatus ;
u32 NewRequestId ;
2009-07-13 22:34:54 +00:00
2009-07-15 21:55:29 +00:00
spinlock_t request_lock ;
2009-07-13 22:34:54 +00:00
LIST_ENTRY RequestList ;
2009-07-14 22:10:26 +00:00
unsigned char HwMacAddr [ HW_MACADDR_LEN ] ;
2009-07-13 22:34:54 +00:00
} RNDIS_DEVICE ;
typedef struct _RNDIS_REQUEST {
LIST_ENTRY ListEntry ;
HANDLE WaitEvent ;
2009-07-27 20:47:24 +00:00
/* FIXME: We assumed a fixed size response here. If we do ever need to handle a bigger response, */
/* we can either define a max response message or add a response buffer variable above this field */
2009-07-13 22:34:54 +00:00
RNDIS_MESSAGE ResponseMessage ;
2009-07-27 20:47:24 +00:00
/* Simplify allocation by having a netvsc packet inline */
2009-07-13 22:34:54 +00:00
NETVSC_PACKET Packet ;
PAGE_BUFFER Buffer ;
2009-07-27 20:47:24 +00:00
/* FIXME: We assumed a fixed size request here. */
2009-07-13 22:34:54 +00:00
RNDIS_MESSAGE RequestMessage ;
} RNDIS_REQUEST ;
typedef struct _RNDIS_FILTER_PACKET {
void * CompletionContext ;
PFN_ON_SENDRECVCOMPLETION OnCompletion ;
RNDIS_MESSAGE Message ;
} RNDIS_FILTER_PACKET ;
2009-07-27 20:47:24 +00:00
/* Internal routines */
2009-07-13 22:34:54 +00:00
static int
RndisFilterSendRequest (
RNDIS_DEVICE * Device ,
RNDIS_REQUEST * Request
) ;
static void
RndisFilterReceiveResponse (
RNDIS_DEVICE * Device ,
RNDIS_MESSAGE * Response
) ;
static void
RndisFilterReceiveIndicateStatus (
RNDIS_DEVICE * Device ,
RNDIS_MESSAGE * Response
) ;
static void
RndisFilterReceiveData (
RNDIS_DEVICE * Device ,
RNDIS_MESSAGE * Message ,
NETVSC_PACKET * Packet
) ;
static int
RndisFilterOnReceive (
DEVICE_OBJECT * Device ,
NETVSC_PACKET * Packet
) ;
static int
RndisFilterQueryDevice (
RNDIS_DEVICE * Device ,
2009-07-14 22:09:36 +00:00
u32 Oid ,
2009-07-14 22:07:21 +00:00
void * Result ,
2009-07-14 22:09:36 +00:00
u32 * ResultSize
2009-07-13 22:34:54 +00:00
) ;
static inline int
RndisFilterQueryDeviceMac (
RNDIS_DEVICE * Device
) ;
static inline int
RndisFilterQueryDeviceLinkStatus (
RNDIS_DEVICE * Device
) ;
static int
RndisFilterSetPacketFilter (
RNDIS_DEVICE * Device ,
2009-07-14 22:09:36 +00:00
u32 NewFilter
2009-07-13 22:34:54 +00:00
) ;
static int
RndisFilterInitDevice (
RNDIS_DEVICE * Device
) ;
static int
RndisFilterOpenDevice (
RNDIS_DEVICE * Device
) ;
static int
RndisFilterCloseDevice (
RNDIS_DEVICE * Device
) ;
static int
RndisFilterOnDeviceAdd (
DEVICE_OBJECT * Device ,
void * AdditionalInfo
) ;
static int
RndisFilterOnDeviceRemove (
DEVICE_OBJECT * Device
) ;
static void
RndisFilterOnCleanup (
DRIVER_OBJECT * Driver
) ;
static int
RndisFilterOnOpen (
DEVICE_OBJECT * Device
) ;
static int
RndisFilterOnClose (
DEVICE_OBJECT * Device
) ;
static int
RndisFilterOnSend (
DEVICE_OBJECT * Device ,
NETVSC_PACKET * Packet
) ;
static void
RndisFilterOnSendCompletion (
void * Context
) ;
static void
RndisFilterOnSendRequestCompletion (
void * Context
) ;
2009-07-27 20:47:24 +00:00
/* Global var */
/* The one and only */
2009-07-13 22:34:54 +00:00
RNDIS_FILTER_DRIVER_OBJECT gRndisFilter ;
static inline RNDIS_DEVICE * GetRndisDevice ( void )
{
RNDIS_DEVICE * device ;
2009-07-15 19:47:43 +00:00
device = kzalloc ( sizeof ( RNDIS_DEVICE ) , GFP_KERNEL ) ;
2009-07-13 22:34:54 +00:00
if ( ! device )
{
return NULL ;
}
2009-07-15 21:55:29 +00:00
spin_lock_init ( & device - > request_lock ) ;
2009-07-13 22:34:54 +00:00
INITIALIZE_LIST_HEAD ( & device - > RequestList ) ;
device - > State = RNDIS_DEV_UNINITIALIZED ;
return device ;
}
static inline void PutRndisDevice ( RNDIS_DEVICE * Device )
{
2009-07-15 19:48:29 +00:00
kfree ( Device ) ;
2009-07-13 22:34:54 +00:00
}
2009-07-14 22:09:36 +00:00
static inline RNDIS_REQUEST * GetRndisRequest ( RNDIS_DEVICE * Device , u32 MessageType , u32 MessageLength )
2009-07-13 22:34:54 +00:00
{
RNDIS_REQUEST * request ;
RNDIS_MESSAGE * rndisMessage ;
RNDIS_SET_REQUEST * set ;
2009-07-15 21:55:29 +00:00
unsigned long flags ;
2009-07-13 22:34:54 +00:00
2009-07-15 19:47:43 +00:00
request = kzalloc ( sizeof ( RNDIS_REQUEST ) , GFP_KERNEL ) ;
2009-07-13 22:34:54 +00:00
if ( ! request )
{
return NULL ;
}
request - > WaitEvent = WaitEventCreate ( ) ;
if ( ! request - > WaitEvent )
{
2009-07-15 19:48:29 +00:00
kfree ( request ) ;
2009-07-13 22:34:54 +00:00
return NULL ;
}
rndisMessage = & request - > RequestMessage ;
rndisMessage - > NdisMessageType = MessageType ;
rndisMessage - > MessageLength = MessageLength ;
2009-07-27 20:47:24 +00:00
/* Set the request id. This field is always after the rndis header for request/response packet types so */
/* we just used the SetRequest as a template */
2009-07-13 22:34:54 +00:00
set = & rndisMessage - > Message . SetRequest ;
set - > RequestId = InterlockedIncrement ( ( int * ) & Device - > NewRequestId ) ;
2009-07-27 20:47:24 +00:00
/* Add to the request list */
2009-07-15 21:55:29 +00:00
spin_lock_irqsave ( & Device - > request_lock , flags ) ;
2009-07-13 22:34:54 +00:00
INSERT_TAIL_LIST ( & Device - > RequestList , & request - > ListEntry ) ;
2009-07-15 21:55:29 +00:00
spin_unlock_irqrestore ( & Device - > request_lock , flags ) ;
2009-07-13 22:34:54 +00:00
return request ;
}
static inline void PutRndisRequest ( RNDIS_DEVICE * Device , RNDIS_REQUEST * Request )
{
2009-07-15 21:55:29 +00:00
unsigned long flags ;
spin_lock_irqsave ( & Device - > request_lock , flags ) ;
2009-07-13 22:34:54 +00:00
REMOVE_ENTRY_LIST ( & Request - > ListEntry ) ;
2009-07-15 21:55:29 +00:00
spin_unlock_irqrestore ( & Device - > request_lock , flags ) ;
2009-07-13 22:34:54 +00:00
WaitEventClose ( Request - > WaitEvent ) ;
2009-07-15 19:48:29 +00:00
kfree ( Request ) ;
2009-07-13 22:34:54 +00:00
}
static inline void DumpRndisMessage ( RNDIS_MESSAGE * RndisMessage )
{
switch ( RndisMessage - > NdisMessageType )
{
case REMOTE_NDIS_PACKET_MSG :
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 " ,
RndisMessage - > MessageLength ,
RndisMessage - > Message . Packet . DataOffset ,
RndisMessage - > Message . Packet . DataLength ,
RndisMessage - > Message . Packet . NumOOBDataElements ,
RndisMessage - > Message . Packet . OOBDataOffset ,
RndisMessage - > Message . Packet . OOBDataLength ,
RndisMessage - > Message . Packet . PerPacketInfoOffset ,
RndisMessage - > Message . Packet . PerPacketInfoLength ) ;
break ;
case REMOTE_NDIS_INITIALIZE_CMPLT :
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) " ,
RndisMessage - > MessageLength ,
RndisMessage - > Message . InitializeComplete . RequestId ,
RndisMessage - > Message . InitializeComplete . Status ,
RndisMessage - > Message . InitializeComplete . MajorVersion ,
RndisMessage - > Message . InitializeComplete . MinorVersion ,
RndisMessage - > Message . InitializeComplete . DeviceFlags ,
RndisMessage - > Message . InitializeComplete . MaxTransferSize ,
RndisMessage - > Message . InitializeComplete . MaxPacketsPerMessage ,
RndisMessage - > Message . InitializeComplete . PacketAlignmentFactor ) ;
break ;
case REMOTE_NDIS_QUERY_CMPLT :
DPRINT_DBG ( NETVSC , " REMOTE_NDIS_QUERY_CMPLT (len %u, id 0x%x, status 0x%x, buf len %u, buf offset %u) " ,
RndisMessage - > MessageLength ,
RndisMessage - > Message . QueryComplete . RequestId ,
RndisMessage - > Message . QueryComplete . Status ,
RndisMessage - > Message . QueryComplete . InformationBufferLength ,
RndisMessage - > Message . QueryComplete . InformationBufferOffset ) ;
break ;
case REMOTE_NDIS_SET_CMPLT :
DPRINT_DBG ( NETVSC , " REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x) " ,
RndisMessage - > MessageLength ,
RndisMessage - > Message . SetComplete . RequestId ,
RndisMessage - > Message . SetComplete . Status ) ;
break ;
case REMOTE_NDIS_INDICATE_STATUS_MSG :
DPRINT_DBG ( NETVSC , " REMOTE_NDIS_INDICATE_STATUS_MSG (len %u, status 0x%x, buf len %u, buf offset %u) " ,
RndisMessage - > MessageLength ,
RndisMessage - > Message . IndicateStatus . Status ,
RndisMessage - > Message . IndicateStatus . StatusBufferLength ,
RndisMessage - > Message . IndicateStatus . StatusBufferOffset ) ;
break ;
default :
DPRINT_DBG ( NETVSC , " 0x%x (len %u) " ,
RndisMessage - > NdisMessageType ,
RndisMessage - > MessageLength ) ;
break ;
}
}
static int
RndisFilterSendRequest (
RNDIS_DEVICE * Device ,
RNDIS_REQUEST * Request
)
{
int ret = 0 ;
NETVSC_PACKET * packet ;
DPRINT_ENTER ( NETVSC ) ;
2009-07-27 20:47:24 +00:00
/* Setup the packet to send it */
2009-07-13 22:34:54 +00:00
packet = & Request - > Packet ;
2009-07-15 19:46:44 +00:00
packet - > IsDataPacket = false ;
2009-07-13 22:34:54 +00:00
packet - > TotalDataBufferLength = Request - > RequestMessage . MessageLength ;
packet - > PageBufferCount = 1 ;
packet - > PageBuffers [ 0 ] . Pfn = GetPhysicalAddress ( & Request - > RequestMessage ) > > PAGE_SHIFT ;
packet - > PageBuffers [ 0 ] . Length = Request - > RequestMessage . MessageLength ;
2009-07-14 22:12:46 +00:00
packet - > PageBuffers [ 0 ] . Offset = ( unsigned long ) & Request - > RequestMessage & ( PAGE_SIZE - 1 ) ;
2009-07-13 22:34:54 +00:00
2009-07-27 20:47:24 +00:00
packet - > Completion . Send . SendCompletionContext = Request ; /* packet; */
2009-07-13 22:34:54 +00:00
packet - > Completion . Send . OnSendCompletion = RndisFilterOnSendRequestCompletion ;
2009-07-14 22:12:46 +00:00
packet - > Completion . Send . SendCompletionTid = ( unsigned long ) Device ;
2009-07-13 22:34:54 +00:00
ret = gRndisFilter . InnerDriver . OnSend ( Device - > NetDevice - > Device , packet ) ;
DPRINT_EXIT ( NETVSC ) ;
return ret ;
}
static void
RndisFilterReceiveResponse (
RNDIS_DEVICE * Device ,
RNDIS_MESSAGE * Response
)
{
LIST_ENTRY * anchor ;
LIST_ENTRY * curr ;
RNDIS_REQUEST * request = NULL ;
2009-07-15 19:46:44 +00:00
bool found = false ;
2009-07-15 21:55:29 +00:00
unsigned long flags ;
2009-07-13 22:34:54 +00:00
DPRINT_ENTER ( NETVSC ) ;
2009-07-15 21:55:29 +00:00
spin_lock_irqsave ( & Device - > request_lock , flags ) ;
2009-07-13 22:34:54 +00:00
ITERATE_LIST_ENTRIES ( anchor , curr , & Device - > RequestList )
{
request = CONTAINING_RECORD ( curr , RNDIS_REQUEST , ListEntry ) ;
2009-07-27 20:47:24 +00:00
/* All request/response message contains RequestId as the 1st field */
2009-07-13 22:34:54 +00:00
if ( request - > RequestMessage . Message . InitializeRequest . RequestId = = Response - > Message . InitializeComplete . RequestId )
{
DPRINT_DBG ( NETVSC , " found rndis request for this response (id 0x%x req type 0x%x res type 0x%x) " ,
request - > RequestMessage . Message . InitializeRequest . RequestId , request - > RequestMessage . NdisMessageType , Response - > NdisMessageType ) ;
2009-07-15 19:46:44 +00:00
found = true ;
2009-07-13 22:34:54 +00:00
break ;
}
}
2009-07-15 21:55:29 +00:00
spin_unlock_irqrestore ( & Device - > request_lock , flags ) ;
2009-07-13 22:34:54 +00:00
if ( found )
{
if ( Response - > MessageLength < = sizeof ( RNDIS_MESSAGE ) )
{
memcpy ( & request - > ResponseMessage , Response , Response - > MessageLength ) ;
}
else
{
DPRINT_ERR ( NETVSC , " rndis response buffer overflow detected (size %u max %u) " , Response - > MessageLength , sizeof ( RNDIS_FILTER_PACKET ) ) ;
2009-07-27 20:47:24 +00:00
if ( Response - > NdisMessageType = = REMOTE_NDIS_RESET_CMPLT ) /* does not have a request id field */
2009-07-13 22:34:54 +00:00
{
request - > ResponseMessage . Message . ResetComplete . Status = STATUS_BUFFER_OVERFLOW ;
}
else
{
request - > ResponseMessage . Message . InitializeComplete . Status = STATUS_BUFFER_OVERFLOW ;
}
}
WaitEventSet ( request - > WaitEvent ) ;
}
else
{
DPRINT_ERR ( NETVSC , " no rndis request found for this response (id 0x%x res type 0x%x) " ,
Response - > Message . InitializeComplete . RequestId , Response - > NdisMessageType ) ;
}
DPRINT_EXIT ( NETVSC ) ;
}
static void
RndisFilterReceiveIndicateStatus (
RNDIS_DEVICE * Device ,
RNDIS_MESSAGE * Response
)
{
RNDIS_INDICATE_STATUS * indicate = & Response - > Message . IndicateStatus ;
if ( indicate - > Status = = RNDIS_STATUS_MEDIA_CONNECT )
{
gRndisFilter . InnerDriver . OnLinkStatusChanged ( Device - > NetDevice - > Device , 1 ) ;
}
else if ( indicate - > Status = = RNDIS_STATUS_MEDIA_DISCONNECT )
{
gRndisFilter . InnerDriver . OnLinkStatusChanged ( Device - > NetDevice - > Device , 0 ) ;
}
else
{
2009-07-27 20:47:24 +00:00
/* TODO: */
2009-07-13 22:34:54 +00:00
}
}
static void
RndisFilterReceiveData (
RNDIS_DEVICE * Device ,
RNDIS_MESSAGE * Message ,
NETVSC_PACKET * Packet
)
{
RNDIS_PACKET * rndisPacket ;
2009-07-14 22:09:36 +00:00
u32 dataOffset ;
2009-07-13 22:34:54 +00:00
DPRINT_ENTER ( NETVSC ) ;
2009-07-27 20:47:24 +00:00
/* empty ethernet frame ?? */
2009-07-13 22:34:54 +00:00
ASSERT ( Packet - > PageBuffers [ 0 ] . Length > RNDIS_MESSAGE_SIZE ( RNDIS_PACKET ) ) ;
rndisPacket = & Message - > Message . Packet ;
2009-07-27 20:47:24 +00:00
/* FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this */
/* netvsc packet (ie TotalDataBufferLength != MessageLength) */
2009-07-13 22:34:54 +00:00
2009-07-27 20:47:24 +00:00
/* Remove the rndis header and pass it back up the stack */
2009-07-13 22:34:54 +00:00
dataOffset = RNDIS_HEADER_SIZE + rndisPacket - > DataOffset ;
Packet - > TotalDataBufferLength - = dataOffset ;
Packet - > PageBuffers [ 0 ] . Offset + = dataOffset ;
Packet - > PageBuffers [ 0 ] . Length - = dataOffset ;
2009-07-15 19:46:44 +00:00
Packet - > IsDataPacket = true ;
2009-07-13 22:34:54 +00:00
gRndisFilter . InnerDriver . OnReceiveCallback ( Device - > NetDevice - > Device , Packet ) ;
DPRINT_EXIT ( NETVSC ) ;
}
static int
RndisFilterOnReceive (
DEVICE_OBJECT * Device ,
NETVSC_PACKET * Packet
)
{
NETVSC_DEVICE * netDevice = ( NETVSC_DEVICE * ) Device - > Extension ;
RNDIS_DEVICE * rndisDevice ;
RNDIS_MESSAGE rndisMessage ;
RNDIS_MESSAGE * rndisHeader ;
DPRINT_ENTER ( NETVSC ) ;
ASSERT ( netDevice ) ;
2009-07-27 20:47:24 +00:00
/* Make sure the rndis device state is initialized */
2009-07-13 22:34:54 +00:00
if ( ! netDevice - > Extension )
{
DPRINT_ERR ( NETVSC , " got rndis message but no rndis device...dropping this message! " ) ;
DPRINT_EXIT ( NETVSC ) ;
return - 1 ;
}
rndisDevice = ( RNDIS_DEVICE * ) netDevice - > Extension ;
if ( rndisDevice - > State = = RNDIS_DEV_UNINITIALIZED )
{
DPRINT_ERR ( NETVSC , " got rndis message but rndis device uninitialized...dropping this message! " ) ;
DPRINT_EXIT ( NETVSC ) ;
return - 1 ;
}
rndisHeader = ( RNDIS_MESSAGE * ) PageMapVirtualAddress ( Packet - > PageBuffers [ 0 ] . Pfn ) ;
2009-07-14 22:12:46 +00:00
rndisHeader = ( void * ) ( ( unsigned long ) rndisHeader + Packet - > PageBuffers [ 0 ] . Offset ) ;
2009-07-13 22:34:54 +00:00
2009-07-27 20:47:24 +00:00
/* Make sure we got a valid rndis message */
/* FIXME: There seems to be a bug in set completion msg where its MessageLength is 16 bytes but */
/* the ByteCount field in the xfer page range shows 52 bytes */
2009-07-13 22:34:54 +00:00
#if 0
if ( Packet - > TotalDataBufferLength ! = rndisHeader - > MessageLength )
{
2009-07-14 22:12:46 +00:00
PageUnmapVirtualAddress ( ( void * ) ( unsigned long ) rndisHeader - Packet - > PageBuffers [ 0 ] . Offset ) ;
2009-07-13 22:34:54 +00:00
DPRINT_ERR ( NETVSC , " invalid rndis message? (expected %u bytes got %u)...dropping this message! " ,
rndisHeader - > MessageLength , Packet - > TotalDataBufferLength ) ;
DPRINT_EXIT ( NETVSC ) ;
return - 1 ;
}
# endif
if ( ( rndisHeader - > NdisMessageType ! = REMOTE_NDIS_PACKET_MSG ) & & ( rndisHeader - > MessageLength > sizeof ( RNDIS_MESSAGE ) ) )
{
DPRINT_ERR ( NETVSC , " incoming rndis message buffer overflow detected (got %u, max %u)...marking it an error! " ,
rndisHeader - > MessageLength , sizeof ( RNDIS_MESSAGE ) ) ;
}
memcpy ( & rndisMessage , rndisHeader , ( rndisHeader - > MessageLength > sizeof ( RNDIS_MESSAGE ) ) ? sizeof ( RNDIS_MESSAGE ) : rndisHeader - > MessageLength ) ;
2009-07-14 22:12:46 +00:00
PageUnmapVirtualAddress ( ( void * ) ( unsigned long ) rndisHeader - Packet - > PageBuffers [ 0 ] . Offset ) ;
2009-07-13 22:34:54 +00:00
DumpRndisMessage ( & rndisMessage ) ;
switch ( rndisMessage . NdisMessageType )
{
2009-07-27 20:47:24 +00:00
/* data msg */
2009-07-13 22:34:54 +00:00
case REMOTE_NDIS_PACKET_MSG :
RndisFilterReceiveData ( rndisDevice , & rndisMessage , Packet ) ;
break ;
2009-07-27 20:47:24 +00:00
/* completion msgs */
2009-07-13 22:34:54 +00:00
case REMOTE_NDIS_INITIALIZE_CMPLT :
case REMOTE_NDIS_QUERY_CMPLT :
case REMOTE_NDIS_SET_CMPLT :
2009-07-27 20:47:24 +00:00
/* case REMOTE_NDIS_RESET_CMPLT: */
/* case REMOTE_NDIS_KEEPALIVE_CMPLT: */
2009-07-13 22:34:54 +00:00
RndisFilterReceiveResponse ( rndisDevice , & rndisMessage ) ;
break ;
2009-07-27 20:47:24 +00:00
/* notification msgs */
2009-07-13 22:34:54 +00:00
case REMOTE_NDIS_INDICATE_STATUS_MSG :
RndisFilterReceiveIndicateStatus ( rndisDevice , & rndisMessage ) ;
break ;
default :
DPRINT_ERR ( NETVSC , " unhandled rndis message (type %u len %u) " , rndisMessage . NdisMessageType , rndisMessage . MessageLength ) ;
break ;
}
DPRINT_EXIT ( NETVSC ) ;
return 0 ;
}
static int
RndisFilterQueryDevice (
RNDIS_DEVICE * Device ,
2009-07-14 22:09:36 +00:00
u32 Oid ,
2009-07-14 22:07:21 +00:00
void * Result ,
2009-07-14 22:09:36 +00:00
u32 * ResultSize
2009-07-13 22:34:54 +00:00
)
{
RNDIS_REQUEST * request ;
2009-07-14 22:09:36 +00:00
u32 inresultSize = * ResultSize ;
2009-07-13 22:34:54 +00:00
RNDIS_QUERY_REQUEST * query ;
RNDIS_QUERY_COMPLETE * queryComplete ;
int ret = 0 ;
DPRINT_ENTER ( NETVSC ) ;
ASSERT ( Result ) ;
* ResultSize = 0 ;
request = GetRndisRequest ( Device , REMOTE_NDIS_QUERY_MSG , RNDIS_MESSAGE_SIZE ( RNDIS_QUERY_REQUEST ) ) ;
if ( ! request )
{
ret = - 1 ;
goto Cleanup ;
}
2009-07-27 20:47:24 +00:00
/* Setup the rndis query */
2009-07-13 22:34:54 +00:00
query = & request - > RequestMessage . Message . QueryRequest ;
query - > Oid = Oid ;
query - > InformationBufferOffset = sizeof ( RNDIS_QUERY_REQUEST ) ;
query - > InformationBufferLength = 0 ;
query - > DeviceVcHandle = 0 ;
ret = RndisFilterSendRequest ( Device , request ) ;
if ( ret ! = 0 )
{
goto Cleanup ;
}
WaitEventWait ( request - > WaitEvent ) ;
2009-07-27 20:47:24 +00:00
/* Copy the response back */
2009-07-13 22:34:54 +00:00
queryComplete = & request - > ResponseMessage . Message . QueryComplete ;
if ( queryComplete - > InformationBufferLength > inresultSize )
{
ret = - 1 ;
goto Cleanup ;
}
memcpy ( Result ,
2009-07-14 22:12:46 +00:00
( void * ) ( ( unsigned long ) queryComplete + queryComplete - > InformationBufferOffset ) ,
2009-07-13 22:34:54 +00:00
queryComplete - > InformationBufferLength ) ;
* ResultSize = queryComplete - > InformationBufferLength ;
Cleanup :
if ( request )
{
PutRndisRequest ( Device , request ) ;
}
DPRINT_EXIT ( NETVSC ) ;
return ret ;
}
static inline int
RndisFilterQueryDeviceMac (
RNDIS_DEVICE * Device
)
{
2009-07-14 22:09:36 +00:00
u32 size = HW_MACADDR_LEN ;
2009-07-13 22:34:54 +00:00
return RndisFilterQueryDevice ( Device ,
RNDIS_OID_802_3_PERMANENT_ADDRESS ,
Device - > HwMacAddr ,
& size ) ;
}
static inline int
RndisFilterQueryDeviceLinkStatus (
RNDIS_DEVICE * Device
)
{
2009-07-14 22:09:36 +00:00
u32 size = sizeof ( u32 ) ;
2009-07-13 22:34:54 +00:00
return RndisFilterQueryDevice ( Device ,
RNDIS_OID_GEN_MEDIA_CONNECT_STATUS ,
& Device - > LinkStatus ,
& size ) ;
}
static int
RndisFilterSetPacketFilter (
RNDIS_DEVICE * Device ,
2009-07-14 22:09:36 +00:00
u32 NewFilter
2009-07-13 22:34:54 +00:00
)
{
RNDIS_REQUEST * request ;
RNDIS_SET_REQUEST * set ;
RNDIS_SET_COMPLETE * setComplete ;
2009-07-14 22:09:36 +00:00
u32 status ;
2009-07-13 22:34:54 +00:00
int ret ;
DPRINT_ENTER ( NETVSC ) ;
2009-07-14 22:09:36 +00:00
ASSERT ( RNDIS_MESSAGE_SIZE ( RNDIS_SET_REQUEST ) + sizeof ( u32 ) < = sizeof ( RNDIS_MESSAGE ) ) ;
2009-07-13 22:34:54 +00:00
2009-07-14 22:09:36 +00:00
request = GetRndisRequest ( Device , REMOTE_NDIS_SET_MSG , RNDIS_MESSAGE_SIZE ( RNDIS_SET_REQUEST ) + sizeof ( u32 ) ) ;
2009-07-13 22:34:54 +00:00
if ( ! request )
{
ret = - 1 ;
goto Cleanup ;
}
2009-07-27 20:47:24 +00:00
/* Setup the rndis set */
2009-07-13 22:34:54 +00:00
set = & request - > RequestMessage . Message . SetRequest ;
set - > Oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER ;
2009-07-14 22:09:36 +00:00
set - > InformationBufferLength = sizeof ( u32 ) ;
2009-07-13 22:34:54 +00:00
set - > InformationBufferOffset = sizeof ( RNDIS_SET_REQUEST ) ;
2009-07-14 22:12:46 +00:00
memcpy ( ( void * ) ( unsigned long ) set + sizeof ( RNDIS_SET_REQUEST ) , & NewFilter , sizeof ( u32 ) ) ;
2009-07-13 22:34:54 +00:00
ret = RndisFilterSendRequest ( Device , request ) ;
if ( ret ! = 0 )
{
goto Cleanup ;
}
ret = WaitEventWaitEx ( request - > WaitEvent , 2000 /*2sec*/ ) ;
if ( ! ret )
{
ret = - 1 ;
DPRINT_ERR ( NETVSC , " timeout before we got a set response... " ) ;
2009-07-27 20:47:24 +00:00
/* We cant deallocate the request since we may still receive a send completion for it. */
2009-07-13 22:34:54 +00:00
goto Exit ;
}
else
{
if ( ret > 0 )
{
ret = 0 ;
}
setComplete = & request - > ResponseMessage . Message . SetComplete ;
status = setComplete - > Status ;
}
Cleanup :
if ( request )
{
PutRndisRequest ( Device , request ) ;
}
Exit :
DPRINT_EXIT ( NETVSC ) ;
return ret ;
}
int
RndisFilterInit (
NETVSC_DRIVER_OBJECT * Driver
)
{
DPRINT_ENTER ( NETVSC ) ;
DPRINT_DBG ( NETVSC , " sizeof(RNDIS_FILTER_PACKET) == %d " , sizeof ( RNDIS_FILTER_PACKET ) ) ;
Driver - > RequestExtSize = sizeof ( RNDIS_FILTER_PACKET ) ;
2009-07-27 20:47:24 +00:00
Driver - > AdditionalRequestPageBufferCount = 1 ; /* For rndis header */
2009-07-13 22:34:54 +00:00
2009-07-27 20:47:24 +00:00
/* Driver->Context = rndisDriver; */
2009-07-13 22:34:54 +00:00
memset ( & gRndisFilter , 0 , sizeof ( RNDIS_FILTER_DRIVER_OBJECT ) ) ;
/*rndisDriver->Driver = Driver;
ASSERT ( Driver - > OnLinkStatusChanged ) ;
rndisDriver - > OnLinkStatusChanged = Driver - > OnLinkStatusChanged ; */
2009-07-27 20:47:24 +00:00
/* Save the original dispatch handlers before we override it */
2009-07-13 22:34:54 +00:00
gRndisFilter . InnerDriver . Base . OnDeviceAdd = Driver - > Base . OnDeviceAdd ;
gRndisFilter . InnerDriver . Base . OnDeviceRemove = Driver - > Base . OnDeviceRemove ;
gRndisFilter . InnerDriver . Base . OnCleanup = Driver - > Base . OnCleanup ;
ASSERT ( Driver - > OnSend ) ;
ASSERT ( Driver - > OnReceiveCallback ) ;
gRndisFilter . InnerDriver . OnSend = Driver - > OnSend ;
gRndisFilter . InnerDriver . OnReceiveCallback = Driver - > OnReceiveCallback ;
gRndisFilter . InnerDriver . OnLinkStatusChanged = Driver - > OnLinkStatusChanged ;
2009-07-27 20:47:24 +00:00
/* Override */
2009-07-13 22:34:54 +00:00
Driver - > Base . OnDeviceAdd = RndisFilterOnDeviceAdd ;
Driver - > Base . OnDeviceRemove = RndisFilterOnDeviceRemove ;
Driver - > Base . OnCleanup = RndisFilterOnCleanup ;
Driver - > OnSend = RndisFilterOnSend ;
Driver - > OnOpen = RndisFilterOnOpen ;
Driver - > OnClose = RndisFilterOnClose ;
2009-07-27 20:47:24 +00:00
/* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */
2009-07-13 22:34:54 +00:00
Driver - > OnReceiveCallback = RndisFilterOnReceive ;
DPRINT_EXIT ( NETVSC ) ;
return 0 ;
}
static int
RndisFilterInitDevice (
RNDIS_DEVICE * Device
)
{
RNDIS_REQUEST * request ;
RNDIS_INITIALIZE_REQUEST * init ;
RNDIS_INITIALIZE_COMPLETE * initComplete ;
2009-07-14 22:09:36 +00:00
u32 status ;
2009-07-13 22:34:54 +00:00
int ret ;
DPRINT_ENTER ( NETVSC ) ;
request = GetRndisRequest ( Device , REMOTE_NDIS_INITIALIZE_MSG , RNDIS_MESSAGE_SIZE ( RNDIS_INITIALIZE_REQUEST ) ) ;
if ( ! request )
{
ret = - 1 ;
goto Cleanup ;
}
2009-07-27 20:47:24 +00:00
/* Setup the rndis set */
2009-07-13 22:34:54 +00:00
init = & request - > RequestMessage . Message . InitializeRequest ;
init - > MajorVersion = RNDIS_MAJOR_VERSION ;
init - > MinorVersion = RNDIS_MINOR_VERSION ;
2009-07-27 20:47:24 +00:00
init - > MaxTransferSize = 2048 ; /* FIXME: Use 1536 - rounded ethernet frame size */
2009-07-13 22:34:54 +00:00
Device - > State = RNDIS_DEV_INITIALIZING ;
ret = RndisFilterSendRequest ( Device , request ) ;
if ( ret ! = 0 )
{
Device - > State = RNDIS_DEV_UNINITIALIZED ;
goto Cleanup ;
}
WaitEventWait ( request - > WaitEvent ) ;
initComplete = & request - > ResponseMessage . Message . InitializeComplete ;
status = initComplete - > Status ;
if ( status = = RNDIS_STATUS_SUCCESS )
{
Device - > State = RNDIS_DEV_INITIALIZED ;
ret = 0 ;
}
else
{
Device - > State = RNDIS_DEV_UNINITIALIZED ;
ret = - 1 ;
}
Cleanup :
if ( request )
{
PutRndisRequest ( Device , request ) ;
}
DPRINT_EXIT ( NETVSC ) ;
return ret ;
}
static void
RndisFilterHaltDevice (
RNDIS_DEVICE * Device
)
{
RNDIS_REQUEST * request ;
RNDIS_HALT_REQUEST * halt ;
DPRINT_ENTER ( NETVSC ) ;
2009-07-27 20:47:24 +00:00
/* Attempt to do a rndis device halt */
2009-07-13 22:34:54 +00:00
request = GetRndisRequest ( Device , REMOTE_NDIS_HALT_MSG , RNDIS_MESSAGE_SIZE ( RNDIS_HALT_REQUEST ) ) ;
if ( ! request )
{
goto Cleanup ;
}
2009-07-27 20:47:24 +00:00
/* Setup the rndis set */
2009-07-13 22:34:54 +00:00
halt = & request - > RequestMessage . Message . HaltRequest ;
halt - > RequestId = InterlockedIncrement ( ( int * ) & Device - > NewRequestId ) ;
2009-07-27 20:47:24 +00:00
/* Ignore return since this msg is optional. */
2009-07-13 22:34:54 +00:00
RndisFilterSendRequest ( Device , request ) ;
Device - > State = RNDIS_DEV_UNINITIALIZED ;
Cleanup :
if ( request )
{
PutRndisRequest ( Device , request ) ;
}
DPRINT_EXIT ( NETVSC ) ;
return ;
}
static int
RndisFilterOpenDevice (
RNDIS_DEVICE * Device
)
{
int ret = 0 ;
DPRINT_ENTER ( NETVSC ) ;
if ( Device - > State ! = RNDIS_DEV_INITIALIZED )
return 0 ;
ret = RndisFilterSetPacketFilter ( Device , NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED ) ;
if ( ret = = 0 )
{
Device - > State = RNDIS_DEV_DATAINITIALIZED ;
}
DPRINT_EXIT ( NETVSC ) ;
return ret ;
}
static int
RndisFilterCloseDevice (
RNDIS_DEVICE * Device
)
{
int ret ;
DPRINT_ENTER ( NETVSC ) ;
if ( Device - > State ! = RNDIS_DEV_DATAINITIALIZED )
return 0 ;
ret = RndisFilterSetPacketFilter ( Device , 0 ) ;
if ( ret = = 0 )
{
Device - > State = RNDIS_DEV_INITIALIZED ;
}
DPRINT_EXIT ( NETVSC ) ;
return ret ;
}
int
RndisFilterOnDeviceAdd (
DEVICE_OBJECT * Device ,
void * AdditionalInfo
)
{
int ret ;
NETVSC_DEVICE * netDevice ;
RNDIS_DEVICE * rndisDevice ;
NETVSC_DEVICE_INFO * deviceInfo = ( NETVSC_DEVICE_INFO * ) AdditionalInfo ;
DPRINT_ENTER ( NETVSC ) ;
rndisDevice = GetRndisDevice ( ) ;
if ( ! rndisDevice )
{
DPRINT_EXIT ( NETVSC ) ;
return - 1 ;
}
DPRINT_DBG ( NETVSC , " rndis device object allocated - %p " , rndisDevice ) ;
2009-07-27 20:47:24 +00:00
/* Let the inner driver handle this first to create the netvsc channel */
/* NOTE! Once the channel is created, we may get a receive callback */
/* (RndisFilterOnReceive()) before this call is completed */
2009-07-13 22:34:54 +00:00
ret = gRndisFilter . InnerDriver . Base . OnDeviceAdd ( Device , AdditionalInfo ) ;
if ( ret ! = 0 )
{
PutRndisDevice ( rndisDevice ) ;
DPRINT_EXIT ( NETVSC ) ;
return ret ;
}
2009-07-27 20:47:24 +00:00
/* Initialize the rndis device */
2009-07-13 22:34:54 +00:00
netDevice = ( NETVSC_DEVICE * ) Device - > Extension ;
ASSERT ( netDevice ) ;
ASSERT ( netDevice - > Device ) ;
netDevice - > Extension = rndisDevice ;
rndisDevice - > NetDevice = netDevice ;
2009-07-27 20:47:24 +00:00
/* Send the rndis initialization message */
2009-07-13 22:34:54 +00:00
ret = RndisFilterInitDevice ( rndisDevice ) ;
if ( ret ! = 0 )
{
2009-07-27 20:47:24 +00:00
/* TODO: If rndis init failed, we will need to shut down the channel */
2009-07-13 22:34:54 +00:00
}
2009-07-27 20:47:24 +00:00
/* Get the mac address */
2009-07-13 22:34:54 +00:00
ret = RndisFilterQueryDeviceMac ( rndisDevice ) ;
if ( ret ! = 0 )
{
2009-07-27 20:47:24 +00:00
/* TODO: shutdown rndis device and the channel */
2009-07-13 22:34:54 +00:00
}
DPRINT_INFO ( NETVSC , " Device 0x%p mac addr %02x%02x%02x%02x%02x%02x " ,
rndisDevice ,
rndisDevice - > HwMacAddr [ 0 ] ,
rndisDevice - > HwMacAddr [ 1 ] ,
rndisDevice - > HwMacAddr [ 2 ] ,
rndisDevice - > HwMacAddr [ 3 ] ,
rndisDevice - > HwMacAddr [ 4 ] ,
rndisDevice - > HwMacAddr [ 5 ] ) ;
memcpy ( deviceInfo - > MacAddr , rndisDevice - > HwMacAddr , HW_MACADDR_LEN ) ;
RndisFilterQueryDeviceLinkStatus ( rndisDevice ) ;
deviceInfo - > LinkState = rndisDevice - > LinkStatus ;
DPRINT_INFO ( NETVSC , " Device 0x%p link state %s " , rndisDevice , ( ( deviceInfo - > LinkState ) ? ( " down " ) : ( " up " ) ) ) ;
DPRINT_EXIT ( NETVSC ) ;
return ret ;
}
static int
RndisFilterOnDeviceRemove (
DEVICE_OBJECT * Device
)
{
NETVSC_DEVICE * netDevice = ( NETVSC_DEVICE * ) Device - > Extension ;
RNDIS_DEVICE * rndisDevice = ( RNDIS_DEVICE * ) netDevice - > Extension ;
DPRINT_ENTER ( NETVSC ) ;
2009-07-27 20:47:24 +00:00
/* Halt and release the rndis device */
2009-07-13 22:34:54 +00:00
RndisFilterHaltDevice ( rndisDevice ) ;
PutRndisDevice ( rndisDevice ) ;
netDevice - > Extension = NULL ;
2009-07-27 20:47:24 +00:00
/* Pass control to inner driver to remove the device */
2009-07-13 22:34:54 +00:00
gRndisFilter . InnerDriver . Base . OnDeviceRemove ( Device ) ;
DPRINT_EXIT ( NETVSC ) ;
return 0 ;
}
static void
RndisFilterOnCleanup (
DRIVER_OBJECT * Driver
)
{
DPRINT_ENTER ( NETVSC ) ;
DPRINT_EXIT ( NETVSC ) ;
}
static int
RndisFilterOnOpen (
DEVICE_OBJECT * Device
)
{
int ret ;
NETVSC_DEVICE * netDevice = ( NETVSC_DEVICE * ) Device - > Extension ;
DPRINT_ENTER ( NETVSC ) ;
ASSERT ( netDevice ) ;
ret = RndisFilterOpenDevice ( ( RNDIS_DEVICE * ) netDevice - > Extension ) ;
DPRINT_EXIT ( NETVSC ) ;
return ret ;
}
static int
RndisFilterOnClose (
DEVICE_OBJECT * Device
)
{
int ret ;
NETVSC_DEVICE * netDevice = ( NETVSC_DEVICE * ) Device - > Extension ;
DPRINT_ENTER ( NETVSC ) ;
ASSERT ( netDevice ) ;
ret = RndisFilterCloseDevice ( ( RNDIS_DEVICE * ) netDevice - > Extension ) ;
DPRINT_EXIT ( NETVSC ) ;
return ret ;
}
static int
RndisFilterOnSend (
DEVICE_OBJECT * Device ,
NETVSC_PACKET * Packet
)
{
int ret = 0 ;
RNDIS_FILTER_PACKET * filterPacket ;
RNDIS_MESSAGE * rndisMessage ;
RNDIS_PACKET * rndisPacket ;
2009-07-14 22:09:36 +00:00
u32 rndisMessageSize ;
2009-07-13 22:34:54 +00:00
DPRINT_ENTER ( NETVSC ) ;
2009-07-27 20:47:24 +00:00
/* Add the rndis header */
2009-07-13 22:34:54 +00:00
filterPacket = ( RNDIS_FILTER_PACKET * ) Packet - > Extension ;
ASSERT ( filterPacket ) ;
memset ( filterPacket , 0 , sizeof ( RNDIS_FILTER_PACKET ) ) ;
rndisMessage = & filterPacket - > Message ;
rndisMessageSize = RNDIS_MESSAGE_SIZE ( RNDIS_PACKET ) ;
rndisMessage - > NdisMessageType = REMOTE_NDIS_PACKET_MSG ;
rndisMessage - > MessageLength = Packet - > TotalDataBufferLength + rndisMessageSize ;
rndisPacket = & rndisMessage - > Message . Packet ;
rndisPacket - > DataOffset = sizeof ( RNDIS_PACKET ) ;
rndisPacket - > DataLength = Packet - > TotalDataBufferLength ;
2009-07-15 19:46:44 +00:00
Packet - > IsDataPacket = true ;
2009-07-13 22:34:54 +00:00
Packet - > PageBuffers [ 0 ] . Pfn = GetPhysicalAddress ( rndisMessage ) > > PAGE_SHIFT ;
2009-07-14 22:12:46 +00:00
Packet - > PageBuffers [ 0 ] . Offset = ( unsigned long ) rndisMessage & ( PAGE_SIZE - 1 ) ;
2009-07-13 22:34:54 +00:00
Packet - > PageBuffers [ 0 ] . Length = rndisMessageSize ;
2009-07-27 20:47:24 +00:00
/* Save the packet send completion and context */
2009-07-13 22:34:54 +00:00
filterPacket - > OnCompletion = Packet - > Completion . Send . OnSendCompletion ;
filterPacket - > CompletionContext = Packet - > Completion . Send . SendCompletionContext ;
2009-07-27 20:47:24 +00:00
/* Use ours */
2009-07-13 22:34:54 +00:00
Packet - > Completion . Send . OnSendCompletion = RndisFilterOnSendCompletion ;
Packet - > Completion . Send . SendCompletionContext = filterPacket ;
ret = gRndisFilter . InnerDriver . OnSend ( Device , Packet ) ;
if ( ret ! = 0 )
{
2009-07-27 20:47:24 +00:00
/* Reset the completion to originals to allow retries from above */
2009-07-13 22:34:54 +00:00
Packet - > Completion . Send . OnSendCompletion = filterPacket - > OnCompletion ;
Packet - > Completion . Send . SendCompletionContext = filterPacket - > CompletionContext ;
}
DPRINT_EXIT ( NETVSC ) ;
return ret ;
}
static void
RndisFilterOnSendCompletion (
void * Context )
{
RNDIS_FILTER_PACKET * filterPacket = ( RNDIS_FILTER_PACKET * ) Context ;
DPRINT_ENTER ( NETVSC ) ;
2009-07-27 20:47:24 +00:00
/* Pass it back to the original handler */
2009-07-13 22:34:54 +00:00
filterPacket - > OnCompletion ( filterPacket - > CompletionContext ) ;
DPRINT_EXIT ( NETVSC ) ;
}
static void
RndisFilterOnSendRequestCompletion (
void * Context
)
{
DPRINT_ENTER ( NETVSC ) ;
2009-07-27 20:47:24 +00:00
/* Noop */
2009-07-13 22:34:54 +00:00
DPRINT_EXIT ( NETVSC ) ;
}