win-pvdrivers

view xennet/xennet_common.c @ 775:31c56358c9fc

NDISTest updates. Correctly implement lookahead in xennet. The first buffer must contain the amount windows asks for in lookahead.
author James Harper <james.harper@bendigoit.com.au>
date Sun Feb 07 09:14:18 2010 +1100 (2010-02-07)
parents 0436238bcda5
children 3da023729e6b
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, PUCHAR header, ULONG new_header_size)
29 {
30 ULONG bytes_remaining;
32 //FUNCTION_ENTER();
34 if (!header)
35 header = pi->header;
37 if (new_header_size <= pi->header_length)
38 {
39 return TRUE; /* header is already at least the required size */
40 }
42 if (header == pi->first_buffer_virtual)
43 {
44 /* still working in the first buffer */
45 if (new_header_size <= pi->first_buffer_length)
46 {
47 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " new_header_size <= pi->first_buffer_length\n"));
48 pi->header_length = new_header_size;
49 if (pi->header_length == pi->first_buffer_length)
50 {
51 NdisGetNextBuffer(pi->curr_buffer, &pi->curr_buffer);
52 pi->curr_mdl_offset = 0;
53 if (pi->curr_pb)
54 pi->curr_pb = pi->curr_pb->next;
55 }
56 else
57 {
58 pi->curr_mdl_offset = (USHORT)new_header_size;
59 }
60 return TRUE;
61 }
62 else
63 {
64 //KdPrint((__DRIVER_NAME " Switching to header_data\n"));
65 memcpy(pi->header_data, header, pi->header_length);
66 header = pi->header = pi->header_data;
67 }
68 }
70 bytes_remaining = new_header_size - pi->header_length;
71 // TODO: if there are only a small number of bytes left in the current buffer then increase to consume that too...
73 //KdPrint((__DRIVER_NAME " A bytes_remaining = %d, pi->curr_buffer = %p, pi->mdl_count = %d\n", bytes_remaining, pi->curr_buffer, pi->mdl_count));
74 while (bytes_remaining && pi->curr_buffer)
75 {
76 ULONG copy_size;
78 ASSERT(pi->curr_buffer);
79 //KdPrint((__DRIVER_NAME " B bytes_remaining = %d, pi->curr_buffer = %p, pi->mdl_count = %d\n", bytes_remaining, pi->curr_buffer, pi->mdl_count));
80 if (MmGetMdlByteCount(pi->curr_buffer))
81 {
82 PUCHAR src_addr;
83 src_addr = MmGetSystemAddressForMdlSafe(pi->curr_buffer, NormalPagePriority);
84 if (!src_addr)
85 return FALSE;
86 copy_size = min(bytes_remaining, MmGetMdlByteCount(pi->curr_buffer) - pi->curr_mdl_offset);
87 //KdPrint((__DRIVER_NAME " B copy_size = %d\n", copy_size));
88 memcpy(header + pi->header_length,
89 src_addr + pi->curr_mdl_offset, copy_size);
90 pi->curr_mdl_offset = (USHORT)(pi->curr_mdl_offset + copy_size);
91 pi->header_length += copy_size;
92 bytes_remaining -= copy_size;
93 }
94 if (pi->curr_mdl_offset == MmGetMdlByteCount(pi->curr_buffer))
95 {
96 NdisGetNextBuffer(pi->curr_buffer, &pi->curr_buffer);
97 if (pi->curr_pb)
98 pi->curr_pb = pi->curr_pb->next;
99 pi->curr_mdl_offset = 0;
100 }
101 }
102 //KdPrint((__DRIVER_NAME " C bytes_remaining = %d, pi->curr_buffer = %p, pi->mdl_count = %d\n", bytes_remaining, pi->curr_buffer, pi->mdl_count));
103 if (bytes_remaining)
104 {
105 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " bytes_remaining\n"));
106 return FALSE;
107 }
108 //FUNCTION_EXIT();
109 return TRUE;
110 }
112 ULONG
113 XenNet_ParsePacketHeader(packet_info_t *pi, PUCHAR alt_buffer, ULONG min_header_size)
114 {
115 //FUNCTION_ENTER();
117 ASSERT(pi->first_buffer);
119 NdisQueryBufferSafe(pi->first_buffer, (PVOID)&pi->first_buffer_virtual, &pi->first_buffer_length, NormalPagePriority);
120 pi->curr_buffer = pi->first_buffer;
121 if (alt_buffer)
122 pi->header = alt_buffer;
123 else
124 pi->header = pi->first_buffer_virtual;
126 pi->header_length = 0;
127 pi->curr_mdl_offset = 0;
129 XenNet_BuildHeader(pi, NULL, min_header_size);
131 if (!XenNet_BuildHeader(pi, NULL, (ULONG)XN_HDR_SIZE))
132 {
133 KdPrint((__DRIVER_NAME " packet too small (Ethernet Header)\n"));
134 return PARSE_TOO_SMALL;
135 }
137 switch (GET_NET_PUSHORT(&pi->header[12])) // L2 protocol field
138 {
139 case 0x0800:
140 //KdPrint((__DRIVER_NAME " IP\n"));
141 if (pi->header_length < (ULONG)(XN_HDR_SIZE + 20))
142 {
143 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + 20)))
144 {
145 KdPrint((__DRIVER_NAME " packet too small (IP Header)\n"));
146 return PARSE_TOO_SMALL;
147 }
148 }
149 pi->ip_version = (pi->header[XN_HDR_SIZE + 0] & 0xF0) >> 4;
150 if (pi->ip_version != 4)
151 {
152 KdPrint((__DRIVER_NAME " ip_version = %d\n", pi->ip_version));
153 return PARSE_UNKNOWN_TYPE;
154 }
155 pi->ip4_header_length = (pi->header[XN_HDR_SIZE + 0] & 0x0F) << 2;
156 if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20))
157 {
158 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20)))
159 {
160 //KdPrint((__DRIVER_NAME " packet too small (IP Header + IP Options + TCP Header)\n"));
161 return PARSE_TOO_SMALL;
162 }
163 }
164 break;
165 default:
166 //KdPrint((__DRIVER_NAME " Not IP (%d)\n", GET_NET_PUSHORT(&pi->header[12])));
167 return PARSE_UNKNOWN_TYPE;
168 }
169 pi->ip_proto = pi->header[XN_HDR_SIZE + 9];
170 switch (pi->ip_proto)
171 {
172 case 6: // TCP
173 case 17: // UDP
174 break;
175 default:
176 //KdPrint((__DRIVER_NAME " Not TCP/UDP (%d)\n", pi->ip_proto));
177 return PARSE_UNKNOWN_TYPE;
178 }
179 pi->ip4_length = GET_NET_PUSHORT(&pi->header[XN_HDR_SIZE + 2]);
180 pi->tcp_header_length = (pi->header[XN_HDR_SIZE + pi->ip4_header_length + 12] & 0xf0) >> 2;
182 if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length))
183 {
184 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length)))
185 {
186 //KdPrint((__DRIVER_NAME " packet too small (IP Header + IP Options + TCP Header + TCP Options)\n"));
187 return PARSE_TOO_SMALL;
188 }
189 }
191 if ((ULONG)XN_HDR_SIZE + pi->ip4_length > pi->total_length)
192 {
193 KdPrint((__DRIVER_NAME " XN_HDR_SIZE + ip4_length (%d) > total_length (%d)\n", XN_HDR_SIZE + pi->ip4_length, pi->total_length));
194 return PARSE_UNKNOWN_TYPE;
195 }
197 pi->tcp_length = pi->ip4_length - pi->ip4_header_length - pi->tcp_header_length;
198 pi->tcp_remaining = pi->tcp_length;
199 pi->tcp_seq = GET_NET_PULONG(&pi->header[XN_HDR_SIZE + pi->ip4_header_length + 4]);
200 pi->tcp_has_options = (BOOLEAN)(pi->tcp_header_length > 20);
201 if (pi->mss > 0 && pi->tcp_length > pi->mss)
202 pi->split_required = TRUE;
204 //KdPrint((__DRIVER_NAME " ip4_length = %d\n", pi->ip4_length));
205 //KdPrint((__DRIVER_NAME " tcp_length = %d\n", pi->tcp_length));
206 //FUNCTION_EXIT();
208 return PARSE_OK;
209 }
211 VOID
212 XenNet_SumIpHeader(
213 PUCHAR header,
214 USHORT ip4_header_length
215 )
216 {
217 ULONG csum = 0;
218 USHORT i;
220 ASSERT(ip4_header_length > 12);
221 ASSERT(!(ip4_header_length & 1));
223 header[XN_HDR_SIZE + 10] = 0;
224 header[XN_HDR_SIZE + 11] = 0;
225 for (i = 0; i < ip4_header_length; i += 2)
226 {
227 csum += GET_NET_PUSHORT(&header[XN_HDR_SIZE + i]);
228 }
229 while (csum & 0xFFFF0000)
230 csum = (csum & 0xFFFF) + (csum >> 16);
231 csum = ~csum;
232 SET_NET_USHORT(&header[XN_HDR_SIZE + 10], (USHORT)csum);
233 }
235 BOOLEAN
236 XenNet_FilterAcceptPacket(struct xennet_info *xi,packet_info_t *pi)
237 {
238 BOOLEAN is_multicast = FALSE;
239 BOOLEAN is_my_multicast = FALSE;
240 BOOLEAN is_broadcast = FALSE;
241 BOOLEAN is_directed = FALSE;
242 ULONG i;
244 if (pi->header[0] == 0xFF && pi->header[1] == 0xFF
245 && pi->header[2] == 0xFF && pi->header[3] == 0xFF
246 && pi->header[4] == 0xFF && pi->header[5] == 0xFF)
247 {
248 is_broadcast = TRUE;
249 }
250 else if (pi->header[0] & 0x01)
251 {
252 is_multicast = TRUE;
253 for (i = 0; i < xi->multicast_list_size; i++)
254 {
255 if (memcmp(xi->multicast_list[i], pi->header, 6) == 0)
256 break;
257 }
258 if (i < xi->multicast_list_size)
259 {
260 is_my_multicast = TRUE;
261 }
262 }
263 if (memcmp(xi->curr_mac_addr, pi->header, ETH_ALEN) == 0)
264 {
265 is_directed = TRUE;
266 }
268 if (is_directed && (xi->packet_filter & NDIS_PACKET_TYPE_DIRECTED))
269 {
270 return TRUE;
271 }
272 if (is_my_multicast && (xi->packet_filter & NDIS_PACKET_TYPE_MULTICAST))
273 {
274 return TRUE;
275 }
276 if (is_multicast && (xi->packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST))
277 {
278 return TRUE;
279 }
280 if (is_broadcast && (xi->packet_filter & NDIS_PACKET_TYPE_BROADCAST))
281 {
282 return TRUE;
283 }
284 if (xi->packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS)
285 {
286 return TRUE;
287 }
288 return FALSE;
289 }