win-pvdrivers

view xennet/xennet6.h @ 962:278b479f3f7d

Fix for problem on rx where tcpip.sys leaks memory if the first MDL contains a fragment of the TCP payload.
Fixed a bug in detecting checksum support
Improve multi-buffer handling in rx path
Remove old #ifdef'd out code
Adding NDIS version detection for version-dependent features
Started adding Header/Data split
author James Harper <james.harper@bendigoit.com.au>
date Fri Dec 30 20:58:01 2011 +1100 (2011-12-30)
parents 916ea40186fc
children a5d1d333e0e2
line source
1 /*
2 PV Drivers 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 #pragma warning(disable: 4201)
22 #pragma warning(disable: 4214)
24 #include <ntddk.h>
25 #include <wdm.h>
26 #define NDIS_MINIPORT_DRIVER 1
27 #define NDIS61_MINIPORT 1
28 #include <ndis.h>
29 #define NTSTRSAFE_LIB
30 #include <ntstrsafe.h>
31 #include <liblfds.h>
33 #define VENDOR_DRIVER_VERSION_MAJOR 0
34 #define VENDOR_DRIVER_VERSION_MINOR 11
36 #define MAX_LINK_SPEED 10000000000L; /* there is not really any theoretical maximum... */
38 #define VENDOR_DRIVER_VERSION (((VENDOR_DRIVER_VERSION_MAJOR) << 16) | (VENDOR_DRIVER_VERSION_MINOR))
40 #define __DRIVER_NAME "XenNet"
42 #define NB_LIST_ENTRY_FIELD MiniportReserved[0] // TX (2 entries)
43 #define NB_FIRST_PB_FIELD MiniportReserved[0] // RX
44 #define NB_NBL_FIELD MiniportReserved[2] // TX
45 #define NB_LIST_ENTRY(_nb) (*(PLIST_ENTRY)&(_nb)->NB_LIST_ENTRY_FIELD)
46 #define NB_NBL(_nb) (*(PNET_BUFFER_LIST *)&(_nb)->NB_NBL_FIELD)
47 #define NB_FIRST_PB(_nb) (*(shared_buffer_t **)&(_nb)->NB_FIRST_PB_FIELD)
49 #define NBL_REF_FIELD MiniportReserved[0] // TX
50 //#define NBL_LIST_ENTRY_FIELD MiniportReserved[0] // TX (2 entries) - overlaps with REF_FIELD
51 //#define NBL_PACKET_COUNT_FIELD MiniportReserved[0] // RX
52 //#define NBL_LAST_NB_FIELD MiniportReserved[1] // RX
53 #define NBL_REF(_nbl) (*(ULONG_PTR *)&(_nbl)->NBL_REF_FIELD)
54 //#define NBL_LIST_ENTRY(_nbl) (*(PLIST_ENTRY)&(_nbl)->NBL_LIST_ENTRY_FIELD)
55 //#define NBL_PACKET_COUNT(_nbl) (*(ULONG_PTR *)&(_nbl)->NBL_PACKET_COUNT_FIELD)
56 //#define NBL_LAST_NB(_nbl) (*(PNET_BUFFER *)&(_nbl)->NBL_LAST_NB_FIELD)
58 #include <xen_windows.h>
59 #include <memory.h>
60 #include <grant_table.h>
61 #include <event_channel.h>
62 #include <hvm/params.h>
63 #include <hvm/hvm_op.h>
64 #include <xen_public.h>
65 #include <io/ring.h>
66 #include <io/netif.h>
67 #include <io/xenbus.h>
68 #include <stdlib.h>
69 #define XENNET_POOL_TAG (ULONG) 'XenN'
71 /* Xen macros use these, so they need to be redefined to Win equivs */
72 #define wmb() KeMemoryBarrier()
73 #define mb() KeMemoryBarrier()
75 #define GRANT_INVALID_REF 0
77 #define NAME_SIZE 64
79 #define ETH_ALEN 6
81 /*
82 #define __NET_USHORT_BYTE_0(x) ((USHORT)(x & 0xFF))
83 #define __NET_USHORT_BYTE_1(x) ((USHORT)((PUCHAR)&x)[1] & 0xFF)
85 #define GET_NET_USHORT(x) ((__NET_USHORT_BYTE_0(x) << 8) | __NET_USHORT_BYTE_1(x))
86 #define SET_NET_USHORT(y, x) *((USHORT *)&(y)) = ((__NET_USHORT_BYTE_0(x) << 8) | __NET_USHORT_BYTE_1(x))
87 */
89 static FORCEINLINE USHORT
90 GET_NET_USHORT(USHORT data)
91 {
92 return (data << 8) | (data >> 8);
93 }
95 static FORCEINLINE USHORT
96 GET_NET_PUSHORT(PVOID pdata)
97 {
98 return (*((PUSHORT)pdata) << 8) | (*((PUSHORT)pdata) >> 8);
99 }
101 static FORCEINLINE VOID
102 SET_NET_USHORT(PVOID ptr, USHORT data)
103 {
104 *((PUSHORT)ptr) = GET_NET_USHORT(data);
105 }
107 static FORCEINLINE ULONG
108 GET_NET_ULONG(ULONG data)
109 {
110 ULONG tmp;
112 tmp = ((data & 0x00ff00ff) << 8) | ((data & 0xff00ff00) >> 8);
113 return (tmp << 16) | (tmp >> 16);
114 }
116 static FORCEINLINE ULONG
117 GET_NET_PULONG(PVOID pdata)
118 {
119 ULONG tmp;
121 tmp = ((*((PULONG)pdata) & 0x00ff00ff) << 8) | ((*((PULONG)pdata) & 0xff00ff00) >> 8);
122 return (tmp << 16) | (tmp >> 16);
123 }
125 static FORCEINLINE VOID
126 SET_NET_ULONG(PVOID ptr, ULONG data)
127 {
128 *((PULONG)ptr) = GET_NET_ULONG(data);
129 }
130 /*
131 #define GET_NET_ULONG(x) ((GET_NET_USHORT(x) << 16) | GET_NET_USHORT(((PUCHAR)&x)[2]))
132 #define SET_NET_ULONG(y, x) *((ULONG *)&(y)) = ((GET_NET_USHORT(x) << 16) | GET_NET_USHORT(((PUCHAR)&x)[2]))
133 */
135 #define SUPPORTED_PACKET_FILTERS (\
136 NDIS_PACKET_TYPE_DIRECTED | \
137 NDIS_PACKET_TYPE_MULTICAST | \
138 NDIS_PACKET_TYPE_BROADCAST | \
139 NDIS_PACKET_TYPE_PROMISCUOUS | \
140 NDIS_PACKET_TYPE_ALL_MULTICAST)
142 /* couldn't get regular xen ring macros to work...*/
143 #define __NET_RING_SIZE(type, _sz) \
144 (__RD32( \
145 (_sz - sizeof(struct type##_sring) + sizeof(union type##_sring_entry)) \
146 / sizeof(union type##_sring_entry)))
148 #define NET_TX_RING_SIZE __NET_RING_SIZE(netif_tx, PAGE_SIZE)
149 #define NET_RX_RING_SIZE __NET_RING_SIZE(netif_rx, PAGE_SIZE)
151 #pragma warning(disable: 4127) // conditional expression is constant
153 #define MIN_LARGE_SEND_SEGMENTS 4
155 /* TODO: crank this up if we support higher mtus? */
156 #define XN_HDR_SIZE 14
157 #define XN_MAX_DATA_SIZE 1500
158 #define XN_MIN_FRAME_SIZE 60
159 #define XN_MAX_FRAME_SIZE (XN_HDR_SIZE + XN_DATA_SIZE)
160 /*
161 #if !defined(OFFLOAD_LARGE_SEND)
162 #define XN_MAX_PKT_SIZE (XN_HDR_SIZE + XN_DATA_SIZE)
163 #else
164 #define XN_MAX_PKT_SIZE MAX_LARGE_SEND_OFFLOAD
165 #endif
166 */
168 #define XN_MAX_SEND_PKTS 16
170 #define XENSOURCE_MAC_HDR 0x00163E
171 #define XN_VENDOR_DESC "Xensource"
172 #define MAX_XENBUS_STR_LEN 128
174 #define RX_MIN_TARGET 8
175 #define RX_DFL_MIN_TARGET 256
176 #define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
177 #define RX_MAX_PB_FREELIST (RX_MAX_TARGET * 4)
179 //#define MAX_BUFFERS_PER_PACKET NET_RX_RING_SIZE
181 #define MIN_ETH_HEADER_LENGTH 14
182 #define MAX_ETH_HEADER_LENGTH 14
183 #define MIN_IP4_HEADER_LENGTH 20
184 #define MAX_IP4_HEADER_LENGTH (15 * 4)
185 #define MIN_TCP_HEADER_LENGTH 20
186 #define MAX_TCP_HEADER_LENGTH (15 * 4)
187 #define MAX_PKT_HEADER_LENGTH (MAX_ETH_HEADER_LENGTH + MAX_IP4_HEADER_LENGTH + MAX_TCP_HEADER_LENGTH)
189 #define MIN_LOOKAHEAD_LENGTH (MAX_IP4_HEADER_LENGTH + MAX_TCP_HEADER_LENGTH)
190 #define MAX_LOOKAHEAD_LENGTH PAGE_SIZE
192 #define LINUX_MAX_SG_ELEMENTS 19
194 struct _shared_buffer_t;
196 typedef struct _shared_buffer_t shared_buffer_t;
198 struct _shared_buffer_t
199 {
200 struct netif_rx_response rsp;
201 shared_buffer_t *next;
202 grant_ref_t gref;
203 //USHORT offset;
204 PVOID virtual;
205 PMDL mdl;
206 //USHORT id;
207 volatile LONG ref_count;
208 };
210 typedef struct
211 {
212 PNET_BUFFER nb; /* only set on the last packet */
213 PVOID *cb;
214 grant_ref_t gref;
215 } tx_shadow_t;
217 typedef struct {
218 ULONG parse_result;
219 PMDL first_mdl;
220 MDL first_mdl_storage;
221 PPFN_NUMBER first_mdl_pfns[17]; /* maximum possible packet size */
222 PMDL curr_mdl;
223 shared_buffer_t *first_pb;
224 shared_buffer_t *curr_pb;
225 PUCHAR first_mdl_virtual;
226 //ULONG mdl_count;
227 ULONG first_mdl_offset;
228 ULONG first_mdl_length;
229 ULONG curr_mdl_offset;
230 USHORT mss;
231 //NDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
232 BOOLEAN csum_blank;
233 BOOLEAN data_validated;
234 BOOLEAN split_required;
235 UCHAR ip_version;
236 PUCHAR header;
237 ULONG header_length;
238 UCHAR ip_proto;
239 ULONG total_length;
240 USHORT ip4_header_length;
241 USHORT ip4_length;
242 USHORT tcp_header_length;
243 BOOLEAN tcp_has_options;
244 USHORT tcp_length;
245 USHORT tcp_remaining;
246 ULONG tcp_seq;
247 BOOLEAN is_multicast;
248 BOOLEAN is_broadcast;
249 /* anything past here doesn't get cleared automatically by the ClearPacketInfo */
250 UCHAR header_data[MAX_LOOKAHEAD_LENGTH + MAX_ETH_HEADER_LENGTH];
251 } packet_info_t;
253 #define PAGE_LIST_SIZE (max(NET_RX_RING_SIZE, NET_TX_RING_SIZE) * 4)
254 #define MULTICAST_LIST_MAX_SIZE 32
256 /* split incoming large packets into MSS sized chunks */
257 #define RX_LSO_SPLIT_MSS 0
258 /* split incoming large packets in half, to not invoke the delayed ack timer */
259 #define RX_LSO_SPLIT_HALF 1
260 /* don't split incoming large packets. not really useful */
261 #define RX_LSO_SPLIT_NONE 2
263 struct xennet_info
264 {
265 BOOLEAN inactive;
267 /* Base device vars */
268 PDEVICE_OBJECT pdo;
269 PDEVICE_OBJECT fdo;
270 PDEVICE_OBJECT lower_do;
271 //WDFDEVICE wdf_device;
272 WCHAR dev_desc[NAME_SIZE];
274 /* NDIS-related vars */
275 NDIS_HANDLE adapter_handle;
276 ULONG packet_filter;
277 BOOLEAN connected;
278 BOOLEAN shutting_down;
279 BOOLEAN tx_shutting_down;
280 BOOLEAN rx_shutting_down;
281 uint8_t perm_mac_addr[ETH_ALEN];
282 uint8_t curr_mac_addr[ETH_ALEN];
283 ULONG current_lookahead;
284 NDIS_DEVICE_POWER_STATE new_power_state;
285 NDIS_DEVICE_POWER_STATE power_state;
286 PIO_WORKITEM power_workitem;
288 /* Misc. Xen vars */
289 XENPCI_VECTORS vectors;
290 PXENPCI_DEVICE_STATE device_state;
291 evtchn_port_t event_channel;
292 ULONG state;
293 char backend_path[MAX_XENBUS_STR_LEN];
294 ULONG backend_state;
295 PVOID config_page;
296 UCHAR multicast_list[MULTICAST_LIST_MAX_SIZE][6];
297 ULONG multicast_list_size;
298 KDPC suspend_dpc;
299 PIO_WORKITEM resume_work_item;
300 KSPIN_LOCK resume_lock;
301 KDPC rxtx_dpc;
303 /* tx related - protected by tx_lock */
304 KSPIN_LOCK tx_lock;
305 LIST_ENTRY tx_waiting_pkt_list;
306 struct netif_tx_front_ring tx;
307 ULONG tx_ring_free;
308 tx_shadow_t tx_shadows[NET_TX_RING_SIZE];
309 //NDIS_HANDLE tx_buffer_pool;
310 #define TX_HEADER_BUFFER_SIZE 512
311 //#define TX_COALESCE_BUFFERS (NET_TX_RING_SIZE >> 2)
312 #define TX_COALESCE_BUFFERS (NET_TX_RING_SIZE)
313 KEVENT tx_idle_event;
314 ULONG tx_outstanding;
315 ULONG tx_id_free;
316 USHORT tx_id_list[NET_TX_RING_SIZE];
317 NPAGED_LOOKASIDE_LIST tx_lookaside_list;
319 /* rx_related - protected by rx_lock */
320 KSPIN_LOCK rx_lock;
321 struct netif_rx_front_ring rx;
322 ULONG rx_id_free;
323 packet_info_t *rxpi;
324 KEVENT packet_returned_event;
325 NDIS_HANDLE rx_nbl_pool;
326 NDIS_HANDLE rx_nb_pool;
327 volatile LONG rx_pb_free;
328 struct stack_state *rx_pb_stack;
329 volatile LONG rx_hb_free;
330 struct stack_state *rx_hb_stack;
331 shared_buffer_t *rx_ring_pbs[NET_RX_RING_SIZE];
332 /* Receive-ring batched refills. */
333 ULONG rx_target;
334 ULONG rx_max_target;
335 ULONG rx_min_target;
336 shared_buffer_t *rx_partial_buf;
337 BOOLEAN rx_partial_extra_info_flag ;
338 BOOLEAN rx_partial_more_data_flag;
340 /* how many packets are in the net stack atm */
341 LONG rx_outstanding;
343 /* config vars from registry */
344 /* the frontend_* indicate our willingness to support */
345 BOOLEAN frontend_sg_supported;
346 BOOLEAN frontend_csum_supported;
347 ULONG frontend_gso_value;
348 ULONG frontend_mtu_value;
349 ULONG frontend_gso_rx_split_type; /* RX_LSO_SPLIT_* */
351 BOOLEAN backend_sg_supported;
352 BOOLEAN backend_csum_supported;
353 ULONG backend_gso_value;
355 BOOLEAN current_sg_supported;
356 BOOLEAN current_csum_supported;
357 ULONG current_gso_value;
358 ULONG current_mtu_value;
359 ULONG current_gso_rx_split_type;
361 /* config stuff calculated from the above */
362 ULONG config_max_pkt_size;
364 /* stats */\
365 NDIS_STATISTICS_INFO stats;
366 //ULONG64 stat_tx_ok;
367 //ULONG64 stat_rx_ok;
368 //ULONG64 stat_tx_error;
369 //ULONG64 stat_rx_error;
370 //ULONG64 stat_rx_no_buffer;
372 } typedef xennet_info_t;
374 struct xennet_oids_t {
375 ULONG oid;
376 char *oid_name;
377 ULONG min_length;
378 MINIPORT_OID_REQUEST *query_routine;
379 MINIPORT_OID_REQUEST *set_routine;
380 };
382 extern struct xennet_oids_t xennet_oids[];
384 extern USHORT ndis_os_major_version;
385 extern USHORT ndis_os_minor_version;
388 MINIPORT_OID_REQUEST XenNet_OidRequest;
389 MINIPORT_CANCEL_OID_REQUEST XenNet_CancelOidRequest;
391 MINIPORT_SEND_NET_BUFFER_LISTS XenNet_SendNetBufferLists;
392 MINIPORT_CANCEL_SEND XenNet_CancelSend;
394 MINIPORT_RETURN_NET_BUFFER_LISTS XenNet_ReturnNetBufferLists;
396 BOOLEAN
397 XenNet_RxInit(xennet_info_t *xi);
399 BOOLEAN
400 XenNet_RxShutdown(xennet_info_t *xi);
402 VOID
403 XenNet_RxResumeStart(xennet_info_t *xi);
405 VOID
406 XenNet_RxResumeEnd(xennet_info_t *xi);
408 BOOLEAN
409 XenNet_RxBufferCheck(struct xennet_info *xi);
411 VOID
412 XenNet_TxResumeStart(xennet_info_t *xi);
414 VOID
415 XenNet_TxResumeEnd(xennet_info_t *xi);
417 BOOLEAN
418 XenNet_TxInit(xennet_info_t *xi);
420 BOOLEAN
421 XenNet_TxShutdown(xennet_info_t *xi);
423 VOID
424 XenNet_TxBufferGC(struct xennet_info *xi, BOOLEAN dont_set_event);
426 #if 0
427 NDIS_STATUS
428 XenNet_D0Entry(struct xennet_info *xi);
429 NDIS_STATUS
430 XenNet_D0Exit(struct xennet_info *xi);
431 IO_WORKITEM_ROUTINE
432 XenNet_SetPower;
433 #endif
435 /* return values */
436 #define PARSE_OK 0
437 #define PARSE_TOO_SMALL 1 /* first buffer is too small */
438 #define PARSE_UNKNOWN_TYPE 2
440 BOOLEAN
441 XenNet_BuildHeader(packet_info_t *pi, PVOID header, ULONG new_header_size);
442 VOID
443 XenNet_ParsePacketHeader(packet_info_t *pi, PUCHAR buffer, ULONG min_header_size);
444 BOOLEAN
445 XenNet_FilterAcceptPacket(struct xennet_info *xi,packet_info_t *pi);
447 VOID
448 XenNet_SumIpHeader(
449 PUCHAR header,
450 USHORT ip4_header_length
451 );
453 static __forceinline VOID
454 XenNet_ClearPacketInfo(packet_info_t *pi)
455 {
456 RtlZeroMemory(pi, sizeof(packet_info_t) - FIELD_OFFSET(packet_info_t, header_data));
457 }
459 /* Get some data from the current packet, but don't cross a page boundry. */
460 static __forceinline ULONG
461 XenNet_QueryData(packet_info_t *pi, ULONG length)
462 {
463 ULONG offset_in_page;
465 if (length > MmGetMdlByteCount(pi->curr_mdl) - pi->curr_mdl_offset)
466 length = MmGetMdlByteCount(pi->curr_mdl) - pi->curr_mdl_offset;
468 offset_in_page = (MmGetMdlByteOffset(pi->curr_mdl) + pi->curr_mdl_offset) & (PAGE_SIZE - 1);
469 if (offset_in_page + length > PAGE_SIZE)
470 length = PAGE_SIZE - offset_in_page;
472 return length;
473 }
475 /* Move the pointers forward by the given amount. No error checking is done. */
476 static __forceinline VOID
477 XenNet_EatData(packet_info_t *pi, ULONG length)
478 {
479 pi->curr_mdl_offset += length;
480 if (pi->curr_mdl_offset >= MmGetMdlByteCount(pi->curr_mdl))
481 {
482 pi->curr_mdl_offset -= MmGetMdlByteCount(pi->curr_mdl);
483 NdisGetNextMdl(pi->curr_mdl, &pi->curr_mdl);
484 }
485 }