From 0f48917b93414a9c306a834b1b93307383956f44 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Thu, 9 Aug 2012 08:04:18 +0000 Subject: hyperv: Add comments for the extended buffer after RNDIS message Reported-by: Olaf Hering Signed-off-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/rndis_filter.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/hyperv/rndis_filter.c') diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 1e88a10..06f8601 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -46,8 +46,14 @@ struct rndis_request { /* 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; + /* + * The buffer for the extended info after the RNDIS message. It's + * referenced based on the data offset in the RNDIS message. Its size + * is enough for current needs, and should be sufficient for the near + * future. + */ u8 ext[100]; }; -- cgit v1.1 From fb1d074edb92604f313ac671f67e806c3223d191 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Tue, 2 Oct 2012 05:30:19 +0000 Subject: hyperv: Fix the max_xfer_size in RNDIS initialization According to RNDIS specs, Windows sets this size to 0x4000. I use the same value here. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/rndis_filter.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/hyperv/rndis_filter.c') diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 06f8601..1337b64 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -684,8 +684,7 @@ static int rndis_filter_init_device(struct rndis_device *dev) 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; + init->max_xfer_size = 0x4000; dev->state = RNDIS_DEV_INITIALIZING; -- cgit v1.1 From ea4963745f712a746ccb45871a22e0814141a891 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Tue, 2 Oct 2012 05:30:20 +0000 Subject: hyperv: Fix the missing return value in rndis_filter_set_packet_filter() Return ETIMEDOUT when the reply message is not received in time. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/rndis_filter.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/hyperv/rndis_filter.c') diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 1337b64..617eb2e 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -647,6 +647,7 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) if (t == 0) { netdev_err(ndev, "timeout before we got a set response...\n"); + ret = -ETIMEDOUT; /* * We can't deallocate the request since we may still receive a * send completion for it. -- cgit v1.1 From 99e3fcfa34e7ea6dbb44fe5df51b79ccb6f73d3d Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Tue, 2 Oct 2012 05:30:21 +0000 Subject: hyperv: Fix page buffer handling in rndis_filter_send_request() To prevent possible data corruption in RNDIS requests, add another page buffer if the request message crossed page boundary. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/rndis_filter.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/net/hyperv/rndis_filter.c') diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 617eb2e..f25f41e 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -45,7 +45,8 @@ struct rndis_request { /* Simplify allocation by having a netvsc packet inline */ struct hv_netvsc_packet pkt; - struct hv_page_buffer buf; + /* Set 2 pages for rndis requests crossing page boundary */ + struct hv_page_buffer buf[2]; struct rndis_message request_msg; /* @@ -227,6 +228,18 @@ static int rndis_filter_send_request(struct rndis_device *dev, packet->page_buf[0].offset = (unsigned long)&req->request_msg & (PAGE_SIZE - 1); + /* Add one page_buf when request_msg crossing page boundary */ + if (packet->page_buf[0].offset + packet->page_buf[0].len > PAGE_SIZE) { + packet->page_buf_cnt++; + packet->page_buf[0].len = PAGE_SIZE - + packet->page_buf[0].offset; + packet->page_buf[1].pfn = virt_to_phys((void *)&req->request_msg + + packet->page_buf[0].len) >> PAGE_SHIFT; + packet->page_buf[1].offset = 0; + packet->page_buf[1].len = req->request_msg.msg_len - + packet->page_buf[0].len; + } + packet->completion.send.send_completion_ctx = req;/* packet; */ packet->completion.send.send_completion = rndis_filter_send_request_completion; -- cgit v1.1 From 63f6921d300c6fbdca3d0e73dcc24b4e5e4dced2 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Tue, 2 Oct 2012 05:30:23 +0000 Subject: hyperv: Report actual status in receive completion packet The existing code always reports NVSP_STAT_SUCCESS. This patch adds the mechanism to report failure when it happens. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/rndis_filter.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/net/hyperv/rndis_filter.c') diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index f25f41e..e7e12cf 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -411,9 +411,12 @@ int rndis_filter_receive(struct hv_device *dev, struct rndis_device *rndis_dev; struct rndis_message *rndis_msg; struct net_device *ndev; + int ret = 0; - if (!net_dev) - return -EINVAL; + if (!net_dev) { + ret = -EINVAL; + goto exit; + } ndev = net_dev->ndev; @@ -421,14 +424,16 @@ int rndis_filter_receive(struct hv_device *dev, if (!net_dev->extension) { netdev_err(ndev, "got rndis message but no rndis device - " "dropping this message!\n"); - return -ENODEV; + ret = -ENODEV; + goto exit; } 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; + ret = -ENODEV; + goto exit; } rndis_msg = pkt->data; @@ -460,7 +465,11 @@ int rndis_filter_receive(struct hv_device *dev, break; } - return 0; +exit: + if (ret != 0) + pkt->status = NVSP_STAT_FAIL; + + return ret; } static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, -- cgit v1.1 From a3a6cab5ea10cca64d036851fe0d932448f2fe4f Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Tue, 2 Oct 2012 05:30:24 +0000 Subject: hyperv: Add buffer for extended info after the RNDIS response message. In some response messages, there may be some extended info after the message. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/rndis_filter.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers/net/hyperv/rndis_filter.c') diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index e7e12cf..928148c 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -32,16 +32,19 @@ #include "hyperv_net.h" +#define RNDIS_EXT_LEN 100 struct rndis_request { struct list_head list_ent; struct completion wait_event; + struct rndis_message response_msg; /* - * 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 + * The buffer for extended info after the RNDIS response message. It's + * referenced based on the data offset in the RNDIS message. Its size + * is enough for current needs, and should be sufficient for the near + * future. */ - struct rndis_message response_msg; + u8 response_ext[RNDIS_EXT_LEN]; /* Simplify allocation by having a netvsc packet inline */ struct hv_netvsc_packet pkt; @@ -50,12 +53,10 @@ struct rndis_request { struct rndis_message request_msg; /* - * The buffer for the extended info after the RNDIS message. It's - * referenced based on the data offset in the RNDIS message. Its size - * is enough for current needs, and should be sufficient for the near - * future. + * The buffer for the extended info after the RNDIS request message. + * It is referenced and sized in a similar way as response_ext. */ - u8 ext[100]; + u8 request_ext[RNDIS_EXT_LEN]; }; static void rndis_filter_send_completion(void *ctx); @@ -274,7 +275,8 @@ static void rndis_filter_receive_response(struct rndis_device *dev, spin_unlock_irqrestore(&dev->request_lock, flags); if (found) { - if (resp->msg_len <= sizeof(struct rndis_message)) { + if (resp->msg_len <= + sizeof(struct rndis_message) + RNDIS_EXT_LEN) { memcpy(&request->response_msg, resp, resp->msg_len); } else { -- cgit v1.1