From: Greg Kroah-Hartman Date: Thu, 6 May 2010 05:32:08 +0000 (-0700) Subject: Staging: hv: rename RndisFilter.c and .h to rndis_filter.c and .h X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=043efcc31e78f4e61b2b8bc321bc9a3c498bf4d1;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git Staging: hv: rename RndisFilter.c and .h to rndis_filter.c and .h Cc: Hank Janssen Cc: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile index cc75185e3b54..685a3200e04e 100644 --- a/drivers/staging/hv/Makefile +++ b/drivers/staging/hv/Makefile @@ -9,4 +9,4 @@ hv_vmbus-objs := vmbus_drv.o osd.o \ ChannelMgmt.o ChannelInterface.o ring_buffer.o hv_storvsc-objs := storvsc_drv.o storvsc.o hv_blkvsc-objs := blkvsc_drv.o blkvsc.o -hv_netvsc-objs := netvsc_drv.o netvsc.o RndisFilter.o +hv_netvsc-objs := netvsc_drv.o netvsc.o rndis_filter.o diff --git a/drivers/staging/hv/RndisFilter.c b/drivers/staging/hv/RndisFilter.c deleted file mode 100644 index 597c972f22c2..000000000000 --- a/drivers/staging/hv/RndisFilter.c +++ /dev/null @@ -1,997 +0,0 @@ -/* - * 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 - * Hank Janssen - */ -#include -#include -#include -#include -#include - -#include "osd.h" -#include "logging.h" -#include "NetVscApi.h" -#include "RndisFilter.h" - -/* Data types */ -struct rndis_filter_driver_object { - /* The original driver */ - struct netvsc_driver InnerDriver; -}; - -enum rndis_device_state { - RNDIS_DEV_UNINITIALIZED = 0, - RNDIS_DEV_INITIALIZING, - RNDIS_DEV_INITIALIZED, - RNDIS_DEV_DATAINITIALIZED, -}; - -struct rndis_device { - struct netvsc_device *NetDevice; - - enum rndis_device_state State; - u32 LinkStatus; - atomic_t NewRequestId; - - spinlock_t request_lock; - struct list_head RequestList; - - unsigned char HwMacAddr[ETH_ALEN]; -}; - -struct rndis_request { - struct list_head ListEntry; - struct osd_waitevent *WaitEvent; - - /* - * 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 - */ - struct rndis_message ResponseMessage; - - /* Simplify allocation by having a netvsc packet inline */ - struct hv_netvsc_packet Packet; - struct hv_page_buffer Buffer; - /* FIXME: We assumed a fixed size request here. */ - struct rndis_message RequestMessage; -}; - - -struct rndis_filter_packet { - void *CompletionContext; - void (*OnCompletion)(void *context); - struct rndis_message Message; -}; - - -static int RndisFilterOnDeviceAdd(struct hv_device *Device, - void *AdditionalInfo); - -static int RndisFilterOnDeviceRemove(struct hv_device *Device); - -static void RndisFilterOnCleanup(struct hv_driver *Driver); - -static int RndisFilterOnSend(struct hv_device *Device, - struct hv_netvsc_packet *Packet); - -static void RndisFilterOnSendCompletion(void *Context); - -static void RndisFilterOnSendRequestCompletion(void *Context); - - -/* The one and only */ -static struct rndis_filter_driver_object gRndisFilter; - -static struct rndis_device *GetRndisDevice(void) -{ - struct rndis_device *device; - - device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL); - if (!device) - return NULL; - - spin_lock_init(&device->request_lock); - - INIT_LIST_HEAD(&device->RequestList); - - device->State = RNDIS_DEV_UNINITIALIZED; - - return device; -} - -static struct rndis_request *GetRndisRequest(struct rndis_device *Device, - u32 MessageType, - u32 MessageLength) -{ - struct rndis_request *request; - struct rndis_message *rndisMessage; - struct rndis_set_request *set; - unsigned long flags; - - request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL); - if (!request) - return NULL; - - request->WaitEvent = osd_WaitEventCreate(); - if (!request->WaitEvent) { - kfree(request); - return NULL; - } - - rndisMessage = &request->RequestMessage; - rndisMessage->NdisMessageType = MessageType; - rndisMessage->MessageLength = MessageLength; - - /* - * 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 - */ - set = &rndisMessage->Message.SetRequest; - set->RequestId = atomic_inc_return(&Device->NewRequestId); - - /* Add to the request list */ - spin_lock_irqsave(&Device->request_lock, flags); - list_add_tail(&request->ListEntry, &Device->RequestList); - spin_unlock_irqrestore(&Device->request_lock, flags); - - return request; -} - -static void PutRndisRequest(struct rndis_device *Device, - struct rndis_request *Request) -{ - unsigned long flags; - - spin_lock_irqsave(&Device->request_lock, flags); - list_del(&Request->ListEntry); - spin_unlock_irqrestore(&Device->request_lock, flags); - - kfree(Request->WaitEvent); - kfree(Request); -} - -static void DumpRndisMessage(struct 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(struct rndis_device *Device, - struct rndis_request *Request) -{ - int ret; - struct hv_netvsc_packet *packet; - - DPRINT_ENTER(NETVSC); - - /* Setup the packet to send it */ - packet = &Request->Packet; - - packet->IsDataPacket = false; - packet->TotalDataBufferLength = Request->RequestMessage.MessageLength; - packet->PageBufferCount = 1; - - packet->PageBuffers[0].Pfn = virt_to_phys(&Request->RequestMessage) >> - PAGE_SHIFT; - packet->PageBuffers[0].Length = Request->RequestMessage.MessageLength; - packet->PageBuffers[0].Offset = - (unsigned long)&Request->RequestMessage & (PAGE_SIZE - 1); - - packet->Completion.Send.SendCompletionContext = Request;/* packet; */ - packet->Completion.Send.OnSendCompletion = - RndisFilterOnSendRequestCompletion; - packet->Completion.Send.SendCompletionTid = (unsigned long)Device; - - ret = gRndisFilter.InnerDriver.OnSend(Device->NetDevice->Device, packet); - DPRINT_EXIT(NETVSC); - return ret; -} - -static void RndisFilterReceiveResponse(struct rndis_device *Device, - struct rndis_message *Response) -{ - struct rndis_request *request = NULL; - bool found = false; - unsigned long flags; - - DPRINT_ENTER(NETVSC); - - spin_lock_irqsave(&Device->request_lock, flags); - list_for_each_entry(request, &Device->RequestList, ListEntry) { - /* - * All request/response message contains RequestId as the 1st - * field - */ - 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); - - found = true; - break; - } - } - spin_unlock_irqrestore(&Device->request_lock, flags); - - if (found) { - if (Response->MessageLength <= sizeof(struct rndis_message)) { - memcpy(&request->ResponseMessage, Response, - Response->MessageLength); - } else { - DPRINT_ERR(NETVSC, "rndis response buffer overflow " - "detected (size %u max %zu)", - Response->MessageLength, - sizeof(struct rndis_filter_packet)); - - if (Response->NdisMessageType == - REMOTE_NDIS_RESET_CMPLT) { - /* does not have a request id field */ - request->ResponseMessage.Message.ResetComplete.Status = STATUS_BUFFER_OVERFLOW; - } else { - request->ResponseMessage.Message.InitializeComplete.Status = STATUS_BUFFER_OVERFLOW; - } - } - - osd_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(struct rndis_device *Device, - struct rndis_message *Response) -{ - struct 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 { - /* - * TODO: - */ - } -} - -static void RndisFilterReceiveData(struct rndis_device *Device, - struct rndis_message *Message, - struct hv_netvsc_packet *Packet) -{ - struct rndis_packet *rndisPacket; - u32 dataOffset; - - DPRINT_ENTER(NETVSC); - - /* empty ethernet frame ?? */ - /* ASSERT(Packet->PageBuffers[0].Length > */ - /* RNDIS_MESSAGE_SIZE(struct rndis_packet)); */ - - rndisPacket = &Message->Message.Packet; - - /* - * FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this - * netvsc packet (ie TotalDataBufferLength != MessageLength) - */ - - /* Remove the rndis header and pass it back up the stack */ - dataOffset = RNDIS_HEADER_SIZE + rndisPacket->DataOffset; - - Packet->TotalDataBufferLength -= dataOffset; - Packet->PageBuffers[0].Offset += dataOffset; - Packet->PageBuffers[0].Length -= dataOffset; - - Packet->IsDataPacket = true; - - gRndisFilter.InnerDriver.OnReceiveCallback(Device->NetDevice->Device, - Packet); - - DPRINT_EXIT(NETVSC); -} - -static int RndisFilterOnReceive(struct hv_device *Device, - struct hv_netvsc_packet *Packet) -{ - struct netvsc_device *netDevice = Device->Extension; - struct rndis_device *rndisDevice; - struct rndis_message rndisMessage; - struct rndis_message *rndisHeader; - - DPRINT_ENTER(NETVSC); - - if (!netDevice) - return -EINVAL; - - /* Make sure the rndis device state is initialized */ - if (!netDevice->Extension) { - DPRINT_ERR(NETVSC, "got rndis message but no rndis device..." - "dropping this message!"); - DPRINT_EXIT(NETVSC); - return -1; - } - - rndisDevice = (struct 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 = (struct rndis_message *)kmap_atomic( - pfn_to_page(Packet->PageBuffers[0].Pfn), KM_IRQ0); - - rndisHeader = (void *)((unsigned long)rndisHeader + - Packet->PageBuffers[0].Offset); - - /* 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 - * */ -#if 0 - if (Packet->TotalDataBufferLength != rndisHeader->MessageLength) { - kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset, - KM_IRQ0); - - 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(struct rndis_message))) { - DPRINT_ERR(NETVSC, "incoming rndis message buffer overflow " - "detected (got %u, max %zu)...marking it an error!", - rndisHeader->MessageLength, - sizeof(struct rndis_message)); - } - - memcpy(&rndisMessage, rndisHeader, - (rndisHeader->MessageLength > sizeof(struct rndis_message)) ? - sizeof(struct rndis_message) : - rndisHeader->MessageLength); - - kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset, KM_IRQ0); - - DumpRndisMessage(&rndisMessage); - - switch (rndisMessage.NdisMessageType) { - case REMOTE_NDIS_PACKET_MSG: - /* data msg */ - RndisFilterReceiveData(rndisDevice, &rndisMessage, Packet); - break; - - case REMOTE_NDIS_INITIALIZE_CMPLT: - case REMOTE_NDIS_QUERY_CMPLT: - case REMOTE_NDIS_SET_CMPLT: - /* case REMOTE_NDIS_RESET_CMPLT: */ - /* case REMOTE_NDIS_KEEPALIVE_CMPLT: */ - /* completion msgs */ - RndisFilterReceiveResponse(rndisDevice, &rndisMessage); - break; - - case REMOTE_NDIS_INDICATE_STATUS_MSG: - /* notification msgs */ - 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(struct rndis_device *Device, u32 Oid, - void *Result, u32 *ResultSize) -{ - struct rndis_request *request; - u32 inresultSize = *ResultSize; - struct rndis_query_request *query; - struct rndis_query_complete *queryComplete; - int ret = 0; - - DPRINT_ENTER(NETVSC); - - if (!Result) - return -EINVAL; - - *ResultSize = 0; - request = GetRndisRequest(Device, REMOTE_NDIS_QUERY_MSG, - RNDIS_MESSAGE_SIZE(struct rndis_query_request)); - if (!request) { - ret = -1; - goto Cleanup; - } - - /* Setup the rndis query */ - query = &request->RequestMessage.Message.QueryRequest; - query->Oid = Oid; - query->InformationBufferOffset = sizeof(struct rndis_query_request); - query->InformationBufferLength = 0; - query->DeviceVcHandle = 0; - - ret = RndisFilterSendRequest(Device, request); - if (ret != 0) - goto Cleanup; - - osd_WaitEventWait(request->WaitEvent); - - /* Copy the response back */ - queryComplete = &request->ResponseMessage.Message.QueryComplete; - - if (queryComplete->InformationBufferLength > inresultSize) { - ret = -1; - goto Cleanup; - } - - memcpy(Result, - (void *)((unsigned long)queryComplete + - queryComplete->InformationBufferOffset), - queryComplete->InformationBufferLength); - - *ResultSize = queryComplete->InformationBufferLength; - -Cleanup: - if (request) - PutRndisRequest(Device, request); - DPRINT_EXIT(NETVSC); - - return ret; -} - -static int RndisFilterQueryDeviceMac(struct rndis_device *Device) -{ - u32 size = ETH_ALEN; - - return RndisFilterQueryDevice(Device, - RNDIS_OID_802_3_PERMANENT_ADDRESS, - Device->HwMacAddr, &size); -} - -static int RndisFilterQueryDeviceLinkStatus(struct rndis_device *Device) -{ - u32 size = sizeof(u32); - - return RndisFilterQueryDevice(Device, - RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, - &Device->LinkStatus, &size); -} - -static int RndisFilterSetPacketFilter(struct rndis_device *Device, - u32 NewFilter) -{ - struct rndis_request *request; - struct rndis_set_request *set; - struct rndis_set_complete *setComplete; - u32 status; - int ret; - - DPRINT_ENTER(NETVSC); - - /* ASSERT(RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32) <= */ - /* sizeof(struct rndis_message)); */ - - request = GetRndisRequest(Device, REMOTE_NDIS_SET_MSG, - RNDIS_MESSAGE_SIZE(struct rndis_set_request) + - sizeof(u32)); - if (!request) { - ret = -1; - goto Cleanup; - } - - /* Setup the rndis set */ - set = &request->RequestMessage.Message.SetRequest; - set->Oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; - set->InformationBufferLength = sizeof(u32); - set->InformationBufferOffset = sizeof(struct rndis_set_request); - - memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request), - &NewFilter, sizeof(u32)); - - ret = RndisFilterSendRequest(Device, request); - if (ret != 0) - goto Cleanup; - - ret = osd_WaitEventWaitEx(request->WaitEvent, 2000/*2sec*/); - if (!ret) { - ret = -1; - DPRINT_ERR(NETVSC, "timeout before we got a set response..."); - /* - * We cant deallocate the request since we may still receive a - * send completion for it. - */ - 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(struct netvsc_driver *Driver) -{ - DPRINT_ENTER(NETVSC); - - DPRINT_DBG(NETVSC, "sizeof(struct rndis_filter_packet) == %zd", - sizeof(struct rndis_filter_packet)); - - Driver->RequestExtSize = sizeof(struct rndis_filter_packet); - - /* Driver->Context = rndisDriver; */ - - memset(&gRndisFilter, 0, sizeof(struct rndis_filter_driver_object)); - - /*rndisDriver->Driver = Driver; - - ASSERT(Driver->OnLinkStatusChanged); - rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/ - - /* Save the original dispatch handlers before we override it */ - 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; - - /* Override */ - Driver->Base.OnDeviceAdd = RndisFilterOnDeviceAdd; - Driver->Base.OnDeviceRemove = RndisFilterOnDeviceRemove; - Driver->Base.OnCleanup = RndisFilterOnCleanup; - Driver->OnSend = RndisFilterOnSend; - /* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */ - Driver->OnReceiveCallback = RndisFilterOnReceive; - - DPRINT_EXIT(NETVSC); - - return 0; -} - -static int RndisFilterInitDevice(struct rndis_device *Device) -{ - struct rndis_request *request; - struct rndis_initialize_request *init; - struct rndis_initialize_complete *initComplete; - u32 status; - int ret; - - DPRINT_ENTER(NETVSC); - - request = GetRndisRequest(Device, REMOTE_NDIS_INITIALIZE_MSG, - RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); - if (!request) { - ret = -1; - goto Cleanup; - } - - /* Setup the rndis set */ - init = &request->RequestMessage.Message.InitializeRequest; - init->MajorVersion = RNDIS_MAJOR_VERSION; - init->MinorVersion = RNDIS_MINOR_VERSION; - /* FIXME: Use 1536 - rounded ethernet frame size */ - init->MaxTransferSize = 2048; - - Device->State = RNDIS_DEV_INITIALIZING; - - ret = RndisFilterSendRequest(Device, request); - if (ret != 0) { - Device->State = RNDIS_DEV_UNINITIALIZED; - goto Cleanup; - } - - osd_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(struct rndis_device *Device) -{ - struct rndis_request *request; - struct rndis_halt_request *halt; - - DPRINT_ENTER(NETVSC); - - /* Attempt to do a rndis device halt */ - request = GetRndisRequest(Device, REMOTE_NDIS_HALT_MSG, - RNDIS_MESSAGE_SIZE(struct rndis_halt_request)); - if (!request) - goto Cleanup; - - /* Setup the rndis set */ - halt = &request->RequestMessage.Message.HaltRequest; - halt->RequestId = atomic_inc_return(&Device->NewRequestId); - - /* Ignore return since this msg is optional. */ - RndisFilterSendRequest(Device, request); - - Device->State = RNDIS_DEV_UNINITIALIZED; - -Cleanup: - if (request) - PutRndisRequest(Device, request); - DPRINT_EXIT(NETVSC); - return; -} - -static int RndisFilterOpenDevice(struct rndis_device *Device) -{ - int ret; - - 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(struct 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; -} - -static int RndisFilterOnDeviceAdd(struct hv_device *Device, - void *AdditionalInfo) -{ - int ret; - struct netvsc_device *netDevice; - struct rndis_device *rndisDevice; - struct netvsc_device_info *deviceInfo = AdditionalInfo; - - DPRINT_ENTER(NETVSC); - - rndisDevice = GetRndisDevice(); - if (!rndisDevice) { - DPRINT_EXIT(NETVSC); - return -1; - } - - DPRINT_DBG(NETVSC, "rndis device object allocated - %p", rndisDevice); - - /* - * 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 - */ - ret = gRndisFilter.InnerDriver.Base.OnDeviceAdd(Device, AdditionalInfo); - if (ret != 0) { - kfree(rndisDevice); - DPRINT_EXIT(NETVSC); - return ret; - } - - - /* Initialize the rndis device */ - netDevice = Device->Extension; - /* ASSERT(netDevice); */ - /* ASSERT(netDevice->Device); */ - - netDevice->Extension = rndisDevice; - rndisDevice->NetDevice = netDevice; - - /* Send the rndis initialization message */ - ret = RndisFilterInitDevice(rndisDevice); - if (ret != 0) { - /* - * TODO: If rndis init failed, we will need to shut down the - * channel - */ - } - - /* Get the mac address */ - ret = RndisFilterQueryDeviceMac(rndisDevice); - if (ret != 0) { - /* - * TODO: shutdown rndis device and the channel - */ - } - - DPRINT_INFO(NETVSC, "Device 0x%p mac addr %pM", - rndisDevice, rndisDevice->HwMacAddr); - - memcpy(deviceInfo->MacAddr, rndisDevice->HwMacAddr, ETH_ALEN); - - 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(struct hv_device *Device) -{ - struct netvsc_device *netDevice = Device->Extension; - struct rndis_device *rndisDevice = netDevice->Extension; - - DPRINT_ENTER(NETVSC); - - /* Halt and release the rndis device */ - RndisFilterHaltDevice(rndisDevice); - - kfree(rndisDevice); - netDevice->Extension = NULL; - - /* Pass control to inner driver to remove the device */ - gRndisFilter.InnerDriver.Base.OnDeviceRemove(Device); - - DPRINT_EXIT(NETVSC); - - return 0; -} - -static void RndisFilterOnCleanup(struct hv_driver *Driver) -{ - DPRINT_ENTER(NETVSC); - - DPRINT_EXIT(NETVSC); -} - -int RndisFilterOnOpen(struct hv_device *Device) -{ - int ret; - struct netvsc_device *netDevice = Device->Extension; - - DPRINT_ENTER(NETVSC); - - if (!netDevice) - return -EINVAL; - - ret = RndisFilterOpenDevice(netDevice->Extension); - - DPRINT_EXIT(NETVSC); - - return ret; -} - -int RndisFilterOnClose(struct hv_device *Device) -{ - int ret; - struct netvsc_device *netDevice = Device->Extension; - - DPRINT_ENTER(NETVSC); - - if (!netDevice) - return -EINVAL; - - ret = RndisFilterCloseDevice(netDevice->Extension); - - DPRINT_EXIT(NETVSC); - - return ret; -} - -static int RndisFilterOnSend(struct hv_device *Device, - struct hv_netvsc_packet *Packet) -{ - int ret; - struct rndis_filter_packet *filterPacket; - struct rndis_message *rndisMessage; - struct rndis_packet *rndisPacket; - u32 rndisMessageSize; - - DPRINT_ENTER(NETVSC); - - /* Add the rndis header */ - filterPacket = (struct rndis_filter_packet *)Packet->Extension; - /* ASSERT(filterPacket); */ - - memset(filterPacket, 0, sizeof(struct rndis_filter_packet)); - - rndisMessage = &filterPacket->Message; - rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet); - - rndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG; - rndisMessage->MessageLength = Packet->TotalDataBufferLength + - rndisMessageSize; - - rndisPacket = &rndisMessage->Message.Packet; - rndisPacket->DataOffset = sizeof(struct rndis_packet); - rndisPacket->DataLength = Packet->TotalDataBufferLength; - - Packet->IsDataPacket = true; - Packet->PageBuffers[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT; - Packet->PageBuffers[0].Offset = - (unsigned long)rndisMessage & (PAGE_SIZE-1); - Packet->PageBuffers[0].Length = rndisMessageSize; - - /* Save the packet send completion and context */ - filterPacket->OnCompletion = Packet->Completion.Send.OnSendCompletion; - filterPacket->CompletionContext = - Packet->Completion.Send.SendCompletionContext; - - /* Use ours */ - Packet->Completion.Send.OnSendCompletion = RndisFilterOnSendCompletion; - Packet->Completion.Send.SendCompletionContext = filterPacket; - - ret = gRndisFilter.InnerDriver.OnSend(Device, Packet); - if (ret != 0) { - /* - * Reset the completion to originals to allow retries from - * above - */ - Packet->Completion.Send.OnSendCompletion = - filterPacket->OnCompletion; - Packet->Completion.Send.SendCompletionContext = - filterPacket->CompletionContext; - } - - DPRINT_EXIT(NETVSC); - - return ret; -} - -static void RndisFilterOnSendCompletion(void *Context) -{ - struct rndis_filter_packet *filterPacket = Context; - - DPRINT_ENTER(NETVSC); - - /* Pass it back to the original handler */ - filterPacket->OnCompletion(filterPacket->CompletionContext); - - DPRINT_EXIT(NETVSC); -} - - -static void RndisFilterOnSendRequestCompletion(void *Context) -{ - DPRINT_ENTER(NETVSC); - - /* Noop */ - DPRINT_EXIT(NETVSC); -} diff --git a/drivers/staging/hv/RndisFilter.h b/drivers/staging/hv/RndisFilter.h deleted file mode 100644 index 764b9bf3e5dc..000000000000 --- a/drivers/staging/hv/RndisFilter.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * 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 - * Hank Janssen - * - */ - - -#ifndef _RNDISFILTER_H_ -#define _RNDISFILTER_H_ - -#define __struct_bcount(x) - -#include "netvsc.h" - -#include "rndis.h" - -#define RNDIS_HEADER_SIZE (sizeof(struct rndis_message) - \ - sizeof(union rndis_message_container)) - -#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 -#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 -#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 -#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 -#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 -#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 -#define NDIS_PACKET_TYPE_SMT 0x00000040 -#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 -#define NDIS_PACKET_TYPE_GROUP 0x00000100 -#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200 -#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 -#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 - - -/* Interface */ - -extern int RndisFilterInit(struct netvsc_driver *driver); - -#endif /* _RNDISFILTER_H_ */ diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c index 1000989cc0a7..ba15059c45b2 100644 --- a/drivers/staging/hv/netvsc.c +++ b/drivers/staging/hv/netvsc.c @@ -26,7 +26,7 @@ #include "osd.h" #include "logging.h" #include "netvsc.h" -#include "RndisFilter.h" +#include "rndis_filter.h" /* Globals */ diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c new file mode 100644 index 000000000000..e6824e055c11 --- /dev/null +++ b/drivers/staging/hv/rndis_filter.c @@ -0,0 +1,997 @@ +/* + * 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 + * Hank Janssen + */ +#include +#include +#include +#include +#include + +#include "osd.h" +#include "logging.h" +#include "NetVscApi.h" +#include "rndis_filter.h" + +/* Data types */ +struct rndis_filter_driver_object { + /* The original driver */ + struct netvsc_driver InnerDriver; +}; + +enum rndis_device_state { + RNDIS_DEV_UNINITIALIZED = 0, + RNDIS_DEV_INITIALIZING, + RNDIS_DEV_INITIALIZED, + RNDIS_DEV_DATAINITIALIZED, +}; + +struct rndis_device { + struct netvsc_device *NetDevice; + + enum rndis_device_state State; + u32 LinkStatus; + atomic_t NewRequestId; + + spinlock_t request_lock; + struct list_head RequestList; + + unsigned char HwMacAddr[ETH_ALEN]; +}; + +struct rndis_request { + struct list_head ListEntry; + struct osd_waitevent *WaitEvent; + + /* + * 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 + */ + struct rndis_message ResponseMessage; + + /* Simplify allocation by having a netvsc packet inline */ + struct hv_netvsc_packet Packet; + struct hv_page_buffer Buffer; + /* FIXME: We assumed a fixed size request here. */ + struct rndis_message RequestMessage; +}; + + +struct rndis_filter_packet { + void *CompletionContext; + void (*OnCompletion)(void *context); + struct rndis_message Message; +}; + + +static int RndisFilterOnDeviceAdd(struct hv_device *Device, + void *AdditionalInfo); + +static int RndisFilterOnDeviceRemove(struct hv_device *Device); + +static void RndisFilterOnCleanup(struct hv_driver *Driver); + +static int RndisFilterOnSend(struct hv_device *Device, + struct hv_netvsc_packet *Packet); + +static void RndisFilterOnSendCompletion(void *Context); + +static void RndisFilterOnSendRequestCompletion(void *Context); + + +/* The one and only */ +static struct rndis_filter_driver_object gRndisFilter; + +static struct rndis_device *GetRndisDevice(void) +{ + struct rndis_device *device; + + device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL); + if (!device) + return NULL; + + spin_lock_init(&device->request_lock); + + INIT_LIST_HEAD(&device->RequestList); + + device->State = RNDIS_DEV_UNINITIALIZED; + + return device; +} + +static struct rndis_request *GetRndisRequest(struct rndis_device *Device, + u32 MessageType, + u32 MessageLength) +{ + struct rndis_request *request; + struct rndis_message *rndisMessage; + struct rndis_set_request *set; + unsigned long flags; + + request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL); + if (!request) + return NULL; + + request->WaitEvent = osd_WaitEventCreate(); + if (!request->WaitEvent) { + kfree(request); + return NULL; + } + + rndisMessage = &request->RequestMessage; + rndisMessage->NdisMessageType = MessageType; + rndisMessage->MessageLength = MessageLength; + + /* + * 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 + */ + set = &rndisMessage->Message.SetRequest; + set->RequestId = atomic_inc_return(&Device->NewRequestId); + + /* Add to the request list */ + spin_lock_irqsave(&Device->request_lock, flags); + list_add_tail(&request->ListEntry, &Device->RequestList); + spin_unlock_irqrestore(&Device->request_lock, flags); + + return request; +} + +static void PutRndisRequest(struct rndis_device *Device, + struct rndis_request *Request) +{ + unsigned long flags; + + spin_lock_irqsave(&Device->request_lock, flags); + list_del(&Request->ListEntry); + spin_unlock_irqrestore(&Device->request_lock, flags); + + kfree(Request->WaitEvent); + kfree(Request); +} + +static void DumpRndisMessage(struct 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(struct rndis_device *Device, + struct rndis_request *Request) +{ + int ret; + struct hv_netvsc_packet *packet; + + DPRINT_ENTER(NETVSC); + + /* Setup the packet to send it */ + packet = &Request->Packet; + + packet->IsDataPacket = false; + packet->TotalDataBufferLength = Request->RequestMessage.MessageLength; + packet->PageBufferCount = 1; + + packet->PageBuffers[0].Pfn = virt_to_phys(&Request->RequestMessage) >> + PAGE_SHIFT; + packet->PageBuffers[0].Length = Request->RequestMessage.MessageLength; + packet->PageBuffers[0].Offset = + (unsigned long)&Request->RequestMessage & (PAGE_SIZE - 1); + + packet->Completion.Send.SendCompletionContext = Request;/* packet; */ + packet->Completion.Send.OnSendCompletion = + RndisFilterOnSendRequestCompletion; + packet->Completion.Send.SendCompletionTid = (unsigned long)Device; + + ret = gRndisFilter.InnerDriver.OnSend(Device->NetDevice->Device, packet); + DPRINT_EXIT(NETVSC); + return ret; +} + +static void RndisFilterReceiveResponse(struct rndis_device *Device, + struct rndis_message *Response) +{ + struct rndis_request *request = NULL; + bool found = false; + unsigned long flags; + + DPRINT_ENTER(NETVSC); + + spin_lock_irqsave(&Device->request_lock, flags); + list_for_each_entry(request, &Device->RequestList, ListEntry) { + /* + * All request/response message contains RequestId as the 1st + * field + */ + 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); + + found = true; + break; + } + } + spin_unlock_irqrestore(&Device->request_lock, flags); + + if (found) { + if (Response->MessageLength <= sizeof(struct rndis_message)) { + memcpy(&request->ResponseMessage, Response, + Response->MessageLength); + } else { + DPRINT_ERR(NETVSC, "rndis response buffer overflow " + "detected (size %u max %zu)", + Response->MessageLength, + sizeof(struct rndis_filter_packet)); + + if (Response->NdisMessageType == + REMOTE_NDIS_RESET_CMPLT) { + /* does not have a request id field */ + request->ResponseMessage.Message.ResetComplete.Status = STATUS_BUFFER_OVERFLOW; + } else { + request->ResponseMessage.Message.InitializeComplete.Status = STATUS_BUFFER_OVERFLOW; + } + } + + osd_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(struct rndis_device *Device, + struct rndis_message *Response) +{ + struct 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 { + /* + * TODO: + */ + } +} + +static void RndisFilterReceiveData(struct rndis_device *Device, + struct rndis_message *Message, + struct hv_netvsc_packet *Packet) +{ + struct rndis_packet *rndisPacket; + u32 dataOffset; + + DPRINT_ENTER(NETVSC); + + /* empty ethernet frame ?? */ + /* ASSERT(Packet->PageBuffers[0].Length > */ + /* RNDIS_MESSAGE_SIZE(struct rndis_packet)); */ + + rndisPacket = &Message->Message.Packet; + + /* + * FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this + * netvsc packet (ie TotalDataBufferLength != MessageLength) + */ + + /* Remove the rndis header and pass it back up the stack */ + dataOffset = RNDIS_HEADER_SIZE + rndisPacket->DataOffset; + + Packet->TotalDataBufferLength -= dataOffset; + Packet->PageBuffers[0].Offset += dataOffset; + Packet->PageBuffers[0].Length -= dataOffset; + + Packet->IsDataPacket = true; + + gRndisFilter.InnerDriver.OnReceiveCallback(Device->NetDevice->Device, + Packet); + + DPRINT_EXIT(NETVSC); +} + +static int RndisFilterOnReceive(struct hv_device *Device, + struct hv_netvsc_packet *Packet) +{ + struct netvsc_device *netDevice = Device->Extension; + struct rndis_device *rndisDevice; + struct rndis_message rndisMessage; + struct rndis_message *rndisHeader; + + DPRINT_ENTER(NETVSC); + + if (!netDevice) + return -EINVAL; + + /* Make sure the rndis device state is initialized */ + if (!netDevice->Extension) { + DPRINT_ERR(NETVSC, "got rndis message but no rndis device..." + "dropping this message!"); + DPRINT_EXIT(NETVSC); + return -1; + } + + rndisDevice = (struct 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 = (struct rndis_message *)kmap_atomic( + pfn_to_page(Packet->PageBuffers[0].Pfn), KM_IRQ0); + + rndisHeader = (void *)((unsigned long)rndisHeader + + Packet->PageBuffers[0].Offset); + + /* 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 + * */ +#if 0 + if (Packet->TotalDataBufferLength != rndisHeader->MessageLength) { + kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset, + KM_IRQ0); + + 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(struct rndis_message))) { + DPRINT_ERR(NETVSC, "incoming rndis message buffer overflow " + "detected (got %u, max %zu)...marking it an error!", + rndisHeader->MessageLength, + sizeof(struct rndis_message)); + } + + memcpy(&rndisMessage, rndisHeader, + (rndisHeader->MessageLength > sizeof(struct rndis_message)) ? + sizeof(struct rndis_message) : + rndisHeader->MessageLength); + + kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset, KM_IRQ0); + + DumpRndisMessage(&rndisMessage); + + switch (rndisMessage.NdisMessageType) { + case REMOTE_NDIS_PACKET_MSG: + /* data msg */ + RndisFilterReceiveData(rndisDevice, &rndisMessage, Packet); + break; + + case REMOTE_NDIS_INITIALIZE_CMPLT: + case REMOTE_NDIS_QUERY_CMPLT: + case REMOTE_NDIS_SET_CMPLT: + /* case REMOTE_NDIS_RESET_CMPLT: */ + /* case REMOTE_NDIS_KEEPALIVE_CMPLT: */ + /* completion msgs */ + RndisFilterReceiveResponse(rndisDevice, &rndisMessage); + break; + + case REMOTE_NDIS_INDICATE_STATUS_MSG: + /* notification msgs */ + 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(struct rndis_device *Device, u32 Oid, + void *Result, u32 *ResultSize) +{ + struct rndis_request *request; + u32 inresultSize = *ResultSize; + struct rndis_query_request *query; + struct rndis_query_complete *queryComplete; + int ret = 0; + + DPRINT_ENTER(NETVSC); + + if (!Result) + return -EINVAL; + + *ResultSize = 0; + request = GetRndisRequest(Device, REMOTE_NDIS_QUERY_MSG, + RNDIS_MESSAGE_SIZE(struct rndis_query_request)); + if (!request) { + ret = -1; + goto Cleanup; + } + + /* Setup the rndis query */ + query = &request->RequestMessage.Message.QueryRequest; + query->Oid = Oid; + query->InformationBufferOffset = sizeof(struct rndis_query_request); + query->InformationBufferLength = 0; + query->DeviceVcHandle = 0; + + ret = RndisFilterSendRequest(Device, request); + if (ret != 0) + goto Cleanup; + + osd_WaitEventWait(request->WaitEvent); + + /* Copy the response back */ + queryComplete = &request->ResponseMessage.Message.QueryComplete; + + if (queryComplete->InformationBufferLength > inresultSize) { + ret = -1; + goto Cleanup; + } + + memcpy(Result, + (void *)((unsigned long)queryComplete + + queryComplete->InformationBufferOffset), + queryComplete->InformationBufferLength); + + *ResultSize = queryComplete->InformationBufferLength; + +Cleanup: + if (request) + PutRndisRequest(Device, request); + DPRINT_EXIT(NETVSC); + + return ret; +} + +static int RndisFilterQueryDeviceMac(struct rndis_device *Device) +{ + u32 size = ETH_ALEN; + + return RndisFilterQueryDevice(Device, + RNDIS_OID_802_3_PERMANENT_ADDRESS, + Device->HwMacAddr, &size); +} + +static int RndisFilterQueryDeviceLinkStatus(struct rndis_device *Device) +{ + u32 size = sizeof(u32); + + return RndisFilterQueryDevice(Device, + RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, + &Device->LinkStatus, &size); +} + +static int RndisFilterSetPacketFilter(struct rndis_device *Device, + u32 NewFilter) +{ + struct rndis_request *request; + struct rndis_set_request *set; + struct rndis_set_complete *setComplete; + u32 status; + int ret; + + DPRINT_ENTER(NETVSC); + + /* ASSERT(RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32) <= */ + /* sizeof(struct rndis_message)); */ + + request = GetRndisRequest(Device, REMOTE_NDIS_SET_MSG, + RNDIS_MESSAGE_SIZE(struct rndis_set_request) + + sizeof(u32)); + if (!request) { + ret = -1; + goto Cleanup; + } + + /* Setup the rndis set */ + set = &request->RequestMessage.Message.SetRequest; + set->Oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; + set->InformationBufferLength = sizeof(u32); + set->InformationBufferOffset = sizeof(struct rndis_set_request); + + memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request), + &NewFilter, sizeof(u32)); + + ret = RndisFilterSendRequest(Device, request); + if (ret != 0) + goto Cleanup; + + ret = osd_WaitEventWaitEx(request->WaitEvent, 2000/*2sec*/); + if (!ret) { + ret = -1; + DPRINT_ERR(NETVSC, "timeout before we got a set response..."); + /* + * We cant deallocate the request since we may still receive a + * send completion for it. + */ + 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(struct netvsc_driver *Driver) +{ + DPRINT_ENTER(NETVSC); + + DPRINT_DBG(NETVSC, "sizeof(struct rndis_filter_packet) == %zd", + sizeof(struct rndis_filter_packet)); + + Driver->RequestExtSize = sizeof(struct rndis_filter_packet); + + /* Driver->Context = rndisDriver; */ + + memset(&gRndisFilter, 0, sizeof(struct rndis_filter_driver_object)); + + /*rndisDriver->Driver = Driver; + + ASSERT(Driver->OnLinkStatusChanged); + rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/ + + /* Save the original dispatch handlers before we override it */ + 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; + + /* Override */ + Driver->Base.OnDeviceAdd = RndisFilterOnDeviceAdd; + Driver->Base.OnDeviceRemove = RndisFilterOnDeviceRemove; + Driver->Base.OnCleanup = RndisFilterOnCleanup; + Driver->OnSend = RndisFilterOnSend; + /* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */ + Driver->OnReceiveCallback = RndisFilterOnReceive; + + DPRINT_EXIT(NETVSC); + + return 0; +} + +static int RndisFilterInitDevice(struct rndis_device *Device) +{ + struct rndis_request *request; + struct rndis_initialize_request *init; + struct rndis_initialize_complete *initComplete; + u32 status; + int ret; + + DPRINT_ENTER(NETVSC); + + request = GetRndisRequest(Device, REMOTE_NDIS_INITIALIZE_MSG, + RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); + if (!request) { + ret = -1; + goto Cleanup; + } + + /* Setup the rndis set */ + init = &request->RequestMessage.Message.InitializeRequest; + init->MajorVersion = RNDIS_MAJOR_VERSION; + init->MinorVersion = RNDIS_MINOR_VERSION; + /* FIXME: Use 1536 - rounded ethernet frame size */ + init->MaxTransferSize = 2048; + + Device->State = RNDIS_DEV_INITIALIZING; + + ret = RndisFilterSendRequest(Device, request); + if (ret != 0) { + Device->State = RNDIS_DEV_UNINITIALIZED; + goto Cleanup; + } + + osd_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(struct rndis_device *Device) +{ + struct rndis_request *request; + struct rndis_halt_request *halt; + + DPRINT_ENTER(NETVSC); + + /* Attempt to do a rndis device halt */ + request = GetRndisRequest(Device, REMOTE_NDIS_HALT_MSG, + RNDIS_MESSAGE_SIZE(struct rndis_halt_request)); + if (!request) + goto Cleanup; + + /* Setup the rndis set */ + halt = &request->RequestMessage.Message.HaltRequest; + halt->RequestId = atomic_inc_return(&Device->NewRequestId); + + /* Ignore return since this msg is optional. */ + RndisFilterSendRequest(Device, request); + + Device->State = RNDIS_DEV_UNINITIALIZED; + +Cleanup: + if (request) + PutRndisRequest(Device, request); + DPRINT_EXIT(NETVSC); + return; +} + +static int RndisFilterOpenDevice(struct rndis_device *Device) +{ + int ret; + + 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(struct 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; +} + +static int RndisFilterOnDeviceAdd(struct hv_device *Device, + void *AdditionalInfo) +{ + int ret; + struct netvsc_device *netDevice; + struct rndis_device *rndisDevice; + struct netvsc_device_info *deviceInfo = AdditionalInfo; + + DPRINT_ENTER(NETVSC); + + rndisDevice = GetRndisDevice(); + if (!rndisDevice) { + DPRINT_EXIT(NETVSC); + return -1; + } + + DPRINT_DBG(NETVSC, "rndis device object allocated - %p", rndisDevice); + + /* + * 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 + */ + ret = gRndisFilter.InnerDriver.Base.OnDeviceAdd(Device, AdditionalInfo); + if (ret != 0) { + kfree(rndisDevice); + DPRINT_EXIT(NETVSC); + return ret; + } + + + /* Initialize the rndis device */ + netDevice = Device->Extension; + /* ASSERT(netDevice); */ + /* ASSERT(netDevice->Device); */ + + netDevice->Extension = rndisDevice; + rndisDevice->NetDevice = netDevice; + + /* Send the rndis initialization message */ + ret = RndisFilterInitDevice(rndisDevice); + if (ret != 0) { + /* + * TODO: If rndis init failed, we will need to shut down the + * channel + */ + } + + /* Get the mac address */ + ret = RndisFilterQueryDeviceMac(rndisDevice); + if (ret != 0) { + /* + * TODO: shutdown rndis device and the channel + */ + } + + DPRINT_INFO(NETVSC, "Device 0x%p mac addr %pM", + rndisDevice, rndisDevice->HwMacAddr); + + memcpy(deviceInfo->MacAddr, rndisDevice->HwMacAddr, ETH_ALEN); + + 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(struct hv_device *Device) +{ + struct netvsc_device *netDevice = Device->Extension; + struct rndis_device *rndisDevice = netDevice->Extension; + + DPRINT_ENTER(NETVSC); + + /* Halt and release the rndis device */ + RndisFilterHaltDevice(rndisDevice); + + kfree(rndisDevice); + netDevice->Extension = NULL; + + /* Pass control to inner driver to remove the device */ + gRndisFilter.InnerDriver.Base.OnDeviceRemove(Device); + + DPRINT_EXIT(NETVSC); + + return 0; +} + +static void RndisFilterOnCleanup(struct hv_driver *Driver) +{ + DPRINT_ENTER(NETVSC); + + DPRINT_EXIT(NETVSC); +} + +int RndisFilterOnOpen(struct hv_device *Device) +{ + int ret; + struct netvsc_device *netDevice = Device->Extension; + + DPRINT_ENTER(NETVSC); + + if (!netDevice) + return -EINVAL; + + ret = RndisFilterOpenDevice(netDevice->Extension); + + DPRINT_EXIT(NETVSC); + + return ret; +} + +int RndisFilterOnClose(struct hv_device *Device) +{ + int ret; + struct netvsc_device *netDevice = Device->Extension; + + DPRINT_ENTER(NETVSC); + + if (!netDevice) + return -EINVAL; + + ret = RndisFilterCloseDevice(netDevice->Extension); + + DPRINT_EXIT(NETVSC); + + return ret; +} + +static int RndisFilterOnSend(struct hv_device *Device, + struct hv_netvsc_packet *Packet) +{ + int ret; + struct rndis_filter_packet *filterPacket; + struct rndis_message *rndisMessage; + struct rndis_packet *rndisPacket; + u32 rndisMessageSize; + + DPRINT_ENTER(NETVSC); + + /* Add the rndis header */ + filterPacket = (struct rndis_filter_packet *)Packet->Extension; + /* ASSERT(filterPacket); */ + + memset(filterPacket, 0, sizeof(struct rndis_filter_packet)); + + rndisMessage = &filterPacket->Message; + rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet); + + rndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG; + rndisMessage->MessageLength = Packet->TotalDataBufferLength + + rndisMessageSize; + + rndisPacket = &rndisMessage->Message.Packet; + rndisPacket->DataOffset = sizeof(struct rndis_packet); + rndisPacket->DataLength = Packet->TotalDataBufferLength; + + Packet->IsDataPacket = true; + Packet->PageBuffers[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT; + Packet->PageBuffers[0].Offset = + (unsigned long)rndisMessage & (PAGE_SIZE-1); + Packet->PageBuffers[0].Length = rndisMessageSize; + + /* Save the packet send completion and context */ + filterPacket->OnCompletion = Packet->Completion.Send.OnSendCompletion; + filterPacket->CompletionContext = + Packet->Completion.Send.SendCompletionContext; + + /* Use ours */ + Packet->Completion.Send.OnSendCompletion = RndisFilterOnSendCompletion; + Packet->Completion.Send.SendCompletionContext = filterPacket; + + ret = gRndisFilter.InnerDriver.OnSend(Device, Packet); + if (ret != 0) { + /* + * Reset the completion to originals to allow retries from + * above + */ + Packet->Completion.Send.OnSendCompletion = + filterPacket->OnCompletion; + Packet->Completion.Send.SendCompletionContext = + filterPacket->CompletionContext; + } + + DPRINT_EXIT(NETVSC); + + return ret; +} + +static void RndisFilterOnSendCompletion(void *Context) +{ + struct rndis_filter_packet *filterPacket = Context; + + DPRINT_ENTER(NETVSC); + + /* Pass it back to the original handler */ + filterPacket->OnCompletion(filterPacket->CompletionContext); + + DPRINT_EXIT(NETVSC); +} + + +static void RndisFilterOnSendRequestCompletion(void *Context) +{ + DPRINT_ENTER(NETVSC); + + /* Noop */ + DPRINT_EXIT(NETVSC); +} diff --git a/drivers/staging/hv/rndis_filter.h b/drivers/staging/hv/rndis_filter.h new file mode 100644 index 000000000000..764b9bf3e5dc --- /dev/null +++ b/drivers/staging/hv/rndis_filter.h @@ -0,0 +1,55 @@ +/* + * + * 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 + * Hank Janssen + * + */ + + +#ifndef _RNDISFILTER_H_ +#define _RNDISFILTER_H_ + +#define __struct_bcount(x) + +#include "netvsc.h" + +#include "rndis.h" + +#define RNDIS_HEADER_SIZE (sizeof(struct rndis_message) - \ + sizeof(union rndis_message_container)) + +#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 +#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 +#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 +#define NDIS_PACKET_TYPE_SMT 0x00000040 +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 +#define NDIS_PACKET_TYPE_GROUP 0x00000100 +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200 +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 +#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 + + +/* Interface */ + +extern int RndisFilterInit(struct netvsc_driver *driver); + +#endif /* _RNDISFILTER_H_ */