win-pvdrivers

annotate xennet/xennet_common.c @ 1065:00d29add6a2a

Tidy up xennet. Remove KdPrint calls.
author James Harper <james.harper@bendigoit.com.au>
date Thu Oct 03 18:12:10 2013 +1000 (2013-10-03)
parents 5bb1f345e06a
children 05ece536b204
rev   line source
james@1007 1 /*
james@1007 2 PV Net Driver for Windows Xen HVM Domains
james@1007 3 Copyright (C) 2007 James Harper
james@1007 4 Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
james@1007 5
james@1007 6 This program is free software; you can redistribute it and/or
james@1007 7 modify it under the terms of the GNU General Public License
james@1007 8 as published by the Free Software Foundation; either version 2
james@1007 9 of the License, or (at your option) any later version.
james@1007 10
james@1007 11 This program is distributed in the hope that it will be useful,
james@1007 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@1007 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@1007 14 GNU General Public License for more details.
james@1007 15
james@1007 16 You should have received a copy of the GNU General Public License
james@1007 17 along with this program; if not, write to the Free Software
james@1007 18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@1007 19 */
james@1007 20
james@1007 21 #include "xennet.h"
james@1007 22
james@1007 23 /* Increase the header to a certain size */
james@1007 24 BOOLEAN
james@1007 25 XenNet_BuildHeader(packet_info_t *pi, PUCHAR header, ULONG new_header_size)
james@1007 26 {
james@1007 27 ULONG bytes_remaining;
james@1007 28
james@1007 29 //FUNCTION_ENTER();
james@1007 30
james@1007 31 if (!header)
james@1007 32 header = pi->header;
james@1007 33
james@1007 34 if (new_header_size > pi->total_length) {
james@1007 35 new_header_size = pi->total_length;
james@1007 36 }
james@1007 37
james@1007 38 if (new_header_size <= pi->header_length) {
james@1007 39 //FUNCTION_EXIT();
james@1007 40 return TRUE; /* header is already at least the required size */
james@1007 41 }
james@1007 42
james@1007 43 if (header == pi->first_mdl_virtual) {
james@1007 44 /* still working in the first buffer */
james@1007 45 if (new_header_size <= pi->first_mdl_length) {
james@1007 46 pi->header_length = new_header_size;
james@1007 47 if (pi->header_length == pi->first_mdl_length) {
james@1007 48 #if NTDDI_VERSION < NTDDI_VISTA
james@1007 49 NdisGetNextBuffer(pi->curr_mdl, &pi->curr_mdl);
james@1007 50 #else
james@1007 51 NdisGetNextMdl(pi->curr_mdl, &pi->curr_mdl);
james@1007 52 #endif
james@1007 53 pi->curr_mdl_offset = 0;
james@1007 54 if (pi->curr_pb)
james@1007 55 pi->curr_pb = pi->curr_pb->next;
james@1007 56 } else {
james@1007 57 pi->curr_mdl_offset = (USHORT)new_header_size;
james@1007 58 }
james@1007 59 //FUNCTION_EXIT();
james@1007 60 return TRUE;
james@1007 61 } else {
james@1007 62 memcpy(pi->header_data, header, pi->header_length);
james@1007 63 header = pi->header = pi->header_data;
james@1007 64 }
james@1007 65 }
james@1007 66
james@1007 67 bytes_remaining = new_header_size - pi->header_length;
james@1007 68 // 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
james@1007 69
james@1007 70 while (bytes_remaining && pi->curr_mdl) {
james@1007 71 ULONG copy_size;
james@1007 72
james@1023 73 XN_ASSERT(pi->curr_mdl);
james@1007 74 if (MmGetMdlByteCount(pi->curr_mdl)) {
james@1007 75 PUCHAR src_addr;
james@1007 76 src_addr = MmGetSystemAddressForMdlSafe(pi->curr_mdl, NormalPagePriority);
james@1007 77 if (!src_addr) {
james@1007 78 //FUNCTION_EXIT();
james@1007 79 return FALSE;
james@1007 80 }
james@1007 81 copy_size = min(bytes_remaining, MmGetMdlByteCount(pi->curr_mdl) - pi->curr_mdl_offset);
james@1007 82 memcpy(header + pi->header_length,
james@1007 83 src_addr + pi->curr_mdl_offset, copy_size);
james@1007 84 pi->curr_mdl_offset = (USHORT)(pi->curr_mdl_offset + copy_size);
james@1007 85 pi->header_length += copy_size;
james@1007 86 bytes_remaining -= copy_size;
james@1007 87 }
james@1007 88 if (pi->curr_mdl_offset == MmGetMdlByteCount(pi->curr_mdl)) {
james@1007 89 #if NTDDI_VERSION < NTDDI_VISTA
james@1007 90 NdisGetNextBuffer(pi->curr_mdl, &pi->curr_mdl);
james@1007 91 #else
james@1007 92 NdisGetNextMdl(pi->curr_mdl, &pi->curr_mdl);
james@1007 93 #endif
james@1007 94 if (pi->curr_pb)
james@1007 95 pi->curr_pb = pi->curr_pb->next;
james@1007 96 pi->curr_mdl_offset = 0;
james@1007 97 }
james@1007 98 }
james@1007 99 //KdPrint((__DRIVER_NAME " C bytes_remaining = %d, pi->curr_mdl = %p\n", bytes_remaining, pi->curr_mdl));
james@1007 100 if (bytes_remaining) {
james@1007 101 //KdPrint((__DRIVER_NAME " bytes_remaining\n"));
james@1007 102 //FUNCTION_EXIT();
james@1007 103 return FALSE;
james@1007 104 }
james@1007 105 //FUNCTION_EXIT();
james@1007 106 return TRUE;
james@1007 107 }
james@1007 108
james@1007 109 VOID
james@1007 110 XenNet_ParsePacketHeader(packet_info_t *pi, PUCHAR alt_buffer, ULONG min_header_size)
james@1007 111 {
james@1007 112 //FUNCTION_ENTER();
james@1007 113
james@1023 114 XN_ASSERT(pi->first_mdl);
james@1007 115
james@1007 116 #if NTDDI_VERSION < NTDDI_VISTA
james@1007 117 NdisQueryBufferSafe(pi->first_mdl, (PVOID)&pi->first_mdl_virtual, &pi->first_mdl_length, NormalPagePriority);
james@1007 118 #else
james@1007 119 NdisQueryMdl(pi->first_mdl, (PVOID)&pi->first_mdl_virtual, &pi->first_mdl_length, NormalPagePriority);
james@1007 120 #endif
james@1007 121 pi->curr_mdl = pi->first_mdl;
james@1007 122 if (alt_buffer)
james@1007 123 pi->header = alt_buffer;
james@1007 124 else
james@1007 125 pi->header = pi->first_mdl_virtual;
james@1007 126
james@1007 127 pi->header_length = 0;
james@1007 128 pi->curr_mdl_offset = pi->first_mdl_offset;
james@1033 129
james@1033 130 pi->ip_proto = 0;
james@1033 131 pi->ip_version = 0;
james@1033 132 pi->ip4_header_length = 0;
james@1033 133 pi->ip4_length = 0;
james@1033 134 pi->tcp_header_length = 0;
james@1033 135 pi->tcp_length = 0;
james@1033 136 pi->split_required = 0;
james@1007 137
james@1007 138 XenNet_BuildHeader(pi, NULL, min_header_size);
james@1007 139
james@1033 140 if (!XenNet_BuildHeader(pi, NULL, (ULONG)XN_HDR_SIZE)) {
james@1007 141 //KdPrint((__DRIVER_NAME " packet too small (Ethernet Header)\n"));
james@1007 142 pi->parse_result = PARSE_TOO_SMALL;
james@1007 143 return;
james@1007 144 }
james@1007 145
james@1007 146 if (pi->header[0] == 0xFF && pi->header[1] == 0xFF
james@1007 147 && pi->header[2] == 0xFF && pi->header[3] == 0xFF
james@1033 148 && pi->header[4] == 0xFF && pi->header[5] == 0xFF) {
james@1007 149 pi->is_broadcast = TRUE;
james@1033 150 } else if (pi->header[0] & 0x01) {
james@1007 151 pi->is_multicast = TRUE;
james@1007 152 }
james@1007 153
james@1033 154 switch (GET_NET_PUSHORT(&pi->header[12])) { // L2 protocol field
james@1007 155 case 0x0800: /* IPv4 */
james@1007 156 //KdPrint((__DRIVER_NAME " IP\n"));
james@1033 157 if (pi->header_length < (ULONG)(XN_HDR_SIZE + 20)) {
james@1033 158 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + 20))) {
james@1065 159 FUNCTION_MSG("packet too small (IP Header)\n");
james@1007 160 pi->parse_result = PARSE_TOO_SMALL;
james@1007 161 return;
james@1007 162 }
james@1007 163 }
james@1007 164 pi->ip_version = (pi->header[XN_HDR_SIZE + 0] & 0xF0) >> 4;
james@1033 165 if (pi->ip_version != 4) {
james@1007 166 //KdPrint((__DRIVER_NAME " ip_version = %d\n", pi->ip_version));
james@1007 167 pi->parse_result = PARSE_UNKNOWN_TYPE;
james@1007 168 return;
james@1007 169 }
james@1007 170 pi->ip4_header_length = (pi->header[XN_HDR_SIZE + 0] & 0x0F) << 2;
james@1033 171 if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20)) {
james@1033 172 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20))) {
james@1007 173 //KdPrint((__DRIVER_NAME " packet too small (IP Header + IP Options + TCP Header)\n"));
james@1007 174 pi->parse_result = PARSE_TOO_SMALL;
james@1007 175 return;
james@1007 176 }
james@1007 177 }
james@1007 178 break;
james@1007 179 case 0x86DD: /* IPv6 */
james@1007 180 //KdPrint((__DRIVER_NAME " IPv6\n"));
james@1007 181 //KdPrint((__DRIVER_NAME " (not currently used)\n"));
james@1007 182 pi->parse_result = PARSE_UNKNOWN_TYPE;
james@1007 183 return;
james@1007 184 default:
james@1007 185 //KdPrint((__DRIVER_NAME " Not IP (%04x)\n", GET_NET_PUSHORT(&pi->header[12])));
james@1007 186 pi->parse_result = PARSE_UNKNOWN_TYPE;
james@1007 187 return;
james@1007 188 }
james@1007 189 pi->ip_proto = pi->header[XN_HDR_SIZE + 9];
james@1007 190 pi->ip4_length = GET_NET_PUSHORT(&pi->header[XN_HDR_SIZE + 2]);
james@1007 191 pi->ip_has_options = (BOOLEAN)(pi->ip4_header_length > 20);
james@1033 192 switch (pi->ip_proto) {
james@1007 193 case 6: // TCP
james@1007 194 case 17: // UDP
james@1007 195 break;
james@1007 196 default:
james@1007 197 //KdPrint((__DRIVER_NAME " Not TCP/UDP (%d)\n", pi->ip_proto));
james@1007 198 pi->parse_result = PARSE_UNKNOWN_TYPE;
james@1007 199 return;
james@1007 200 }
james@1007 201 pi->tcp_header_length = (pi->header[XN_HDR_SIZE + pi->ip4_header_length + 12] & 0xf0) >> 2;
james@1007 202
james@1033 203 if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length)) {
james@1007 204 /* we don't actually need the tcp options to analyse the header */
james@1033 205 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + MIN_TCP_HEADER_LENGTH))) {
james@1007 206 //KdPrint((__DRIVER_NAME " packet too small (IP Header + IP Options + TCP Header (not including TCP Options))\n"));
james@1007 207 pi->parse_result = PARSE_TOO_SMALL;
james@1007 208 return;
james@1007 209 }
james@1007 210 }
james@1007 211
james@1033 212 if ((ULONG)XN_HDR_SIZE + pi->ip4_length > pi->total_length) {
james@1007 213 //KdPrint((__DRIVER_NAME " XN_HDR_SIZE + ip4_length (%d) > total_length (%d)\n", XN_HDR_SIZE + pi->ip4_length, pi->total_length));
james@1007 214 pi->parse_result = PARSE_UNKNOWN_TYPE;
james@1007 215 return;
james@1007 216 }
james@1007 217
james@1007 218 pi->tcp_length = pi->ip4_length - pi->ip4_header_length - pi->tcp_header_length;
james@1007 219 pi->tcp_remaining = pi->tcp_length;
james@1007 220 pi->tcp_seq = GET_NET_PULONG(&pi->header[XN_HDR_SIZE + pi->ip4_header_length + 4]);
james@1007 221 pi->tcp_has_options = (BOOLEAN)(pi->tcp_header_length > 20);
james@1007 222 if (pi->mss > 0 && pi->tcp_length > pi->mss)
james@1007 223 pi->split_required = TRUE;
james@1007 224
james@1007 225 //KdPrint((__DRIVER_NAME " ip4_length = %d\n", pi->ip4_length));
james@1007 226 //KdPrint((__DRIVER_NAME " tcp_length = %d\n", pi->tcp_length));
james@1007 227 //FUNCTION_EXIT();
james@1007 228
james@1007 229 pi->parse_result = PARSE_OK;
james@1007 230 }
james@1007 231
james@1007 232 BOOLEAN
james@1007 233 XenNet_CheckIpHeaderSum(PUCHAR header, USHORT ip4_header_length) {
james@1007 234 ULONG csum = 0;
james@1007 235 USHORT i;
james@1007 236
james@1023 237 XN_ASSERT(ip4_header_length > 12);
james@1023 238 XN_ASSERT(!(ip4_header_length & 1));
james@1007 239
james@1007 240 for (i = 0; i < ip4_header_length; i += 2) {
james@1007 241 csum += GET_NET_PUSHORT(&header[XN_HDR_SIZE + i]);
james@1007 242 }
james@1007 243 while (csum & 0xFFFF0000)
james@1007 244 csum = (csum & 0xFFFF) + (csum >> 16);
james@1007 245 return (BOOLEAN)(csum == 0xFFFF);
james@1007 246 }
james@1007 247
james@1007 248 VOID
james@1007 249 XenNet_SumIpHeader(PUCHAR header, USHORT ip4_header_length) {
james@1007 250 ULONG csum = 0;
james@1007 251 USHORT i;
james@1007 252
james@1023 253 XN_ASSERT(ip4_header_length > 12);
james@1023 254 XN_ASSERT(!(ip4_header_length & 1));
james@1007 255
james@1007 256 header[XN_HDR_SIZE + 10] = 0;
james@1007 257 header[XN_HDR_SIZE + 11] = 0;
james@1007 258 for (i = 0; i < ip4_header_length; i += 2) {
james@1007 259 csum += GET_NET_PUSHORT(&header[XN_HDR_SIZE + i]);
james@1007 260 }
james@1007 261 while (csum & 0xFFFF0000)
james@1007 262 csum = (csum & 0xFFFF) + (csum >> 16);
james@1007 263 csum = ~csum;
james@1007 264 SET_NET_USHORT(&header[XN_HDR_SIZE + 10], (USHORT)csum);
james@1007 265 }
james@1007 266
james@1007 267 BOOLEAN
james@1007 268 XenNet_FilterAcceptPacket(struct xennet_info *xi,packet_info_t *pi)
james@1007 269 {
james@1007 270 ULONG i;
james@1007 271 BOOLEAN is_my_multicast = FALSE;
james@1007 272 BOOLEAN is_directed = FALSE;
james@1007 273
james@1007 274 if (memcmp(xi->curr_mac_addr, pi->header, ETH_ALEN) == 0)
james@1007 275 {
james@1007 276 is_directed = TRUE;
james@1007 277 }
james@1007 278 else if (pi->is_multicast)
james@1007 279 {
james@1007 280 for (i = 0; i < xi->multicast_list_size; i++)
james@1007 281 {
james@1007 282 if (memcmp(xi->multicast_list[i], pi->header, 6) == 0)
james@1007 283 break;
james@1007 284 }
james@1007 285 if (i < xi->multicast_list_size)
james@1007 286 {
james@1007 287 is_my_multicast = TRUE;
james@1007 288 }
james@1007 289 }
james@1007 290 if (is_directed && (xi->packet_filter & NDIS_PACKET_TYPE_DIRECTED))
james@1007 291 {
james@1007 292 return TRUE;
james@1007 293 }
james@1007 294 if (is_my_multicast && (xi->packet_filter & NDIS_PACKET_TYPE_MULTICAST))
james@1007 295 {
james@1007 296 return TRUE;
james@1007 297 }
james@1007 298 if (pi->is_multicast && (xi->packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST))
james@1007 299 {
james@1007 300 return TRUE;
james@1007 301 }
james@1007 302 if (pi->is_broadcast && (xi->packet_filter & NDIS_PACKET_TYPE_BROADCAST))
james@1007 303 {
james@1007 304 return TRUE;
james@1007 305 }
james@1007 306 if (xi->packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS)
james@1007 307 {
james@1007 308 return TRUE;
james@1007 309 }
james@1007 310 //return TRUE;
james@1007 311 return FALSE;
james@1007 312 }
james@1007 313
james@1007 314 static VOID
james@1007 315 XenNet_RxTxDpc(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
james@1007 316 {
james@1007 317 struct xennet_info *xi = context;
james@1007 318 BOOLEAN dont_set_event;
james@1007 319
james@1007 320 UNREFERENCED_PARAMETER(dpc);
james@1007 321 UNREFERENCED_PARAMETER(arg1);
james@1007 322 UNREFERENCED_PARAMETER(arg2);
james@1007 323
james@1007 324 //FUNCTION_ENTER();
james@1007 325 /* if Rx goes over its per-dpc quota then make sure TxBufferGC doesn't set an event as we are already guaranteed to be called again */
james@1007 326 dont_set_event = XenNet_RxBufferCheck(xi);
james@1007 327 XenNet_TxBufferGC(xi, dont_set_event);
james@1007 328 //FUNCTION_EXIT();
james@1007 329 }
james@1007 330
james@1007 331 static BOOLEAN
james@1007 332 XenNet_HandleEvent_DIRQL(PVOID context)
james@1007 333 {
james@1007 334 struct xennet_info *xi = context;
james@1007 335 //ULONG suspend_resume_state_pdo;
james@1007 336
james@1007 337 //FUNCTION_ENTER();
james@1007 338 if (xi->device_state == DEVICE_STATE_ACTIVE || xi->device_state == DEVICE_STATE_DISCONNECTING) {
james@1007 339 KeInsertQueueDpc(&xi->rxtx_dpc, NULL, NULL);
james@1007 340 }
james@1007 341 //FUNCTION_EXIT();
james@1007 342 return TRUE;
james@1007 343 }
james@1007 344
james@1007 345 NTSTATUS
james@1007 346 XenNet_Connect(PVOID context, BOOLEAN suspend) {
james@1007 347 NTSTATUS status;
james@1007 348 struct xennet_info *xi = context;
james@1007 349 PFN_NUMBER pfn;
james@1007 350 ULONG qemu_hide_filter;
james@1007 351 ULONG qemu_hide_flags_value;
james@1007 352 int i;
james@1007 353 ULONG state;
james@1007 354 ULONG octet;
james@1007 355 PCHAR tmp_string;
james@1007 356 ULONG tmp_ulong;
james@1052 357 LARGE_INTEGER timeout;
james@1007 358
james@1007 359 if (!suspend) {
james@1007 360 xi->handle = XnOpenDevice(xi->pdo, XenNet_DeviceCallback, xi);
james@1007 361 }
james@1007 362 if (!xi->handle) {
james@1007 363 FUNCTION_MSG("Cannot open Xen device\n");
james@1007 364 return STATUS_UNSUCCESSFUL;
james@1007 365 }
james@1007 366 XnGetValue(xi->handle, XN_VALUE_TYPE_QEMU_HIDE_FLAGS, &qemu_hide_flags_value);
james@1007 367 XnGetValue(xi->handle, XN_VALUE_TYPE_QEMU_FILTER, &qemu_hide_filter);
james@1007 368 if (!(qemu_hide_flags_value & QEMU_UNPLUG_ALL_NICS) || qemu_hide_filter) {
james@1007 369 FUNCTION_MSG("inactive\n");
james@1007 370 xi->device_state = DEVICE_STATE_INACTIVE;
james@1007 371 /* continue with setup so all the flags and capabilities are correct */
james@1007 372 }
james@1007 373
james@1017 374 if (xi->device_state != DEVICE_STATE_INACTIVE) {
james@1017 375 for (i = 0; i <= 5 && xi->backend_state != XenbusStateInitialising && xi->backend_state != XenbusStateInitWait && xi->backend_state != XenbusStateInitialised; i++) {
james@1017 376 FUNCTION_MSG("Waiting for XenbusStateInitXxx\n");
james@1017 377 if (xi->backend_state == XenbusStateClosed) {
james@1017 378 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "state", XenbusStateInitialising);
james@1017 379 }
james@1052 380 timeout.QuadPart = -10 * 1000 * 1000; /* 1 second */
james@1052 381 KeWaitForSingleObject(&xi->backend_event, Executive, KernelMode, FALSE, &timeout);
james@1017 382 }
james@1017 383 if (xi->backend_state != XenbusStateInitialising && xi->backend_state != XenbusStateInitWait && xi->backend_state != XenbusStateInitialised) {
james@1017 384 FUNCTION_MSG("Backend state timeout\n");
james@1017 385 return STATUS_UNSUCCESSFUL;
james@1017 386 }
james@1017 387 if (!NT_SUCCESS(status = XnBindEvent(xi->handle, &xi->event_channel, XenNet_HandleEvent_DIRQL, xi))) {
james@1017 388 FUNCTION_MSG("Cannot allocate event channel\n");
james@1017 389 return STATUS_UNSUCCESSFUL;
james@1017 390 }
james@1017 391 FUNCTION_MSG("event_channel = %d\n", xi->event_channel);
james@1017 392 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "event-channel", xi->event_channel);
james@1017 393 xi->tx_sring = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENNET_POOL_TAG);
james@1017 394 if (!xi->tx_sring) {
james@1017 395 FUNCTION_MSG("Cannot allocate tx_sring\n");
james@1017 396 return STATUS_UNSUCCESSFUL;
james@1017 397 }
james@1017 398 SHARED_RING_INIT(xi->tx_sring);
james@1017 399 FRONT_RING_INIT(&xi->tx_ring, xi->tx_sring, PAGE_SIZE);
james@1017 400 pfn = (PFN_NUMBER)(MmGetPhysicalAddress(xi->tx_sring).QuadPart >> PAGE_SHIFT);
james@1017 401 FUNCTION_MSG("tx sring pfn = %d\n", (ULONG)pfn);
james@1017 402 xi->tx_sring_gref = XnGrantAccess(xi->handle, (ULONG)pfn, FALSE, INVALID_GRANT_REF, XENNET_POOL_TAG);
james@1017 403 FUNCTION_MSG("tx sring_gref = %d\n", xi->tx_sring_gref);
james@1017 404 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "tx-ring-ref", xi->tx_sring_gref);
james@1017 405 xi->rx_sring = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENNET_POOL_TAG);
james@1017 406 if (!xi->rx_sring) {
james@1017 407 FUNCTION_MSG("Cannot allocate rx_sring\n");
james@1017 408 return STATUS_UNSUCCESSFUL;
james@1017 409 }
james@1017 410 SHARED_RING_INIT(xi->rx_sring);
james@1017 411 FRONT_RING_INIT(&xi->rx_ring, xi->rx_sring, PAGE_SIZE);
james@1017 412 pfn = (PFN_NUMBER)(MmGetPhysicalAddress(xi->rx_sring).QuadPart >> PAGE_SHIFT);
james@1017 413 FUNCTION_MSG("rx sring pfn = %d\n", (ULONG)pfn);
james@1017 414 xi->rx_sring_gref = XnGrantAccess(xi->handle, (ULONG)pfn, FALSE, INVALID_GRANT_REF, XENNET_POOL_TAG);
james@1017 415 FUNCTION_MSG("rx sring_gref = %d\n", xi->rx_sring_gref);
james@1017 416 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "rx-ring-ref", xi->rx_sring_gref);
james@1017 417
james@1017 418 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "request-rx-copy", 1);
james@1017 419 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "request-rx-notify", 1);
james@1017 420 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "feature-no-csum-offload", !xi->frontend_csum_supported);
james@1017 421 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "feature-sg", (int)xi->frontend_sg_supported);
james@1017 422 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "feature-gso-tcpv4", !!xi->frontend_gso_value);
james@1007 423 }
james@1007 424 status = XnReadInt32(xi->handle, XN_BASE_BACKEND, "feature-sg", &tmp_ulong);
james@1007 425 if (tmp_ulong) {
james@1007 426 xi->backend_sg_supported = TRUE;
james@1007 427 }
james@1007 428 status = XnReadInt32(xi->handle, XN_BASE_BACKEND, "feature-gso-tcpv4", &tmp_ulong);
james@1007 429 if (tmp_ulong) {
james@1007 430 xi->backend_gso_value = xi->frontend_gso_value;
james@1007 431 }
james@1007 432
james@1007 433 status = XnReadString(xi->handle, XN_BASE_BACKEND, "mac", &tmp_string);
james@1007 434 state = 0;
james@1007 435 octet = 0;
james@1007 436 for (i = 0; state != 3 && i < (int)strlen(tmp_string); i++) {
james@1007 437 if (octet == 6) {
james@1007 438 state = 3;
james@1007 439 break;
james@1007 440 }
james@1007 441 switch(state) {
james@1007 442 case 0:
james@1007 443 case 1:
james@1007 444 if (tmp_string[i] >= '0' && tmp_string[i] <= '9') {
james@1007 445 xi->perm_mac_addr[octet] |= (tmp_string[i] - '0') << ((1 - state) * 4);
james@1007 446 state++;
james@1007 447 } else if (tmp_string[i] >= 'A' && tmp_string[i] <= 'F') {
james@1007 448 xi->perm_mac_addr[octet] |= (tmp_string[i] - 'A' + 10) << ((1 - state) * 4);
james@1007 449 state++;
james@1007 450 } else if (tmp_string[i] >= 'a' && tmp_string[i] <= 'f') {
james@1007 451 xi->perm_mac_addr[octet] |= (tmp_string[i] - 'a' + 10) << ((1 - state) * 4);
james@1007 452 state++;
james@1007 453 } else {
james@1007 454 state = 3;
james@1007 455 }
james@1007 456 break;
james@1007 457 case 2:
james@1007 458 if (tmp_string[i] == ':') {
james@1007 459 octet++;
james@1007 460 state = 0;
james@1007 461 } else {
james@1007 462 state = 3;
james@1007 463 }
james@1007 464 break;
james@1007 465 }
james@1007 466 }
james@1007 467 if (octet != 5 || state != 2) {
james@1007 468 FUNCTION_MSG("Failed to parse backend MAC address %s\n", tmp_string);
james@1007 469 XnFreeMem(xi->handle, tmp_string);
james@1007 470 return STATUS_UNSUCCESSFUL;
james@1007 471 } else if ((xi->curr_mac_addr[0] & 0x03) != 0x02) {
james@1007 472 /* only copy if curr_mac_addr is not a LUA */
james@1007 473 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
james@1007 474 }
james@1007 475 XnFreeMem(xi->handle, tmp_string);
james@1007 476 FUNCTION_MSG("MAC address is %02X:%02X:%02X:%02X:%02X:%02X\n",
james@1007 477 xi->curr_mac_addr[0], xi->curr_mac_addr[1], xi->curr_mac_addr[2],
james@1007 478 xi->curr_mac_addr[3], xi->curr_mac_addr[4], xi->curr_mac_addr[5]);
james@1007 479
james@1017 480 if (xi->device_state != DEVICE_STATE_INACTIVE) {
james@1017 481 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "state", XenbusStateConnected);
james@1007 482
james@1017 483 for (i = 0; i <= 5 && xi->backend_state != XenbusStateConnected; i++) {
james@1017 484 FUNCTION_MSG("Waiting for XenbusStateConnected\n");
james@1052 485 timeout.QuadPart = -10 * 1000 * 1000; /* 1 second */
james@1052 486 KeWaitForSingleObject(&xi->backend_event, Executive, KernelMode, FALSE, &timeout);
james@1017 487 }
james@1017 488 if (xi->backend_state != XenbusStateConnected) {
james@1017 489 FUNCTION_MSG("Backend state timeout\n");
james@1017 490 return STATUS_UNSUCCESSFUL;
james@1017 491 }
james@1017 492 XenNet_TxInit(xi);
james@1017 493 XenNet_RxInit(xi);
james@1007 494 }
james@1007 495
james@1007 496 /* we don't set device_state = DEVICE_STATE_ACTIVE here - has to be done during init once ndis is ready */
james@1007 497
james@1007 498 return STATUS_SUCCESS;
james@1007 499 }
james@1007 500
james@1007 501 NTSTATUS
james@1007 502 XenNet_Disconnect(PVOID context, BOOLEAN suspend) {
james@1007 503 struct xennet_info *xi = (struct xennet_info *)context;
james@1007 504 //PFN_NUMBER pfn;
james@1052 505 LARGE_INTEGER timeout;
james@1007 506 NTSTATUS status;
james@1007 507
james@1017 508 if (xi->device_state != DEVICE_STATE_ACTIVE && xi->device_state != DEVICE_STATE_INACTIVE) {
james@1017 509 FUNCTION_MSG("state not DEVICE_STATE_(IN)ACTIVE, is %d instead\n", xi->device_state);
james@1007 510 FUNCTION_EXIT();
james@1007 511 return STATUS_SUCCESS;
james@1007 512 }
james@1017 513 if (xi->device_state != DEVICE_STATE_INACTIVE) {
james@1017 514 xi->device_state = DEVICE_STATE_DISCONNECTING;
james@1017 515 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "state", XenbusStateClosing);
james@1017 516 while (xi->backend_state != XenbusStateClosing && xi->backend_state != XenbusStateClosed) {
james@1017 517 FUNCTION_MSG("Waiting for XenbusStateClosing/Closed\n");
james@1052 518 timeout.QuadPart = -10 * 1000 * 1000; /* 1 second */
james@1052 519 KeWaitForSingleObject(&xi->backend_event, Executive, KernelMode, FALSE, &timeout);
james@1017 520 }
james@1017 521 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "state", XenbusStateClosed);
james@1017 522 while (xi->backend_state != XenbusStateClosed) {
james@1017 523 FUNCTION_MSG("Waiting for XenbusStateClosed\n");
james@1052 524 timeout.QuadPart = -10 * 1000 * 1000; /* 1 second */
james@1052 525 KeWaitForSingleObject(&xi->backend_event, Executive, KernelMode, FALSE, &timeout);
james@1017 526 }
james@1017 527 XnUnbindEvent(xi->handle, xi->event_channel);
james@1017 528
james@1017 529 #if NTDDI_VERSION < WINXP
james@1017 530 KeFlushQueuedDpcs();
james@1017 531 #endif
james@1017 532 XenNet_TxShutdown(xi);
james@1017 533 XenNet_RxShutdown(xi);
james@1017 534 XnEndAccess(xi->handle, xi->rx_sring_gref, FALSE, XENNET_POOL_TAG);
james@1017 535 ExFreePoolWithTag(xi->rx_sring, XENNET_POOL_TAG);
james@1017 536 XnEndAccess(xi->handle, xi->tx_sring_gref, FALSE, XENNET_POOL_TAG);
james@1017 537 ExFreePoolWithTag(xi->tx_sring, XENNET_POOL_TAG);
james@1007 538 }
james@1007 539 if (!suspend) {
james@1007 540 XnCloseDevice(xi->handle);
james@1007 541 }
james@1007 542 xi->device_state = DEVICE_STATE_DISCONNECTED;
james@1007 543 return STATUS_SUCCESS;
james@1011 544 }
james@1007 545
james@1007 546 VOID
james@1007 547 XenNet_DeviceCallback(PVOID context, ULONG callback_type, PVOID value) {
james@1007 548 struct xennet_info *xi = (struct xennet_info *)context;
james@1007 549 ULONG state;
james@1052 550 NTSTATUS status;
james@1007 551
james@1007 552 FUNCTION_ENTER();
james@1007 553 switch (callback_type) {
james@1007 554 case XN_DEVICE_CALLBACK_BACKEND_STATE:
james@1007 555 state = (ULONG)(ULONG_PTR)value;
james@1007 556 if (state == xi->backend_state) {
james@1007 557 FUNCTION_MSG("same state %d\n", state);
james@1007 558 FUNCTION_EXIT();
james@1007 559 }
james@1007 560 FUNCTION_MSG("XenBusState = %d -> %d\n", xi->backend_state, state);
james@1007 561 xi->backend_state = state;
james@1007 562 KeSetEvent(&xi->backend_event, 0, FALSE);
james@1007 563 break;
james@1007 564 case XN_DEVICE_CALLBACK_SUSPEND:
james@1007 565 FUNCTION_MSG("XN_DEVICE_CALLBACK_SUSPEND");
james@1007 566 XenNet_Disconnect(xi, TRUE);
james@1007 567 break;
james@1007 568 case XN_DEVICE_CALLBACK_RESUME:
james@1007 569 FUNCTION_MSG("XN_DEVICE_CALLBACK_RESUME");
james@1017 570 xi->device_state = DEVICE_STATE_INITIALISING;
james@1052 571 status = XenNet_Connect(xi, TRUE);
james@1052 572 // TODO: what to do here if not success?
james@1017 573 if (xi->device_state != DEVICE_STATE_INACTIVE) {
james@1017 574 xi->device_state = DEVICE_STATE_ACTIVE;
james@1017 575 }
james@1007 576 KeInsertQueueDpc(&xi->rxtx_dpc, NULL, NULL);
james@1007 577 break;
james@1007 578 }
james@1007 579 FUNCTION_EXIT();
james@1007 580 }
james@1007 581