win-pvdrivers

view xennet/xennet6_common.c @ 953:cc8651af4e45

Fix header length calculation properly
author James Harper <james.harper@bendigoit.com.au>
date Thu Nov 10 21:04:53 2011 +1100 (2011-11-10)
parents 81f132396f9e
children 278b479f3f7d
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 "xennet6.h"
23 /* Increase the header to a certain size */
24 BOOLEAN
25 XenNet_BuildHeader(packet_info_t *pi, PUCHAR header, ULONG new_header_size)
26 {
27 ULONG bytes_remaining;
29 //FUNCTION_ENTER();
31 if (!header)
32 header = pi->header;
34 if (new_header_size > pi->total_length)
35 {
36 new_header_size = pi->total_length;
37 }
39 if (new_header_size <= pi->header_length)
40 {
41 //FUNCTION_EXIT();
42 return TRUE; /* header is already at least the required size */
43 }
45 if (header == pi->first_mdl_virtual)
46 {
47 /* still working in the first buffer */
48 if (new_header_size <= pi->first_mdl_length)
49 {
50 //KdPrint((__DRIVER_NAME " new_header_size <= pi->first_mdl_length\n"));
51 pi->header_length = new_header_size;
52 if (pi->header_length == pi->first_mdl_length)
53 {
54 NdisGetNextMdl(pi->curr_mdl, &pi->curr_mdl);
55 pi->curr_mdl_offset = 0;
56 if (pi->curr_pb)
57 pi->curr_pb = pi->curr_pb->next;
58 }
59 else
60 {
61 pi->curr_mdl_offset = (USHORT)new_header_size;
62 }
63 //FUNCTION_EXIT();
64 return TRUE;
65 }
66 else
67 {
68 //KdPrint((__DRIVER_NAME " Switching to header_data\n"));
69 memcpy(pi->header_data, header, pi->header_length);
70 header = pi->header = pi->header_data;
71 }
72 }
74 bytes_remaining = new_header_size - pi->header_length;
75 // TODO: if there are only a small number of bytes left in the current buffer then increase to consume that too... it would have to be no more than the size of header+mss though
77 //KdPrint((__DRIVER_NAME " A bytes_remaining = %d, pi->curr_mdl = %p\n", bytes_remaining, pi->curr_mdl));
78 while (bytes_remaining && pi->curr_mdl)
79 {
80 ULONG copy_size;
82 ASSERT(pi->curr_mdl);
83 //KdPrint((__DRIVER_NAME " B bytes_remaining = %d, pi->curr_mdl = %p\n", bytes_remaining, pi->curr_mdl));
84 if (MmGetMdlByteCount(pi->curr_mdl))
85 {
86 PUCHAR src_addr;
87 src_addr = MmGetSystemAddressForMdlSafe(pi->curr_mdl, NormalPagePriority);
88 if (!src_addr)
89 {
90 //FUNCTION_EXIT();
91 return FALSE;
92 }
93 copy_size = min(bytes_remaining, MmGetMdlByteCount(pi->curr_mdl) - pi->curr_mdl_offset);
94 //KdPrint((__DRIVER_NAME " B copy_size = %d\n", copy_size));
95 memcpy(header + pi->header_length,
96 src_addr + pi->curr_mdl_offset, copy_size);
97 pi->curr_mdl_offset = (USHORT)(pi->curr_mdl_offset + copy_size);
98 pi->header_length += copy_size;
99 bytes_remaining -= copy_size;
100 }
101 if (pi->curr_mdl_offset == MmGetMdlByteCount(pi->curr_mdl))
102 {
103 NdisGetNextMdl(pi->curr_mdl, &pi->curr_mdl);
104 if (pi->curr_pb)
105 pi->curr_pb = pi->curr_pb->next;
106 pi->curr_mdl_offset = 0;
107 }
108 }
109 //KdPrint((__DRIVER_NAME " C bytes_remaining = %d, pi->curr_mdl = %p\n", bytes_remaining, pi->curr_mdl));
110 if (bytes_remaining)
111 {
112 //KdPrint((__DRIVER_NAME " bytes_remaining\n"));
113 //FUNCTION_EXIT();
114 return FALSE;
115 }
116 //FUNCTION_EXIT();
117 return TRUE;
118 }
120 VOID
121 XenNet_ParsePacketHeader(packet_info_t *pi, PUCHAR alt_buffer, ULONG min_header_size)
122 {
123 //FUNCTION_ENTER();
125 ASSERT(pi->first_mdl);
127 NdisQueryMdl(pi->first_mdl, (PVOID)&pi->first_mdl_virtual, &pi->first_mdl_length, NormalPagePriority);
128 pi->curr_mdl = pi->first_mdl;
129 if (alt_buffer)
130 pi->header = alt_buffer;
131 else
132 pi->header = pi->first_mdl_virtual;
134 pi->header_length = 0;
135 pi->curr_mdl_offset = pi->first_mdl_offset;
137 XenNet_BuildHeader(pi, NULL, min_header_size);
139 if (!XenNet_BuildHeader(pi, NULL, (ULONG)XN_HDR_SIZE))
140 {
141 //KdPrint((__DRIVER_NAME " packet too small (Ethernet Header)\n"));
142 pi->parse_result = PARSE_TOO_SMALL;
143 return;
144 }
146 if (pi->header[0] == 0xFF && pi->header[1] == 0xFF
147 && pi->header[2] == 0xFF && pi->header[3] == 0xFF
148 && pi->header[4] == 0xFF && pi->header[5] == 0xFF)
149 {
150 pi->is_broadcast = TRUE;
151 }
152 else if (pi->header[0] & 0x01)
153 {
154 pi->is_multicast = TRUE;
155 }
157 switch (GET_NET_PUSHORT(&pi->header[12])) // L2 protocol field
158 {
159 case 0x0800: /* IPv4 */
160 //KdPrint((__DRIVER_NAME " IP\n"));
161 if (pi->header_length < (ULONG)(XN_HDR_SIZE + 20))
162 {
163 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + 20)))
164 {
165 KdPrint((__DRIVER_NAME " packet too small (IP Header)\n"));
166 pi->parse_result = PARSE_TOO_SMALL;
167 return;
168 }
169 }
170 pi->ip_version = (pi->header[XN_HDR_SIZE + 0] & 0xF0) >> 4;
171 if (pi->ip_version != 4)
172 {
173 //KdPrint((__DRIVER_NAME " ip_version = %d\n", pi->ip_version));
174 pi->parse_result = PARSE_UNKNOWN_TYPE;
175 return;
176 }
177 pi->ip4_header_length = (pi->header[XN_HDR_SIZE + 0] & 0x0F) << 2;
178 if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20))
179 {
180 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20)))
181 {
182 //KdPrint((__DRIVER_NAME " packet too small (IP Header + IP Options + TCP Header)\n"));
183 pi->parse_result = PARSE_TOO_SMALL;
184 return;
185 }
186 }
187 break;
188 case 0x86DD: /* IPv6 */
189 //KdPrint((__DRIVER_NAME " IPv6\n"));
190 //KdPrint((__DRIVER_NAME " (not currently used)\n"));
191 pi->parse_result = PARSE_UNKNOWN_TYPE;
192 return;
193 default:
194 //KdPrint((__DRIVER_NAME " Not IP (%04x)\n", GET_NET_PUSHORT(&pi->header[12])));
195 pi->parse_result = PARSE_UNKNOWN_TYPE;
196 return;
197 }
198 pi->ip_proto = pi->header[XN_HDR_SIZE + 9];
199 switch (pi->ip_proto)
200 {
201 case 6: // TCP
202 case 17: // UDP
203 break;
204 default:
205 //KdPrint((__DRIVER_NAME " Not TCP/UDP (%d)\n", pi->ip_proto));
206 pi->parse_result = PARSE_UNKNOWN_TYPE;
207 return;
208 }
209 pi->ip4_length = GET_NET_PUSHORT(&pi->header[XN_HDR_SIZE + 2]);
210 pi->tcp_header_length = (pi->header[XN_HDR_SIZE + pi->ip4_header_length + 12] & 0xf0) >> 2;
212 if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length))
213 {
214 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length)))
215 {
216 //KdPrint((__DRIVER_NAME " packet too small (IP Header + IP Options + TCP Header + TCP Options)\n"));
217 pi->parse_result = PARSE_TOO_SMALL;
218 return;
219 }
220 }
222 if ((ULONG)XN_HDR_SIZE + pi->ip4_length > pi->total_length)
223 {
224 //KdPrint((__DRIVER_NAME " XN_HDR_SIZE + ip4_length (%d) > total_length (%d)\n", XN_HDR_SIZE + pi->ip4_length, pi->total_length));
225 pi->parse_result = PARSE_UNKNOWN_TYPE;
226 return;
227 }
229 pi->tcp_length = pi->ip4_length - pi->ip4_header_length - pi->tcp_header_length;
230 pi->tcp_remaining = pi->tcp_length;
231 pi->tcp_seq = GET_NET_PULONG(&pi->header[XN_HDR_SIZE + pi->ip4_header_length + 4]);
232 pi->tcp_has_options = (BOOLEAN)(pi->tcp_header_length > 20);
233 if (pi->mss > 0 && pi->tcp_length > pi->mss)
234 pi->split_required = TRUE;
236 //KdPrint((__DRIVER_NAME " ip4_length = %d\n", pi->ip4_length));
237 //KdPrint((__DRIVER_NAME " tcp_length = %d\n", pi->tcp_length));
238 //FUNCTION_EXIT();
240 pi->parse_result = PARSE_OK;
241 }
243 VOID
244 XenNet_SumIpHeader(
245 PUCHAR header,
246 USHORT ip4_header_length
247 )
248 {
249 ULONG csum = 0;
250 USHORT i;
252 ASSERT(ip4_header_length > 12);
253 ASSERT(!(ip4_header_length & 1));
255 header[XN_HDR_SIZE + 10] = 0;
256 header[XN_HDR_SIZE + 11] = 0;
257 for (i = 0; i < ip4_header_length; i += 2)
258 {
259 csum += GET_NET_PUSHORT(&header[XN_HDR_SIZE + i]);
260 }
261 while (csum & 0xFFFF0000)
262 csum = (csum & 0xFFFF) + (csum >> 16);
263 csum = ~csum;
264 SET_NET_USHORT(&header[XN_HDR_SIZE + 10], (USHORT)csum);
265 }
267 BOOLEAN
268 XenNet_FilterAcceptPacket(struct xennet_info *xi,packet_info_t *pi)
269 {
270 ULONG i;
271 BOOLEAN is_my_multicast = FALSE;
272 BOOLEAN is_directed = FALSE;
274 if (memcmp(xi->curr_mac_addr, pi->header, ETH_ALEN) == 0)
275 {
276 is_directed = TRUE;
277 }
278 else if (pi->is_multicast)
279 {
280 for (i = 0; i < xi->multicast_list_size; i++)
281 {
282 if (memcmp(xi->multicast_list[i], pi->header, 6) == 0)
283 break;
284 }
285 if (i < xi->multicast_list_size)
286 {
287 is_my_multicast = TRUE;
288 }
289 }
290 if (is_directed && (xi->packet_filter & NDIS_PACKET_TYPE_DIRECTED))
291 {
292 return TRUE;
293 }
294 if (is_my_multicast && (xi->packet_filter & NDIS_PACKET_TYPE_MULTICAST))
295 {
296 return TRUE;
297 }
298 if (pi->is_multicast && (xi->packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST))
299 {
300 return TRUE;
301 }
302 if (pi->is_broadcast && (xi->packet_filter & NDIS_PACKET_TYPE_BROADCAST))
303 {
304 return TRUE;
305 }
306 if (xi->packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS)
307 {
308 return TRUE;
309 }
310 //return TRUE;
311 return FALSE;
312 }