summaryrefslogtreecommitdiff
path: root/drivers/staging/hv/rndis_filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/hv/rndis_filter.c')
-rw-r--r--drivers/staging/hv/rndis_filter.c855
1 files changed, 0 insertions, 855 deletions
diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c
deleted file mode 100644
index bafccb36004..00000000000
--- a/drivers/staging/hv/rndis_filter.c
+++ /dev/null
@@ -1,855 +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 <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- */
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-
-#include "hyperv_net.h"
-
-
-enum rndis_device_state {
- RNDIS_DEV_UNINITIALIZED = 0,
- RNDIS_DEV_INITIALIZING,
- RNDIS_DEV_INITIALIZED,
- RNDIS_DEV_DATAINITIALIZED,
-};
-
-struct rndis_device {
- struct netvsc_device *net_dev;
-
- enum rndis_device_state state;
- bool link_state;
- atomic_t new_req_id;
-
- spinlock_t request_lock;
- struct list_head req_list;
-
- unsigned char hw_mac_adr[ETH_ALEN];
-};
-
-struct rndis_request {
- struct list_head list_ent;
- struct completion wait_event;
-
- /*
- * 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 response_msg;
-
- /* Simplify allocation by having a netvsc packet inline */
- struct hv_netvsc_packet pkt;
- struct hv_page_buffer buf;
- /* FIXME: We assumed a fixed size request here. */
- struct rndis_message request_msg;
-};
-
-static void rndis_filter_send_completion(void *ctx);
-
-static void rndis_filter_send_request_completion(void *ctx);
-
-
-
-static struct rndis_device *get_rndis_device(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->req_list);
-
- device->state = RNDIS_DEV_UNINITIALIZED;
-
- return device;
-}
-
-static struct rndis_request *get_rndis_request(struct rndis_device *dev,
- u32 msg_type,
- u32 msg_len)
-{
- struct rndis_request *request;
- struct rndis_message *rndis_msg;
- struct rndis_set_request *set;
- unsigned long flags;
-
- request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL);
- if (!request)
- return NULL;
-
- init_completion(&request->wait_event);
-
- rndis_msg = &request->request_msg;
- rndis_msg->ndis_msg_type = msg_type;
- rndis_msg->msg_len = msg_len;
-
- /*
- * 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 = &rndis_msg->msg.set_req;
- set->req_id = atomic_inc_return(&dev->new_req_id);
-
- /* Add to the request list */
- spin_lock_irqsave(&dev->request_lock, flags);
- list_add_tail(&request->list_ent, &dev->req_list);
- spin_unlock_irqrestore(&dev->request_lock, flags);
-
- return request;
-}
-
-static void put_rndis_request(struct rndis_device *dev,
- struct rndis_request *req)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->request_lock, flags);
- list_del(&req->list_ent);
- spin_unlock_irqrestore(&dev->request_lock, flags);
-
- kfree(req);
-}
-
-static void dump_rndis_message(struct hv_device *hv_dev,
- struct rndis_message *rndis_msg)
-{
- struct net_device *netdev;
- struct netvsc_device *net_device;
-
- net_device = hv_get_drvdata(hv_dev);
- netdev = net_device->ndev;
-
- switch (rndis_msg->ndis_msg_type) {
- case REMOTE_NDIS_PACKET_MSG:
- netdev_dbg(netdev, "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\n",
- rndis_msg->msg_len,
- rndis_msg->msg.pkt.data_offset,
- rndis_msg->msg.pkt.data_len,
- rndis_msg->msg.pkt.num_oob_data_elements,
- rndis_msg->msg.pkt.oob_data_offset,
- rndis_msg->msg.pkt.oob_data_len,
- rndis_msg->msg.pkt.per_pkt_info_offset,
- rndis_msg->msg.pkt.per_pkt_info_len);
- break;
-
- case REMOTE_NDIS_INITIALIZE_CMPLT:
- netdev_dbg(netdev, "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)\n",
- rndis_msg->msg_len,
- rndis_msg->msg.init_complete.req_id,
- rndis_msg->msg.init_complete.status,
- rndis_msg->msg.init_complete.major_ver,
- rndis_msg->msg.init_complete.minor_ver,
- rndis_msg->msg.init_complete.dev_flags,
- rndis_msg->msg.init_complete.max_xfer_size,
- rndis_msg->msg.init_complete.
- max_pkt_per_msg,
- rndis_msg->msg.init_complete.
- pkt_alignment_factor);
- break;
-
- case REMOTE_NDIS_QUERY_CMPLT:
- netdev_dbg(netdev, "REMOTE_NDIS_QUERY_CMPLT "
- "(len %u, id 0x%x, status 0x%x, buf len %u, "
- "buf offset %u)\n",
- rndis_msg->msg_len,
- rndis_msg->msg.query_complete.req_id,
- rndis_msg->msg.query_complete.status,
- rndis_msg->msg.query_complete.
- info_buflen,
- rndis_msg->msg.query_complete.
- info_buf_offset);
- break;
-
- case REMOTE_NDIS_SET_CMPLT:
- netdev_dbg(netdev,
- "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)\n",
- rndis_msg->msg_len,
- rndis_msg->msg.set_complete.req_id,
- rndis_msg->msg.set_complete.status);
- break;
-
- case REMOTE_NDIS_INDICATE_STATUS_MSG:
- netdev_dbg(netdev, "REMOTE_NDIS_INDICATE_STATUS_MSG "
- "(len %u, status 0x%x, buf len %u, buf offset %u)\n",
- rndis_msg->msg_len,
- rndis_msg->msg.indicate_status.status,
- rndis_msg->msg.indicate_status.status_buflen,
- rndis_msg->msg.indicate_status.status_buf_offset);
- break;
-
- default:
- netdev_dbg(netdev, "0x%x (len %u)\n",
- rndis_msg->ndis_msg_type,
- rndis_msg->msg_len);
- break;
- }
-}
-
-static int rndis_filter_send_request(struct rndis_device *dev,
- struct rndis_request *req)
-{
- int ret;
- struct hv_netvsc_packet *packet;
-
- /* Setup the packet to send it */
- packet = &req->pkt;
-
- packet->is_data_pkt = false;
- packet->total_data_buflen = req->request_msg.msg_len;
- packet->page_buf_cnt = 1;
-
- packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
- PAGE_SHIFT;
- packet->page_buf[0].len = req->request_msg.msg_len;
- packet->page_buf[0].offset =
- (unsigned long)&req->request_msg & (PAGE_SIZE - 1);
-
- packet->completion.send.send_completion_ctx = req;/* packet; */
- packet->completion.send.send_completion =
- rndis_filter_send_request_completion;
- packet->completion.send.send_completion_tid = (unsigned long)dev;
-
- ret = netvsc_send(dev->net_dev->dev, packet);
- return ret;
-}
-
-static void rndis_filter_receive_response(struct rndis_device *dev,
- struct rndis_message *resp)
-{
- struct rndis_request *request = NULL;
- bool found = false;
- unsigned long flags;
- struct net_device *ndev;
-
- ndev = dev->net_dev->ndev;
-
- spin_lock_irqsave(&dev->request_lock, flags);
- list_for_each_entry(request, &dev->req_list, list_ent) {
- /*
- * All request/response message contains RequestId as the 1st
- * field
- */
- if (request->request_msg.msg.init_req.req_id
- == resp->msg.init_complete.req_id) {
- found = true;
- break;
- }
- }
- spin_unlock_irqrestore(&dev->request_lock, flags);
-
- if (found) {
- if (resp->msg_len <= sizeof(struct rndis_message)) {
- memcpy(&request->response_msg, resp,
- resp->msg_len);
- } else {
- netdev_err(ndev,
- "rndis response buffer overflow "
- "detected (size %u max %zu)\n",
- resp->msg_len,
- sizeof(struct rndis_filter_packet));
-
- if (resp->ndis_msg_type ==
- REMOTE_NDIS_RESET_CMPLT) {
- /* does not have a request id field */
- request->response_msg.msg.reset_complete.
- status = STATUS_BUFFER_OVERFLOW;
- } else {
- request->response_msg.msg.
- init_complete.status =
- STATUS_BUFFER_OVERFLOW;
- }
- }
-
- complete(&request->wait_event);
- } else {
- netdev_err(ndev,
- "no rndis request found for this response "
- "(id 0x%x res type 0x%x)\n",
- resp->msg.init_complete.req_id,
- resp->ndis_msg_type);
- }
-}
-
-static void rndis_filter_receive_indicate_status(struct rndis_device *dev,
- struct rndis_message *resp)
-{
- struct rndis_indicate_status *indicate =
- &resp->msg.indicate_status;
-
- if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) {
- netvsc_linkstatus_callback(
- dev->net_dev->dev, 1);
- } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) {
- netvsc_linkstatus_callback(
- dev->net_dev->dev, 0);
- } else {
- /*
- * TODO:
- */
- }
-}
-
-static void rndis_filter_receive_data(struct rndis_device *dev,
- struct rndis_message *msg,
- struct hv_netvsc_packet *pkt)
-{
- struct rndis_packet *rndis_pkt;
- u32 data_offset;
- int i;
-
- rndis_pkt = &msg->msg.pkt;
-
- /*
- * 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 */
- data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
-
- pkt->total_data_buflen -= data_offset;
- pkt->page_buf[0].offset += data_offset;
- pkt->page_buf[0].len -= data_offset;
-
- /* Drop the 0th page, if rndis data go beyond page boundary */
- if (pkt->page_buf[0].offset >= PAGE_SIZE) {
- pkt->page_buf[1].offset = pkt->page_buf[0].offset - PAGE_SIZE;
- pkt->page_buf[1].len -= pkt->page_buf[1].offset;
- pkt->page_buf_cnt--;
- for (i = 0; i < pkt->page_buf_cnt; i++)
- pkt->page_buf[i] = pkt->page_buf[i+1];
- }
-
- pkt->is_data_pkt = true;
-
- netvsc_recv_callback(dev->net_dev->dev, pkt);
-}
-
-int rndis_filter_receive(struct hv_device *dev,
- struct hv_netvsc_packet *pkt)
-{
- struct netvsc_device *net_dev = hv_get_drvdata(dev);
- struct rndis_device *rndis_dev;
- struct rndis_message rndis_msg;
- struct rndis_message *rndis_hdr;
- struct net_device *ndev;
-
- if (!net_dev)
- return -EINVAL;
-
- ndev = net_dev->ndev;
-
- /* Make sure the rndis device state is initialized */
- if (!net_dev->extension) {
- netdev_err(ndev, "got rndis message but no rndis device - "
- "dropping this message!\n");
- return -ENODEV;
- }
-
- rndis_dev = (struct rndis_device *)net_dev->extension;
- if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
- netdev_err(ndev, "got rndis message but rndis device "
- "uninitialized...dropping this message!\n");
- return -ENODEV;
- }
-
- rndis_hdr = (struct rndis_message *)kmap_atomic(
- pfn_to_page(pkt->page_buf[0].pfn), KM_IRQ0);
-
- rndis_hdr = (void *)((unsigned long)rndis_hdr +
- pkt->page_buf[0].offset);
-
- /* Make sure we got a valid rndis message */
- if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) &&
- (rndis_hdr->msg_len > sizeof(struct rndis_message))) {
- netdev_err(ndev, "incoming rndis message buffer overflow "
- "detected (got %u, max %zu)..marking it an error!\n",
- rndis_hdr->msg_len,
- sizeof(struct rndis_message));
- }
-
- memcpy(&rndis_msg, rndis_hdr,
- (rndis_hdr->msg_len > sizeof(struct rndis_message)) ?
- sizeof(struct rndis_message) :
- rndis_hdr->msg_len);
-
- kunmap_atomic(rndis_hdr - pkt->page_buf[0].offset, KM_IRQ0);
-
- dump_rndis_message(dev, &rndis_msg);
-
- switch (rndis_msg.ndis_msg_type) {
- case REMOTE_NDIS_PACKET_MSG:
- /* data msg */
- rndis_filter_receive_data(rndis_dev, &rndis_msg, pkt);
- break;
-
- case REMOTE_NDIS_INITIALIZE_CMPLT:
- case REMOTE_NDIS_QUERY_CMPLT:
- case REMOTE_NDIS_SET_CMPLT:
- /* completion msgs */
- rndis_filter_receive_response(rndis_dev, &rndis_msg);
- break;
-
- case REMOTE_NDIS_INDICATE_STATUS_MSG:
- /* notification msgs */
- rndis_filter_receive_indicate_status(rndis_dev, &rndis_msg);
- break;
- default:
- netdev_err(ndev,
- "unhandled rndis message (type %u len %u)\n",
- rndis_msg.ndis_msg_type,
- rndis_msg.msg_len);
- break;
- }
-
- return 0;
-}
-
-static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
- void *result, u32 *result_size)
-{
- struct rndis_request *request;
- u32 inresult_size = *result_size;
- struct rndis_query_request *query;
- struct rndis_query_complete *query_complete;
- int ret = 0;
- int t;
-
- if (!result)
- return -EINVAL;
-
- *result_size = 0;
- request = get_rndis_request(dev, REMOTE_NDIS_QUERY_MSG,
- RNDIS_MESSAGE_SIZE(struct rndis_query_request));
- if (!request) {
- ret = -ENOMEM;
- goto cleanup;
- }
-
- /* Setup the rndis query */
- query = &request->request_msg.msg.query_req;
- query->oid = oid;
- query->info_buf_offset = sizeof(struct rndis_query_request);
- query->info_buflen = 0;
- query->dev_vc_handle = 0;
-
- ret = rndis_filter_send_request(dev, request);
- if (ret != 0)
- goto cleanup;
-
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
- /* Copy the response back */
- query_complete = &request->response_msg.msg.query_complete;
-
- if (query_complete->info_buflen > inresult_size) {
- ret = -1;
- goto cleanup;
- }
-
- memcpy(result,
- (void *)((unsigned long)query_complete +
- query_complete->info_buf_offset),
- query_complete->info_buflen);
-
- *result_size = query_complete->info_buflen;
-
-cleanup:
- if (request)
- put_rndis_request(dev, request);
-
- return ret;
-}
-
-static int rndis_filter_query_device_mac(struct rndis_device *dev)
-{
- u32 size = ETH_ALEN;
-
- return rndis_filter_query_device(dev,
- RNDIS_OID_802_3_PERMANENT_ADDRESS,
- dev->hw_mac_adr, &size);
-}
-
-static int rndis_filter_query_device_link_status(struct rndis_device *dev)
-{
- u32 size = sizeof(u32);
- u32 link_status;
- int ret;
-
- ret = rndis_filter_query_device(dev,
- RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
- &link_status, &size);
- dev->link_state = (link_status != 0) ? true : false;
-
- return ret;
-}
-
-static int rndis_filter_set_packet_filter(struct rndis_device *dev,
- u32 new_filter)
-{
- struct rndis_request *request;
- struct rndis_set_request *set;
- struct rndis_set_complete *set_complete;
- u32 status;
- int ret, t;
- struct net_device *ndev;
-
- ndev = dev->net_dev->ndev;
-
- request = get_rndis_request(dev, REMOTE_NDIS_SET_MSG,
- RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
- sizeof(u32));
- if (!request) {
- ret = -ENOMEM;
- goto cleanup;
- }
-
- /* Setup the rndis set */
- set = &request->request_msg.msg.set_req;
- set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
- set->info_buflen = sizeof(u32);
- set->info_buf_offset = sizeof(struct rndis_set_request);
-
- memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
- &new_filter, sizeof(u32));
-
- ret = rndis_filter_send_request(dev, request);
- if (ret != 0)
- goto cleanup;
-
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-
- if (t == 0) {
- netdev_err(ndev,
- "timeout before we got a set response...\n");
- /*
- * We can't deallocate the request since we may still receive a
- * send completion for it.
- */
- goto exit;
- } else {
- set_complete = &request->response_msg.msg.set_complete;
- status = set_complete->status;
- }
-
-cleanup:
- if (request)
- put_rndis_request(dev, request);
-exit:
- return ret;
-}
-
-
-static int rndis_filter_init_device(struct rndis_device *dev)
-{
- struct rndis_request *request;
- struct rndis_initialize_request *init;
- struct rndis_initialize_complete *init_complete;
- u32 status;
- int ret, t;
-
- request = get_rndis_request(dev, REMOTE_NDIS_INITIALIZE_MSG,
- RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
- if (!request) {
- ret = -ENOMEM;
- goto cleanup;
- }
-
- /* Setup the rndis set */
- init = &request->request_msg.msg.init_req;
- init->major_ver = RNDIS_MAJOR_VERSION;
- init->minor_ver = RNDIS_MINOR_VERSION;
- /* FIXME: Use 1536 - rounded ethernet frame size */
- init->max_xfer_size = 2048;
-
- dev->state = RNDIS_DEV_INITIALIZING;
-
- ret = rndis_filter_send_request(dev, request);
- if (ret != 0) {
- dev->state = RNDIS_DEV_UNINITIALIZED;
- goto cleanup;
- }
-
-
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
- init_complete = &request->response_msg.msg.init_complete;
- status = init_complete->status;
- if (status == RNDIS_STATUS_SUCCESS) {
- dev->state = RNDIS_DEV_INITIALIZED;
- ret = 0;
- } else {
- dev->state = RNDIS_DEV_UNINITIALIZED;
- ret = -EINVAL;
- }
-
-cleanup:
- if (request)
- put_rndis_request(dev, request);
-
- return ret;
-}
-
-static void rndis_filter_halt_device(struct rndis_device *dev)
-{
- struct rndis_request *request;
- struct rndis_halt_request *halt;
-
- /* Attempt to do a rndis device halt */
- request = get_rndis_request(dev, REMOTE_NDIS_HALT_MSG,
- RNDIS_MESSAGE_SIZE(struct rndis_halt_request));
- if (!request)
- goto cleanup;
-
- /* Setup the rndis set */
- halt = &request->request_msg.msg.halt_req;
- halt->req_id = atomic_inc_return(&dev->new_req_id);
-
- /* Ignore return since this msg is optional. */
- rndis_filter_send_request(dev, request);
-
- dev->state = RNDIS_DEV_UNINITIALIZED;
-
-cleanup:
- if (request)
- put_rndis_request(dev, request);
- return;
-}
-
-static int rndis_filter_open_device(struct rndis_device *dev)
-{
- int ret;
-
- if (dev->state != RNDIS_DEV_INITIALIZED)
- return 0;
-
- ret = rndis_filter_set_packet_filter(dev,
- NDIS_PACKET_TYPE_BROADCAST |
- NDIS_PACKET_TYPE_ALL_MULTICAST |
- NDIS_PACKET_TYPE_DIRECTED);
- if (ret == 0)
- dev->state = RNDIS_DEV_DATAINITIALIZED;
-
- return ret;
-}
-
-static int rndis_filter_close_device(struct rndis_device *dev)
-{
- int ret;
-
- if (dev->state != RNDIS_DEV_DATAINITIALIZED)
- return 0;
-
- ret = rndis_filter_set_packet_filter(dev, 0);
- if (ret == 0)
- dev->state = RNDIS_DEV_INITIALIZED;
-
- return ret;
-}
-
-int rndis_filter_device_add(struct hv_device *dev,
- void *additional_info)
-{
- int ret;
- struct netvsc_device *net_device;
- struct rndis_device *rndis_device;
- struct netvsc_device_info *device_info = additional_info;
-
- rndis_device = get_rndis_device();
- if (!rndis_device)
- return -ENODEV;
-
- /*
- * 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 = netvsc_device_add(dev, additional_info);
- if (ret != 0) {
- kfree(rndis_device);
- return ret;
- }
-
-
- /* Initialize the rndis device */
- net_device = hv_get_drvdata(dev);
-
- net_device->extension = rndis_device;
- rndis_device->net_dev = net_device;
-
- /* Send the rndis initialization message */
- ret = rndis_filter_init_device(rndis_device);
- if (ret != 0) {
- /*
- * TODO: If rndis init failed, we will need to shut down the
- * channel
- */
- }
-
- /* Get the mac address */
- ret = rndis_filter_query_device_mac(rndis_device);
- if (ret != 0) {
- /*
- * TODO: shutdown rndis device and the channel
- */
- }
-
- memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
-
- rndis_filter_query_device_link_status(rndis_device);
-
- device_info->link_state = rndis_device->link_state;
-
- dev_info(&dev->device, "Device MAC %pM link state %s\n",
- rndis_device->hw_mac_adr,
- device_info->link_state ? "down" : "up");
-
- return ret;
-}
-
-void rndis_filter_device_remove(struct hv_device *dev)
-{
- struct netvsc_device *net_dev = hv_get_drvdata(dev);
- struct rndis_device *rndis_dev = net_dev->extension;
-
- /* Halt and release the rndis device */
- rndis_filter_halt_device(rndis_dev);
-
- kfree(rndis_dev);
- net_dev->extension = NULL;
-
- netvsc_device_remove(dev);
-}
-
-
-int rndis_filter_open(struct hv_device *dev)
-{
- struct netvsc_device *net_device = hv_get_drvdata(dev);
-
- if (!net_device)
- return -EINVAL;
-
- return rndis_filter_open_device(net_device->extension);
-}
-
-int rndis_filter_close(struct hv_device *dev)
-{
- struct netvsc_device *netDevice = hv_get_drvdata(dev);
-
- if (!netDevice)
- return -EINVAL;
-
- return rndis_filter_close_device(netDevice->extension);
-}
-
-int rndis_filter_send(struct hv_device *dev,
- struct hv_netvsc_packet *pkt)
-{
- int ret;
- struct rndis_filter_packet *filterPacket;
- struct rndis_message *rndisMessage;
- struct rndis_packet *rndisPacket;
- u32 rndisMessageSize;
-
- /* Add the rndis header */
- filterPacket = (struct rndis_filter_packet *)pkt->extension;
-
- memset(filterPacket, 0, sizeof(struct rndis_filter_packet));
-
- rndisMessage = &filterPacket->msg;
- rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet);
-
- rndisMessage->ndis_msg_type = REMOTE_NDIS_PACKET_MSG;
- rndisMessage->msg_len = pkt->total_data_buflen +
- rndisMessageSize;
-
- rndisPacket = &rndisMessage->msg.pkt;
- rndisPacket->data_offset = sizeof(struct rndis_packet);
- rndisPacket->data_len = pkt->total_data_buflen;
-
- pkt->is_data_pkt = true;
- pkt->page_buf[0].pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT;
- pkt->page_buf[0].offset =
- (unsigned long)rndisMessage & (PAGE_SIZE-1);
- pkt->page_buf[0].len = rndisMessageSize;
-
- /* Save the packet send completion and context */
- filterPacket->completion = pkt->completion.send.send_completion;
- filterPacket->completion_ctx =
- pkt->completion.send.send_completion_ctx;
-
- /* Use ours */
- pkt->completion.send.send_completion = rndis_filter_send_completion;
- pkt->completion.send.send_completion_ctx = filterPacket;
-
- ret = netvsc_send(dev, pkt);
- if (ret != 0) {
- /*
- * Reset the completion to originals to allow retries from
- * above
- */
- pkt->completion.send.send_completion =
- filterPacket->completion;
- pkt->completion.send.send_completion_ctx =
- filterPacket->completion_ctx;
- }
-
- return ret;
-}
-
-static void rndis_filter_send_completion(void *ctx)
-{
- struct rndis_filter_packet *filterPacket = ctx;
-
- /* Pass it back to the original handler */
- filterPacket->completion(filterPacket->completion_ctx);
-}
-
-
-static void rndis_filter_send_request_completion(void *ctx)
-{
- /* Noop */
-}