win-pvdrivers

view xennet/xennet_common.c @ 685:c13ccf5a629b

Fixed a bug in the dma routines which was causing memory corruption. In some cases when Windows gave an MDL that was longer than the buffer to be dma'd, the end of the buffer would be overwritten. The only time I am aware of this occuring is on one particular map in Call Of Duty 4.

Split out the dma routines from xenpci_pdo.c into xenpci_dma.c
author James Harper <james.harper@bendigoit.com.au>
date Wed Oct 14 14:46:39 2009 +1100 (2009-10-14)
parents 0436238bcda5
children 31c56358c9fc
line source
1 /*
2 PV Net Driver for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
4 Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
21 #include "xennet.h"
23 /*
24 Increase the header to a certain size
25 */
27 BOOLEAN
28 XenNet_BuildHeader(packet_info_t *pi, ULONG new_header_size)
29 {
30 ULONG bytes_remaining;
32 //FUNCTION_ENTER();
34 if (new_header_size <= pi->header_length)
35 {
36 return TRUE; /* header is already at least the required size */
37 }
39 if (pi->header == pi->first_buffer_virtual)
40 {
41 /* still working in the first buffer */
42 if (new_header_size <= pi->first_buffer_length)
43 {
44 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " new_header_size <= pi->first_buffer_length\n"));
45 pi->header_length = new_header_size;
46 if (pi->header_length == pi->first_buffer_length)
47 {
48 NdisGetNextBuffer(pi->curr_buffer, &pi->curr_buffer);
49 pi->curr_mdl_offset = 0;
50 }
51 else
52 {
53 pi->curr_mdl_offset = (USHORT)new_header_size;
54 if (pi->curr_pb)
55 pi->curr_pb = pi->curr_pb->next;
56 }
57 return TRUE;
58 }
59 else
60 {
61 //KdPrint((__DRIVER_NAME " Switching to header_data\n"));
62 memcpy(pi->header_data, pi->header, pi->header_length);
63 pi->header = pi->header_data;
64 }
65 }
67 bytes_remaining = new_header_size - pi->header_length;
69 //KdPrint((__DRIVER_NAME " A bytes_remaining = %d, pi->curr_buffer = %p, pi->mdl_count = %d\n", bytes_remaining, pi->curr_buffer, pi->mdl_count));
70 while (bytes_remaining && pi->curr_buffer)
71 {
72 ULONG copy_size;
74 ASSERT(pi->curr_buffer);
75 //KdPrint((__DRIVER_NAME " B bytes_remaining = %d, pi->curr_buffer = %p, pi->mdl_count = %d\n", bytes_remaining, pi->curr_buffer, pi->mdl_count));
76 if (MmGetMdlByteCount(pi->curr_buffer))
77 {
78 PUCHAR src_addr;
79 src_addr = MmGetSystemAddressForMdlSafe(pi->curr_buffer, NormalPagePriority);
80 if (!src_addr)
81 return FALSE;
82 copy_size = min(bytes_remaining, MmGetMdlByteCount(pi->curr_buffer) - pi->curr_mdl_offset);
83 //KdPrint((__DRIVER_NAME " B copy_size = %d\n", copy_size));
84 memcpy(pi->header + pi->header_length,
85 src_addr + pi->curr_mdl_offset, copy_size);
86 pi->curr_mdl_offset = (USHORT)(pi->curr_mdl_offset + copy_size);
87 pi->header_length += copy_size;
88 bytes_remaining -= copy_size;
89 }
90 if (pi->curr_mdl_offset == MmGetMdlByteCount(pi->curr_buffer))
91 {
92 NdisGetNextBuffer(pi->curr_buffer, &pi->curr_buffer);
93 if (pi->curr_pb)
94 pi->curr_pb = pi->curr_pb->next;
95 pi->curr_mdl_offset = 0;
96 }
97 }
98 //KdPrint((__DRIVER_NAME " C bytes_remaining = %d, pi->curr_buffer = %p, pi->mdl_count = %d\n", bytes_remaining, pi->curr_buffer, pi->mdl_count));
99 if (bytes_remaining)
100 {
101 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " bytes_remaining\n"));
102 return FALSE;
103 }
104 //FUNCTION_EXIT();
105 return TRUE;
106 }
108 ULONG
109 XenNet_ParsePacketHeader(packet_info_t *pi, PUCHAR alt_buffer, ULONG min_header_size)
110 {
111 //FUNCTION_ENTER();
113 ASSERT(pi->first_buffer);
115 NdisQueryBufferSafe(pi->first_buffer, (PVOID)&pi->first_buffer_virtual, &pi->first_buffer_length, NormalPagePriority);
116 pi->curr_buffer = pi->first_buffer;
117 if (alt_buffer)
118 pi->header = alt_buffer;
119 else
120 pi->header = pi->first_buffer_virtual;
122 pi->header_length = 0;
123 pi->curr_mdl_offset = 0;
125 if (!XenNet_BuildHeader(pi, max((ULONG)XN_HDR_SIZE, min_header_size)))
126 {
127 KdPrint((__DRIVER_NAME " packet too small (Ethernet Header)\n"));
128 return PARSE_TOO_SMALL;
129 }
131 switch (GET_NET_PUSHORT(&pi->header[12])) // L2 protocol field
132 {
133 case 0x0800:
134 //KdPrint((__DRIVER_NAME " IP\n"));
135 if (pi->header_length < (ULONG)(XN_HDR_SIZE + 20))
136 {
137 if (!XenNet_BuildHeader(pi, (ULONG)(XN_HDR_SIZE + 20)))
138 {
139 KdPrint((__DRIVER_NAME " packet too small (IP Header)\n"));
140 return PARSE_TOO_SMALL;
141 }
142 }
143 pi->ip_version = (pi->header[XN_HDR_SIZE + 0] & 0xF0) >> 4;
144 if (pi->ip_version != 4)
145 {
146 KdPrint((__DRIVER_NAME " ip_version = %d\n", pi->ip_version));
147 return PARSE_UNKNOWN_TYPE;
148 }
149 pi->ip4_header_length = (pi->header[XN_HDR_SIZE + 0] & 0x0F) << 2;
150 if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20))
151 {
152 if (!XenNet_BuildHeader(pi, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20)))
153 {
154 //KdPrint((__DRIVER_NAME " packet too small (IP Header + IP Options + TCP Header)\n"));
155 return PARSE_TOO_SMALL;
156 }
157 }
158 break;
159 default:
160 //KdPrint((__DRIVER_NAME " Not IP (%d)\n", GET_NET_PUSHORT(&pi->header[12])));
161 return PARSE_UNKNOWN_TYPE;
162 }
163 pi->ip_proto = pi->header[XN_HDR_SIZE + 9];
164 switch (pi->ip_proto)
165 {
166 case 6: // TCP
167 case 17: // UDP
168 break;
169 default:
170 //KdPrint((__DRIVER_NAME " Not TCP/UDP (%d)\n", pi->ip_proto));
171 return PARSE_UNKNOWN_TYPE;
172 }
173 pi->ip4_length = GET_NET_PUSHORT(&pi->header[XN_HDR_SIZE + 2]);
174 pi->tcp_header_length = (pi->header[XN_HDR_SIZE + pi->ip4_header_length + 12] & 0xf0) >> 2;
176 if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length))
177 {
178 if (!XenNet_BuildHeader(pi, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length)))
179 {
180 //KdPrint((__DRIVER_NAME " packet too small (IP Header + IP Options + TCP Header + TCP Options)\n"));
181 return PARSE_TOO_SMALL;
182 }
183 }
185 if ((ULONG)XN_HDR_SIZE + pi->ip4_length > pi->total_length)
186 {
187 KdPrint((__DRIVER_NAME " XN_HDR_SIZE + ip4_length (%d) > total_length (%d)\n", XN_HDR_SIZE + pi->ip4_length, pi->total_length));
188 return PARSE_UNKNOWN_TYPE;
189 }
191 pi->tcp_length = pi->ip4_length - pi->ip4_header_length - pi->tcp_header_length;
192 pi->tcp_remaining = pi->tcp_length;
193 pi->tcp_seq = GET_NET_PULONG(&pi->header[XN_HDR_SIZE + pi->ip4_header_length + 4]);
194 pi->tcp_has_options = (BOOLEAN)(pi->tcp_header_length > 20);
195 if (pi->mss > 0 && pi->tcp_length > pi->mss)
196 pi->split_required = TRUE;
198 //KdPrint((__DRIVER_NAME " ip4_length = %d\n", pi->ip4_length));
199 //KdPrint((__DRIVER_NAME " tcp_length = %d\n", pi->tcp_length));
200 //FUNCTION_EXIT();
202 return PARSE_OK;
203 }
205 VOID
206 XenNet_SumIpHeader(
207 PUCHAR header,
208 USHORT ip4_header_length
209 )
210 {
211 ULONG csum = 0;
212 USHORT i;
214 ASSERT(ip4_header_length > 12);
215 ASSERT(!(ip4_header_length & 1));
217 header[XN_HDR_SIZE + 10] = 0;
218 header[XN_HDR_SIZE + 11] = 0;
219 for (i = 0; i < ip4_header_length; i += 2)
220 {
221 csum += GET_NET_PUSHORT(&header[XN_HDR_SIZE + i]);
222 }
223 while (csum & 0xFFFF0000)
224 csum = (csum & 0xFFFF) + (csum >> 16);
225 csum = ~csum;
226 SET_NET_USHORT(&header[XN_HDR_SIZE + 10], (USHORT)csum);
227 }