diff options
author | Haiyang Zhang <haiyangz@microsoft.com> | 2012-02-02 02:18:00 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-02-02 14:35:12 -0500 |
commit | c31c151b1c4a29da4dc92212aa8648fb4f8557b9 (patch) | |
tree | c61eb4b25fcac9f70cc381468b2365d85ca39ad6 /drivers/net/hyperv | |
parent | 0a282538cc1977655004cdb2eb25dd2b63f20637 (diff) |
net/hyperv: Fix the page buffer when an RNDIS message goes beyond page boundary
There is a possible data corruption if an RNDIS message goes beyond page
boundary in the sending code path. This patch fixes the problem.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/hyperv')
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 8 | ||||
-rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 13 |
2 files changed, 17 insertions, 4 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 69193fcb7648..466c58a7353d 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -151,10 +151,10 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
151 | int ret; | 151 | int ret; |
152 | unsigned int i, num_pages, npg_data; | 152 | unsigned int i, num_pages, npg_data; |
153 | 153 | ||
154 | /* Add multipage for skb->data and additional one for RNDIS */ | 154 | /* Add multipages for skb->data and additional 2 for RNDIS */ |
155 | npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1) | 155 | npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1) |
156 | >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1; | 156 | >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1; |
157 | num_pages = skb_shinfo(skb)->nr_frags + npg_data + 1; | 157 | num_pages = skb_shinfo(skb)->nr_frags + npg_data + 2; |
158 | 158 | ||
159 | /* Allocate a netvsc packet based on # of frags. */ | 159 | /* Allocate a netvsc packet based on # of frags. */ |
160 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + | 160 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + |
@@ -173,8 +173,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
173 | sizeof(struct hv_netvsc_packet) + | 173 | sizeof(struct hv_netvsc_packet) + |
174 | (num_pages * sizeof(struct hv_page_buffer)); | 174 | (num_pages * sizeof(struct hv_page_buffer)); |
175 | 175 | ||
176 | /* Setup the rndis header */ | 176 | /* If the rndis msg goes beyond 1 page, we will add 1 later */ |
177 | packet->page_buf_cnt = num_pages; | 177 | packet->page_buf_cnt = num_pages - 1; |
178 | 178 | ||
179 | /* Initialize it from the skb */ | 179 | /* Initialize it from the skb */ |
180 | packet->total_data_buflen = skb->len; | 180 | packet->total_data_buflen = skb->len; |
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index dc2e3849573b..133b7fbf8595 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c | |||
@@ -797,6 +797,19 @@ int rndis_filter_send(struct hv_device *dev, | |||
797 | (unsigned long)rndisMessage & (PAGE_SIZE-1); | 797 | (unsigned long)rndisMessage & (PAGE_SIZE-1); |
798 | pkt->page_buf[0].len = rndisMessageSize; | 798 | pkt->page_buf[0].len = rndisMessageSize; |
799 | 799 | ||
800 | /* Add one page_buf if the rndis msg goes beyond page boundary */ | ||
801 | if (pkt->page_buf[0].offset + rndisMessageSize > PAGE_SIZE) { | ||
802 | int i; | ||
803 | for (i = pkt->page_buf_cnt; i > 1; i--) | ||
804 | pkt->page_buf[i] = pkt->page_buf[i-1]; | ||
805 | pkt->page_buf_cnt++; | ||
806 | pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset; | ||
807 | pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong) | ||
808 | rndisMessage + pkt->page_buf[0].len)) >> PAGE_SHIFT; | ||
809 | pkt->page_buf[1].offset = 0; | ||
810 | pkt->page_buf[1].len = rndisMessageSize - pkt->page_buf[0].len; | ||
811 | } | ||
812 | |||
800 | /* Save the packet send completion and context */ | 813 | /* Save the packet send completion and context */ |
801 | filterPacket->completion = pkt->completion.send.send_completion; | 814 | filterPacket->completion = pkt->completion.send.send_completion; |
802 | filterPacket->completion_ctx = | 815 | filterPacket->completion_ctx = |