win-pvdrivers

changeset 916:4b5290b0bcd9

First attempt at NDIS6 driver. Very slow due to lots of debugging output and no offload, and will probably crash if you do anything more than a ping or two
author James Harper <james.harper@bendigoit.com.au>
date Mon May 02 00:17:33 2011 +1000 (2011-05-02)
parents a8a03b07dcfc
children 7321f245acc6
files xennet/xennet6.c xennet/xennet6.h xennet/xennet6_common.c xennet/xennet6_oid.c xennet/xennet6_rx.c xennet/xennet6_tx.c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xennet/xennet6.c	Mon May 02 00:17:33 2011 +1000
     1.3 @@ -0,0 +1,1112 @@
     1.4 +/*
     1.5 +PV Net Driver for Windows Xen HVM Domains
     1.6 +Copyright (C) 2007 James Harper
     1.7 +Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
     1.8 +
     1.9 +This program is free software; you can redistribute it and/or
    1.10 +modify it under the terms of the GNU General Public License
    1.11 +as published by the Free Software Foundation; either version 2
    1.12 +of the License, or (at your option) any later version.
    1.13 +
    1.14 +This program is distributed in the hope that it will be useful,
    1.15 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.16 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.17 +GNU General Public License for more details.
    1.18 +
    1.19 +You should have received a copy of the GNU General Public License
    1.20 +along with this program; if not, write to the Free Software
    1.21 +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    1.22 +*/
    1.23 +
    1.24 +#include <stdlib.h>
    1.25 +#include <io/xenbus.h>
    1.26 +#include "xennet6.h"
    1.27 +
    1.28 +/* Not really necessary but keeps PREfast happy */
    1.29 +DRIVER_INITIALIZE DriverEntry;
    1.30 +static IO_WORKITEM_ROUTINE XenNet_ResumeWorkItem;
    1.31 +#if (VER_PRODUCTBUILD >= 7600)
    1.32 +static KDEFERRED_ROUTINE XenNet_SuspendResume;
    1.33 +#endif
    1.34 +
    1.35 +#pragma NDIS_INIT_FUNCTION(DriverEntry)
    1.36 +
    1.37 +NDIS_HANDLE driver_handle = NULL;
    1.38 +
    1.39 +/* ----- BEGIN Other people's code --------- */
    1.40 +/* from linux/include/linux/ctype.h, used under GPLv2 */
    1.41 +#define _U      0x01    /* upper */
    1.42 +#define _L      0x02    /* lower */
    1.43 +#define _D      0x04    /* digit */
    1.44 +#define _C      0x08    /* cntrl */
    1.45 +#define _P      0x10    /* punct */
    1.46 +#define _S      0x20    /* white space (space/lf/tab) */
    1.47 +#define _X      0x40    /* hex digit */
    1.48 +#define _SP     0x80    /* hard space (0x20) */
    1.49 +
    1.50 +/* from linux/include/lib/ctype.c, used under GPLv2 */
    1.51 +unsigned char _ctype[] = {
    1.52 +_C,_C,_C,_C,_C,_C,_C,_C,                        /* 0-7 */
    1.53 +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,         /* 8-15 */
    1.54 +_C,_C,_C,_C,_C,_C,_C,_C,                        /* 16-23 */
    1.55 +_C,_C,_C,_C,_C,_C,_C,_C,                        /* 24-31 */
    1.56 +_S|_SP,_P,_P,_P,_P,_P,_P,_P,                    /* 32-39 */
    1.57 +_P,_P,_P,_P,_P,_P,_P,_P,                        /* 40-47 */
    1.58 +_D,_D,_D,_D,_D,_D,_D,_D,                        /* 48-55 */
    1.59 +_D,_D,_P,_P,_P,_P,_P,_P,                        /* 56-63 */
    1.60 +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,      /* 64-71 */
    1.61 +_U,_U,_U,_U,_U,_U,_U,_U,                        /* 72-79 */
    1.62 +_U,_U,_U,_U,_U,_U,_U,_U,                        /* 80-87 */
    1.63 +_U,_U,_U,_P,_P,_P,_P,_P,                        /* 88-95 */
    1.64 +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,      /* 96-103 */
    1.65 +_L,_L,_L,_L,_L,_L,_L,_L,                        /* 104-111 */
    1.66 +_L,_L,_L,_L,_L,_L,_L,_L,                        /* 112-119 */
    1.67 +_L,_L,_L,_P,_P,_P,_P,_C,                        /* 120-127 */
    1.68 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                /* 128-143 */
    1.69 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                /* 144-159 */
    1.70 +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
    1.71 +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
    1.72 +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
    1.73 +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
    1.74 +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
    1.75 +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
    1.76 +
    1.77 +/* from linux/include/linux/ctype.h, used under GPLv2 */
    1.78 +#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
    1.79 +
    1.80 +#define isalnum(c)      ((__ismask(c)&(_U|_L|_D)) != 0)
    1.81 +#define isalpha(c)      ((__ismask(c)&(_U|_L)) != 0)
    1.82 +#define iscntrl(c)      ((__ismask(c)&(_C)) != 0)
    1.83 +#define isdigit(c)      ((__ismask(c)&(_D)) != 0)
    1.84 +#define isgraph(c)      ((__ismask(c)&(_P|_U|_L|_D)) != 0)
    1.85 +#define islower(c)      ((__ismask(c)&(_L)) != 0)
    1.86 +#define isprint(c)      ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
    1.87 +#define ispunct(c)      ((__ismask(c)&(_P)) != 0)
    1.88 +#define isspace(c)      ((__ismask(c)&(_S)) != 0)
    1.89 +#define isupper(c)      ((__ismask(c)&(_U)) != 0)
    1.90 +#define isxdigit(c)     ((__ismask(c)&(_D|_X)) != 0)
    1.91 +
    1.92 +#define TOLOWER(x) ((x) | 0x20)
    1.93 +
    1.94 +/* from linux/lib/vsprintf.c, used under GPLv2 */
    1.95 +/* Copyright (C) 1991, 1992  Linus Torvalds
    1.96 + * Wirzenius wrote this portably, Torvalds fucked it up :-)
    1.97 + */
    1.98 +/**
    1.99 + * simple_strtoul - convert a string to an unsigned long
   1.100 + * @cp: The start of the string
   1.101 + * @endp: A pointer to the end of the parsed string will be placed here
   1.102 + * @base: The number base to use
   1.103 + */
   1.104 +unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
   1.105 +{
   1.106 +  unsigned long result = 0,value;
   1.107 +
   1.108 +  if (!base) {
   1.109 +    base = 10;
   1.110 +    if (*cp == '0') {
   1.111 +      base = 8;
   1.112 +      cp++;
   1.113 +      if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
   1.114 +        cp++;
   1.115 +        base = 16;
   1.116 +      }
   1.117 +    }
   1.118 +  } else if (base == 16) {
   1.119 +    if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
   1.120 +      cp += 2;
   1.121 +  }
   1.122 +  while (isxdigit(*cp) &&
   1.123 +    (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
   1.124 +    result = result*base + value;
   1.125 +    cp++;
   1.126 +  }
   1.127 +  if (endp)
   1.128 +    *endp = (char *)cp;
   1.129 +  return result;
   1.130 +}
   1.131 +/* end vsprintf.c code */
   1.132 +/* ----- END Other people's code --------- */
   1.133 +
   1.134 +static NDIS_STATUS
   1.135 +XenNet_ConnectBackend(struct xennet_info *xi)
   1.136 +{
   1.137 +  PUCHAR ptr;
   1.138 +  UCHAR type;
   1.139 +  PCHAR setting, value, value2;
   1.140 +  UINT i;
   1.141 +  ULONG backend_sg = 0;
   1.142 +  ULONG backend_gso = 0;
   1.143 +
   1.144 +  FUNCTION_ENTER();
   1.145 +  
   1.146 +  ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
   1.147 +
   1.148 +  ptr = xi->config_page;
   1.149 +  while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
   1.150 +  {
   1.151 +    switch(type)
   1.152 +    {
   1.153 +    case XEN_INIT_TYPE_RING: /* frontend ring */
   1.154 +      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_RING - %s = %p\n", setting, value));
   1.155 +      if (strcmp(setting, "tx-ring-ref") == 0)
   1.156 +      {
   1.157 +        FRONT_RING_INIT(&xi->tx, (netif_tx_sring_t *)value, PAGE_SIZE);
   1.158 +      } else if (strcmp(setting, "rx-ring-ref") == 0)
   1.159 +      {
   1.160 +        FRONT_RING_INIT(&xi->rx, (netif_rx_sring_t *)value, PAGE_SIZE);
   1.161 +      }
   1.162 +      break;
   1.163 +    case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
   1.164 +      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, PtrToUlong(value)));
   1.165 +      if (strcmp(setting, "event-channel") == 0)
   1.166 +      {
   1.167 +        xi->event_channel = PtrToUlong(value);
   1.168 +      }
   1.169 +      break;
   1.170 +    case XEN_INIT_TYPE_READ_STRING_FRONT:
   1.171 +      break;
   1.172 +    case XEN_INIT_TYPE_READ_STRING_BACK:
   1.173 +      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
   1.174 +      if (strcmp(setting, "mac") == 0)
   1.175 +      {
   1.176 +        char *s, *e;
   1.177 +        s = value;
   1.178 +        for (i = 0; i < ETH_ALEN; i++) {
   1.179 +          xi->perm_mac_addr[i] = (uint8_t)simple_strtoul(s, &e, 16);
   1.180 +          if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
   1.181 +            KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
   1.182 +          }
   1.183 +          s = e + 1;
   1.184 +        }
   1.185 +        if ((xi->curr_mac_addr[0] & 0x03) != 0x02)
   1.186 +        {
   1.187 +          /* only copy if curr_mac_addr is not a LUA */
   1.188 +          memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
   1.189 +        }
   1.190 +      }
   1.191 +      else if (strcmp(setting, "feature-sg") == 0)
   1.192 +      {
   1.193 +        if (atoi(value))
   1.194 +        {
   1.195 +          backend_sg = 1;
   1.196 +        }
   1.197 +      }
   1.198 +      else if (strcmp(setting, "feature-gso-tcpv4") == 0)
   1.199 +      {
   1.200 +        if (atoi(value))
   1.201 +        {
   1.202 +          backend_gso = 1;
   1.203 +        }
   1.204 +      }
   1.205 +      break;
   1.206 +    case XEN_INIT_TYPE_VECTORS:
   1.207 +      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_VECTORS\n"));
   1.208 +      if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
   1.209 +        ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
   1.210 +      {
   1.211 +        KdPrint((__DRIVER_NAME "     vectors mismatch (magic = %08x, length = %d)\n",
   1.212 +          ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
   1.213 +        FUNCTION_EXIT();
   1.214 +        return NDIS_STATUS_ADAPTER_NOT_FOUND;
   1.215 +      }
   1.216 +      else
   1.217 +        memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
   1.218 +      break;
   1.219 +    case XEN_INIT_TYPE_STATE_PTR:
   1.220 +      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
   1.221 +      xi->device_state = (PXENPCI_DEVICE_STATE)value;
   1.222 +      break;
   1.223 +    default:
   1.224 +      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_%d\n", type));
   1.225 +      break;
   1.226 +    }
   1.227 +  }
   1.228 +  if (xi->config_sg && !backend_sg)
   1.229 +  {
   1.230 +    KdPrint((__DRIVER_NAME "     SG not supported by backend - disabling\n"));
   1.231 +    xi->config_sg = 0;
   1.232 +  }
   1.233 +  if (xi->config_gso && !backend_gso)
   1.234 +  {
   1.235 +    KdPrint((__DRIVER_NAME "     GSO not supported by backend - disabling\n"));
   1.236 +    xi->config_gso = 0;
   1.237 +  }
   1.238 +  FUNCTION_EXIT();
   1.239 +  
   1.240 +  return NDIS_STATUS_SUCCESS;
   1.241 +}
   1.242 +
   1.243 +static VOID
   1.244 +XenNet_ResumeWorkItem(PDEVICE_OBJECT device_object, PVOID context)
   1.245 +{
   1.246 +  struct xennet_info *xi = context;
   1.247 +  KIRQL old_irql;
   1.248 +  
   1.249 +  UNREFERENCED_PARAMETER(device_object);
   1.250 +  
   1.251 +  FUNCTION_ENTER();
   1.252 +
   1.253 +  ASSERT(xi->resume_work_item);
   1.254 +
   1.255 +  IoFreeWorkItem(xi->resume_work_item);
   1.256 +  
   1.257 +  XenNet_TxResumeStart(xi);
   1.258 +  XenNet_RxResumeStart(xi);
   1.259 +  XenNet_ConnectBackend(xi);
   1.260 +  XenNet_RxResumeEnd(xi);
   1.261 +  XenNet_TxResumeEnd(xi);
   1.262 +
   1.263 +  KeAcquireSpinLock(&xi->resume_lock, &old_irql);
   1.264 +  xi->resume_work_item = NULL;
   1.265 +  KdPrint((__DRIVER_NAME "     *Setting suspend_resume_state_fdo = %d\n", xi->device_state->suspend_resume_state_pdo));
   1.266 +  xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
   1.267 +  KdPrint((__DRIVER_NAME "     *Notifying event channel %d\n", xi->device_state->pdo_event_channel));
   1.268 +  xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
   1.269 +  KeReleaseSpinLock(&xi->resume_lock, old_irql);
   1.270 +
   1.271 +  FUNCTION_EXIT();
   1.272 +
   1.273 +}
   1.274 +
   1.275 +static VOID
   1.276 +XenNet_SuspendResume(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
   1.277 +{
   1.278 +  struct xennet_info *xi = context;
   1.279 +  KIRQL old_irql;
   1.280 +  PIO_WORKITEM resume_work_item;
   1.281 +
   1.282 +  UNREFERENCED_PARAMETER(dpc);
   1.283 +  UNREFERENCED_PARAMETER(arg1);
   1.284 +  UNREFERENCED_PARAMETER(arg2);
   1.285 +
   1.286 +  FUNCTION_ENTER();
   1.287 +  
   1.288 +  switch (xi->device_state->suspend_resume_state_pdo)
   1.289 +  {
   1.290 +  case SR_STATE_SUSPENDING:
   1.291 +    KdPrint((__DRIVER_NAME "     New state SUSPENDING\n"));
   1.292 +    KeAcquireSpinLock(&xi->rx_lock, &old_irql);
   1.293 +    if (xi->rx_id_free == NET_RX_RING_SIZE)
   1.294 +    {  
   1.295 +      xi->device_state->suspend_resume_state_fdo = SR_STATE_SUSPENDING;
   1.296 +      KdPrint((__DRIVER_NAME "     Notifying event channel %d\n", xi->device_state->pdo_event_channel));
   1.297 +      xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
   1.298 +    }
   1.299 +    KeReleaseSpinLock(&xi->rx_lock, old_irql);
   1.300 +    break;
   1.301 +  case SR_STATE_RESUMING:
   1.302 +    KdPrint((__DRIVER_NAME "     New state SR_STATE_RESUMING\n"));
   1.303 +    /* do it like this so we don't race and double-free the work item */
   1.304 +    resume_work_item = IoAllocateWorkItem(xi->fdo);
   1.305 +    KeAcquireSpinLock(&xi->resume_lock, &old_irql);
   1.306 +    if (xi->resume_work_item || xi->device_state->suspend_resume_state_fdo == SR_STATE_RESUMING)
   1.307 +    {
   1.308 +      KeReleaseSpinLock(&xi->resume_lock, old_irql);
   1.309 +      IoFreeWorkItem(resume_work_item);
   1.310 +      return;
   1.311 +    }
   1.312 +    xi->resume_work_item = resume_work_item;
   1.313 +    KeReleaseSpinLock(&xi->resume_lock, old_irql);
   1.314 +    IoQueueWorkItem(xi->resume_work_item, XenNet_ResumeWorkItem, DelayedWorkQueue, xi);
   1.315 +    break;
   1.316 +  default:
   1.317 +    KdPrint((__DRIVER_NAME "     New state %d\n", xi->device_state->suspend_resume_state_fdo));
   1.318 +    xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
   1.319 +    KdPrint((__DRIVER_NAME "     Notifying event channel %d\n", xi->device_state->pdo_event_channel));
   1.320 +    xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
   1.321 +    break;
   1.322 +  }
   1.323 +  KeMemoryBarrier();
   1.324 +  
   1.325 +  FUNCTION_EXIT();
   1.326 +}
   1.327 +
   1.328 +static VOID
   1.329 +XenNet_RxTxDpc(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
   1.330 +{
   1.331 +  struct xennet_info *xi = context;
   1.332 +  BOOLEAN dont_set_event;
   1.333 +
   1.334 +  UNREFERENCED_PARAMETER(dpc);
   1.335 +  UNREFERENCED_PARAMETER(arg1);
   1.336 +  UNREFERENCED_PARAMETER(arg2);
   1.337 +
   1.338 +  FUNCTION_ENTER();
   1.339 +  /* 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 */
   1.340 +  dont_set_event = XenNet_RxBufferCheck(xi);
   1.341 +  XenNet_TxBufferGC(xi, dont_set_event);
   1.342 +  FUNCTION_EXIT();
   1.343 +} 
   1.344 +
   1.345 +static BOOLEAN
   1.346 +XenNet_HandleEvent(PVOID context)
   1.347 +{
   1.348 +  struct xennet_info *xi = context;
   1.349 +  ULONG suspend_resume_state_pdo;
   1.350 +  
   1.351 +  //FUNCTION_ENTER();
   1.352 +  suspend_resume_state_pdo = xi->device_state->suspend_resume_state_pdo;
   1.353 +  KeMemoryBarrier();
   1.354 +
   1.355 +  if (!xi->shutting_down && suspend_resume_state_pdo != xi->device_state->suspend_resume_state_fdo)
   1.356 +  {
   1.357 +    KeInsertQueueDpc(&xi->suspend_dpc, NULL, NULL);
   1.358 +  }
   1.359 +  if (xi->connected && !xi->inactive && suspend_resume_state_pdo != SR_STATE_RESUMING)
   1.360 +  {
   1.361 +    KeInsertQueueDpc(&xi->rxtx_dpc, NULL, NULL);
   1.362 +  }
   1.363 +  //FUNCTION_EXIT();
   1.364 +  return TRUE;
   1.365 +}
   1.366 +
   1.367 +#if 0
   1.368 +VOID
   1.369 +XenNet_SetPower(PDEVICE_OBJECT device_object, PVOID context)
   1.370 +{
   1.371 +  NTSTATUS status = STATUS_SUCCESS;
   1.372 +  KIRQL old_irql;
   1.373 +  struct xennet_info *xi = context;
   1.374 +  
   1.375 +  FUNCTION_ENTER();
   1.376 +  UNREFERENCED_PARAMETER(device_object);
   1.377 +
   1.378 +  switch (xi->new_power_state)
   1.379 +  {
   1.380 +  case NdisDeviceStateD0:
   1.381 +    KdPrint(("       NdisDeviceStateD0\n"));
   1.382 +    status = XenNet_D0Entry(xi);
   1.383 +    break;
   1.384 +  case NdisDeviceStateD1:
   1.385 +    KdPrint(("       NdisDeviceStateD1\n"));
   1.386 +    if (xi->power_state == NdisDeviceStateD0)
   1.387 +      status = XenNet_D0Exit(xi);
   1.388 +    break;
   1.389 +  case NdisDeviceStateD2:
   1.390 +    KdPrint(("       NdisDeviceStateD2\n"));
   1.391 +    if (xi->power_state == NdisDeviceStateD0)
   1.392 +      status = XenNet_D0Exit(xi);
   1.393 +    break;
   1.394 +  case NdisDeviceStateD3:
   1.395 +    KdPrint(("       NdisDeviceStateD3\n"));
   1.396 +    if (xi->power_state == NdisDeviceStateD0)
   1.397 +      status = XenNet_D0Exit(xi);
   1.398 +    break;
   1.399 +  default:
   1.400 +    KdPrint(("       NdisDeviceState??\n"));
   1.401 +    status = NDIS_STATUS_NOT_SUPPORTED;
   1.402 +    break;
   1.403 +  }
   1.404 +  xi->power_state = xi->new_power_state;
   1.405 +
   1.406 +  old_irql = KeRaiseIrqlToDpcLevel();
   1.407 +  NdisMSetInformationComplete(xi->adapter_handle, status);
   1.408 +  KeLowerIrql(old_irql);
   1.409 +  
   1.410 +  FUNCTION_EXIT();
   1.411 +}
   1.412 +#endif
   1.413 +
   1.414 +NDIS_STATUS
   1.415 +XenNet_D0Entry(struct xennet_info *xi)
   1.416 +{
   1.417 +  NDIS_STATUS status;
   1.418 +  PUCHAR ptr;
   1.419 +  CHAR buf[128];
   1.420 +  
   1.421 +  FUNCTION_ENTER();
   1.422 +
   1.423 +  xi->shutting_down = FALSE;
   1.424 +  
   1.425 +  ptr = xi->config_page;
   1.426 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "tx-ring-ref", NULL, NULL);
   1.427 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "rx-ring-ref", NULL, NULL);
   1.428 +  #pragma warning(suppress:4054)
   1.429 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL, "event-channel", (PVOID)XenNet_HandleEvent, xi);
   1.430 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mac", NULL, NULL);
   1.431 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-sg", NULL, NULL);
   1.432 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-gso-tcpv4", NULL, NULL);
   1.433 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "request-rx-copy", "1", NULL);
   1.434 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-rx-notify", "1", NULL);
   1.435 +  RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !xi->config_csum);
   1.436 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-no-csum-offload", buf, NULL);
   1.437 +  RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", (int)xi->config_sg);
   1.438 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-sg", buf, NULL);
   1.439 +  RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !!xi->config_gso);
   1.440 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-gso-tcpv4", buf, NULL);
   1.441 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_PRE_CONNECT, NULL, NULL, NULL);
   1.442 +  __ADD_XEN_INIT_UCHAR(&ptr, 0); /* no pre-connect required */
   1.443 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_POST_CONNECT, NULL, NULL, NULL);
   1.444 +  __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
   1.445 +  __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
   1.446 +  __ADD_XEN_INIT_UCHAR(&ptr, 20);
   1.447 +  __ADD_XEN_INIT_UCHAR(&ptr, 0);
   1.448 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_SHUTDOWN, NULL, NULL, NULL);
   1.449 +  __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
   1.450 +  __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
   1.451 +  __ADD_XEN_INIT_UCHAR(&ptr, 50);
   1.452 +  __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
   1.453 +  __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
   1.454 +  __ADD_XEN_INIT_UCHAR(&ptr, 50);
   1.455 +  __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitialising);
   1.456 +  __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitWait);
   1.457 +  __ADD_XEN_INIT_UCHAR(&ptr, 50);
   1.458 +  __ADD_XEN_INIT_UCHAR(&ptr, 0);
   1.459 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
   1.460 +
   1.461 +  status = xi->vectors.XenPci_XenConfigDevice(xi->vectors.context);
   1.462 +  if (!NT_SUCCESS(status))
   1.463 +  {
   1.464 +    KdPrint(("Failed to complete device configuration (%08x)\n", status));
   1.465 +    return status;
   1.466 +  }
   1.467 +
   1.468 +  status = XenNet_ConnectBackend(xi);
   1.469 +  
   1.470 +  if (!NT_SUCCESS(status))
   1.471 +  {
   1.472 +    KdPrint(("Failed to complete device configuration (%08x)\n", status));
   1.473 +    return status;
   1.474 +  }
   1.475 +
   1.476 +  if (!xi->config_sg)
   1.477 +  {
   1.478 +    /* without SG, GSO can be a maximum of PAGE_SIZE */
   1.479 +    xi->config_gso = min(xi->config_gso, PAGE_SIZE);
   1.480 +  }
   1.481 +
   1.482 +  XenNet_TxInit(xi);
   1.483 +  XenNet_RxInit(xi);
   1.484 +
   1.485 +  xi->connected = TRUE;
   1.486 +
   1.487 +  KeMemoryBarrier(); // packets could be received anytime after we set Frontent to Connected
   1.488 +
   1.489 +  FUNCTION_EXIT();
   1.490 +
   1.491 +  return status;
   1.492 +}
   1.493 +
   1.494 +NDIS_OID supported_oids[] =
   1.495 +{
   1.496 +  /* general OIDs */
   1.497 +  OID_GEN_SUPPORTED_LIST,        // Q
   1.498 +  OID_GEN_HARDWARE_STATUS,       // Q
   1.499 +  OID_GEN_MEDIA_SUPPORTED,       // Q
   1.500 +  OID_GEN_MEDIA_IN_USE,          // Q
   1.501 +  OID_GEN_MAXIMUM_LOOKAHEAD,     // Q
   1.502 +  OID_GEN_MAXIMUM_FRAME_SIZE,    // Q
   1.503 +  //OID_GEN_LINK_SPEED,            // Q
   1.504 +  OID_GEN_TRANSMIT_BUFFER_SPACE, // Q
   1.505 +  OID_GEN_RECEIVE_BUFFER_SPACE,  // Q
   1.506 +  OID_GEN_TRANSMIT_BLOCK_SIZE,   // Q
   1.507 +  OID_GEN_RECEIVE_BLOCK_SIZE,    // Q
   1.508 +  OID_GEN_VENDOR_ID,             // Q
   1.509 +  OID_GEN_VENDOR_DESCRIPTION,    // Q
   1.510 +  OID_GEN_CURRENT_PACKET_FILTER, // QS
   1.511 +  OID_GEN_CURRENT_LOOKAHEAD,     // QS
   1.512 +  OID_GEN_DRIVER_VERSION,        // Q
   1.513 +  OID_GEN_VENDOR_DRIVER_VERSION, // Q
   1.514 +  OID_GEN_MAXIMUM_TOTAL_SIZE,    // Q
   1.515 +  OID_GEN_PROTOCOL_OPTIONS,      // S
   1.516 +  OID_GEN_MAC_OPTIONS,           // Q
   1.517 +  OID_GEN_MEDIA_CONNECT_STATUS,  // Q
   1.518 +  OID_GEN_MAXIMUM_SEND_PACKETS,  // Q
   1.519 +  /* stats */
   1.520 +  OID_GEN_XMIT_OK,               // Q
   1.521 +  OID_GEN_RCV_OK,                // Q
   1.522 +  OID_GEN_XMIT_ERROR,            // Q
   1.523 +  OID_GEN_RCV_ERROR,             // Q
   1.524 +  OID_GEN_RCV_NO_BUFFER,         // Q
   1.525 +  /* media-specific OIDs */
   1.526 +  OID_802_3_PERMANENT_ADDRESS,
   1.527 +  OID_802_3_CURRENT_ADDRESS,
   1.528 +  OID_802_3_MULTICAST_LIST,
   1.529 +  OID_802_3_MAXIMUM_LIST_SIZE,
   1.530 +  OID_802_3_RCV_ERROR_ALIGNMENT,
   1.531 +  OID_802_3_XMIT_ONE_COLLISION,
   1.532 +  OID_802_3_XMIT_MORE_COLLISIONS,
   1.533 +  /* tcp offload */
   1.534 +  OID_TCP_TASK_OFFLOAD,
   1.535 +  /* power */
   1.536 +  OID_PNP_CAPABILITIES,
   1.537 +  OID_PNP_SET_POWER,
   1.538 +  OID_PNP_QUERY_POWER,
   1.539 +};
   1.540 +
   1.541 +// Called at <= DISPATCH_LEVEL
   1.542 +static NDIS_STATUS
   1.543 +XenNet_Initialize(NDIS_HANDLE adapter_handle, NDIS_HANDLE driver_context, PNDIS_MINIPORT_INIT_PARAMETERS init_parameters)
   1.544 +{
   1.545 +  NDIS_STATUS status;
   1.546 +  struct xennet_info *xi = NULL;
   1.547 +  PNDIS_RESOURCE_LIST nrl;
   1.548 +  PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
   1.549 +  NDIS_HANDLE config_handle;
   1.550 +  NDIS_STRING config_param_name;
   1.551 +  NDIS_CONFIGURATION_OBJECT config_object;
   1.552 +  PNDIS_CONFIGURATION_PARAMETER config_param;
   1.553 +  //PNDIS_MINIPORT_ADAPTER_ATTRIBUTES adapter_attributes;
   1.554 +  ULONG i;
   1.555 +  PUCHAR ptr;
   1.556 +  UCHAR type;
   1.557 +  PCHAR setting, value;
   1.558 +  ULONG length;
   1.559 +  //CHAR buf[128];
   1.560 +  PVOID network_address;
   1.561 +  UINT network_address_length;
   1.562 +  BOOLEAN qemu_hide_filter = FALSE;
   1.563 +  ULONG qemu_hide_flags_value = 0;
   1.564 +  NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES registration_attributes;
   1.565 +  NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES general_attributes;
   1.566 +  
   1.567 +  UNREFERENCED_PARAMETER(driver_context);
   1.568 +
   1.569 +  FUNCTION_ENTER();
   1.570 +
   1.571 +  /* Alloc memory for adapter private info */
   1.572 +  status = NdisAllocateMemoryWithTag((PVOID)&xi, sizeof(*xi), XENNET_POOL_TAG);
   1.573 +  if (!NT_SUCCESS(status))
   1.574 +  {
   1.575 +    KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
   1.576 +    status = NDIS_STATUS_RESOURCES;
   1.577 +    goto err;
   1.578 +  }
   1.579 +  RtlZeroMemory(xi, sizeof(*xi));
   1.580 +  xi->adapter_handle = adapter_handle;
   1.581 +  xi->rx_target     = RX_DFL_MIN_TARGET;
   1.582 +  xi->rx_min_target = RX_DFL_MIN_TARGET;
   1.583 +  xi->rx_max_target = RX_MAX_TARGET;
   1.584 +  xi->inactive      = TRUE;
   1.585 +  
   1.586 +  xi->multicast_list_size = 0;
   1.587 +  xi->current_lookahead = MIN_LOOKAHEAD_LENGTH;
   1.588 +
   1.589 +  xi->event_channel = 0;
   1.590 +  xi->config_csum = 1;
   1.591 +  xi->config_csum_rx_check = 1;
   1.592 +  xi->config_sg = 1;
   1.593 +  xi->config_gso = 61440;
   1.594 +  xi->config_page = NULL;
   1.595 +  xi->config_rx_interrupt_moderation = 0;
   1.596 +  
   1.597 +  nrl = init_parameters->AllocatedResources;
   1.598 +  for (i = 0; i < nrl->Count; i++)
   1.599 +  {
   1.600 +    prd = &nrl->PartialDescriptors[i];
   1.601 +
   1.602 +    switch(prd->Type)
   1.603 +    {
   1.604 +    case CmResourceTypeInterrupt:
   1.605 +      break;
   1.606 +    case CmResourceTypeMemory:
   1.607 +      if (xi->config_page)
   1.608 +      {
   1.609 +        KdPrint(("More than one memory range\n"));
   1.610 +        return NDIS_STATUS_RESOURCES;
   1.611 +      }
   1.612 +      else
   1.613 +      {
   1.614 +        status = NdisMMapIoSpace(&xi->config_page, xi->adapter_handle, prd->u.Memory.Start, prd->u.Memory.Length);
   1.615 +        if (!NT_SUCCESS(status))
   1.616 +        {
   1.617 +          KdPrint(("NdisMMapIoSpace failed with 0x%x\n", status));
   1.618 +          return NDIS_STATUS_RESOURCES;
   1.619 +        }
   1.620 +      }
   1.621 +      break;
   1.622 +    }
   1.623 +  }
   1.624 +  if (!xi->config_page)
   1.625 +  {
   1.626 +    KdPrint(("No config page given\n"));
   1.627 +    return NDIS_STATUS_RESOURCES;
   1.628 +  }
   1.629 +
   1.630 +  KeInitializeDpc(&xi->suspend_dpc, XenNet_SuspendResume, xi);
   1.631 +  KeInitializeSpinLock(&xi->resume_lock);
   1.632 +
   1.633 +  KeInitializeDpc(&xi->rxtx_dpc, XenNet_RxTxDpc, xi);
   1.634 +  KeSetTargetProcessorDpc(&xi->rxtx_dpc, 0);
   1.635 +  KeSetImportanceDpc(&xi->rxtx_dpc, HighImportance);
   1.636 +
   1.637 +  NdisMGetDeviceProperty(xi->adapter_handle, &xi->pdo, &xi->fdo,
   1.638 +    &xi->lower_do, NULL, NULL);
   1.639 +  xi->packet_filter = 0;
   1.640 +
   1.641 +  status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
   1.642 +    NAME_SIZE, xi->dev_desc, &length);
   1.643 +  if (!NT_SUCCESS(status))
   1.644 +  {
   1.645 +    KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
   1.646 +    status = NDIS_STATUS_FAILURE;
   1.647 +    goto err;
   1.648 +  }
   1.649 +
   1.650 +  ptr = xi->config_page;
   1.651 +  while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value)) != XEN_INIT_TYPE_END)
   1.652 +  {
   1.653 +    switch(type)
   1.654 +    {
   1.655 +    case XEN_INIT_TYPE_VECTORS:
   1.656 +      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_VECTORS\n"));
   1.657 +      if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
   1.658 +        ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
   1.659 +      {
   1.660 +        KdPrint((__DRIVER_NAME "     vectors mismatch (magic = %08x, length = %d)\n",
   1.661 +          ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
   1.662 +        FUNCTION_EXIT();
   1.663 +        return NDIS_STATUS_FAILURE;
   1.664 +      }
   1.665 +      else
   1.666 +        memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
   1.667 +      break;
   1.668 +    case XEN_INIT_TYPE_STATE_PTR:
   1.669 +      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
   1.670 +      xi->device_state = (PXENPCI_DEVICE_STATE)value;
   1.671 +      break;
   1.672 +    case XEN_INIT_TYPE_QEMU_HIDE_FLAGS:
   1.673 +      qemu_hide_flags_value = PtrToUlong(value);
   1.674 +      break;
   1.675 +    case XEN_INIT_TYPE_QEMU_HIDE_FILTER:
   1.676 +      qemu_hide_filter = TRUE;
   1.677 +      break;
   1.678 +    default:
   1.679 +      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_%d\n", type));
   1.680 +      break;
   1.681 +    }
   1.682 +  }
   1.683 +
   1.684 +  if ((qemu_hide_flags_value & QEMU_UNPLUG_ALL_IDE_DISKS) || qemu_hide_filter)
   1.685 +    xi->inactive = FALSE;
   1.686 +
   1.687 +  xi->power_state = NdisDeviceStateD0;
   1.688 +  xi->power_workitem = IoAllocateWorkItem(xi->fdo);
   1.689 +
   1.690 +  // now build config page
   1.691 +  
   1.692 +  config_object.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);
   1.693 +  config_object.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
   1.694 +  config_object.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
   1.695 +  config_object.NdisHandle = xi->adapter_handle;
   1.696 +  config_object.Flags = 0;
   1.697 +
   1.698 +  status = NdisOpenConfigurationEx(&config_object, &config_handle);
   1.699 +  if (!NT_SUCCESS(status))
   1.700 +  {
   1.701 +    KdPrint(("Could not open config in registry (%08x)\n", status));
   1.702 +    status = NDIS_STATUS_RESOURCES;
   1.703 +    goto err;
   1.704 +  }
   1.705 +
   1.706 +  NdisInitUnicodeString(&config_param_name, L"ScatterGather");
   1.707 +  NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
   1.708 +  if (!NT_SUCCESS(status))
   1.709 +  {
   1.710 +    KdPrint(("Could not read ScatterGather value (%08x)\n", status));
   1.711 +    xi->config_sg = 1;
   1.712 +  }
   1.713 +  else
   1.714 +  {
   1.715 +    KdPrint(("ScatterGather = %d\n", config_param->ParameterData.IntegerData));
   1.716 +    xi->config_sg = config_param->ParameterData.IntegerData;
   1.717 +  }
   1.718 +  
   1.719 +  NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
   1.720 +  NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
   1.721 +  if (!NT_SUCCESS(status))
   1.722 +  {
   1.723 +    KdPrint(("Could not read LargeSendOffload value (%08x)\n", status));
   1.724 +    xi->config_gso = 0;
   1.725 +  }
   1.726 +  else
   1.727 +  {
   1.728 +    KdPrint(("LargeSendOffload = %d\n", config_param->ParameterData.IntegerData));
   1.729 +    xi->config_gso = config_param->ParameterData.IntegerData;
   1.730 +    if (xi->config_gso > 61440)
   1.731 +    {
   1.732 +      xi->config_gso = 61440;
   1.733 +      KdPrint(("(clipped to %d)\n", xi->config_gso));
   1.734 +    }
   1.735 +  }
   1.736 +
   1.737 +  NdisInitUnicodeString(&config_param_name, L"ChecksumOffload");
   1.738 +  NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
   1.739 +  if (!NT_SUCCESS(status))
   1.740 +  {
   1.741 +    KdPrint(("Could not read ChecksumOffload value (%08x)\n", status));
   1.742 +    xi->config_csum = 1;
   1.743 +  }
   1.744 +  else
   1.745 +  {
   1.746 +    KdPrint(("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData));
   1.747 +    xi->config_csum = !!config_param->ParameterData.IntegerData;
   1.748 +  }
   1.749 +
   1.750 +  NdisInitUnicodeString(&config_param_name, L"ChecksumOffloadRxCheck");
   1.751 +  NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
   1.752 +  if (!NT_SUCCESS(status))
   1.753 +  {
   1.754 +    KdPrint(("Could not read ChecksumOffloadRxCheck value (%08x)\n", status));
   1.755 +    xi->config_csum_rx_check = 1;
   1.756 +  }
   1.757 +  else
   1.758 +  {
   1.759 +    KdPrint(("ChecksumOffloadRxCheck = %d\n", config_param->ParameterData.IntegerData));
   1.760 +    xi->config_csum_rx_check = !!config_param->ParameterData.IntegerData;
   1.761 +  }
   1.762 +
   1.763 +  NdisInitUnicodeString(&config_param_name, L"ChecksumOffloadDontFix");
   1.764 +  NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
   1.765 +  if (!NT_SUCCESS(status))
   1.766 +  {
   1.767 +    KdPrint(("Could not read ChecksumOffloadDontFix value (%08x)\n", status));
   1.768 +    xi->config_csum_rx_dont_fix = 0;
   1.769 +  }
   1.770 +  else
   1.771 +  {
   1.772 +    KdPrint(("ChecksumOffloadDontFix = %d\n", config_param->ParameterData.IntegerData));
   1.773 +    xi->config_csum_rx_dont_fix = !!config_param->ParameterData.IntegerData;
   1.774 +  }
   1.775 +  
   1.776 +  NdisInitUnicodeString(&config_param_name, L"MTU");
   1.777 +  NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);  
   1.778 +  if (!NT_SUCCESS(status))
   1.779 +  {
   1.780 +    KdPrint(("Could not read MTU value (%08x)\n", status));
   1.781 +    xi->config_mtu = 1500;
   1.782 +  }
   1.783 +  else
   1.784 +  {
   1.785 +    KdPrint(("MTU = %d\n", config_param->ParameterData.IntegerData));
   1.786 +    xi->config_mtu = config_param->ParameterData.IntegerData;
   1.787 +  }
   1.788 +
   1.789 +  NdisInitUnicodeString(&config_param_name, L"RxInterruptModeration");
   1.790 +  NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);  
   1.791 +  if (!NT_SUCCESS(status))
   1.792 +  {
   1.793 +    KdPrint(("Could not read RxInterruptModeration value (%08x)\n", status));
   1.794 +    xi->config_rx_interrupt_moderation = 1500;
   1.795 +  }
   1.796 +  else
   1.797 +  {
   1.798 +    KdPrint(("RxInterruptModeration = %d\n", config_param->ParameterData.IntegerData));
   1.799 +    xi->config_rx_interrupt_moderation = config_param->ParameterData.IntegerData;
   1.800 +  }
   1.801 +  
   1.802 +  NdisReadNetworkAddress(&status, &network_address, &network_address_length, config_handle);
   1.803 +  if (!NT_SUCCESS(status) || network_address_length != ETH_ALEN || ((((PUCHAR)network_address)[0] & 0x03) != 0x02))
   1.804 +  {
   1.805 +    KdPrint(("Could not read NetworkAddress value (%08x) or value is invalid\n", status));
   1.806 +    memset(xi->curr_mac_addr, 0, ETH_ALEN);
   1.807 +  }
   1.808 +  else
   1.809 +  {
   1.810 +    memcpy(xi->curr_mac_addr, network_address, ETH_ALEN);
   1.811 +    KdPrint(("     Set MAC address from registry to %02X:%02X:%02X:%02X:%02X:%02X\n",
   1.812 +      xi->curr_mac_addr[0], xi->curr_mac_addr[1], xi->curr_mac_addr[2], 
   1.813 +      xi->curr_mac_addr[3], xi->curr_mac_addr[4], xi->curr_mac_addr[5]));
   1.814 +  }
   1.815 +
   1.816 +  xi->config_max_pkt_size = max(xi->config_mtu + XN_HDR_SIZE, xi->config_gso + XN_HDR_SIZE);
   1.817 +  
   1.818 +  NdisCloseConfiguration(config_handle);
   1.819 +
   1.820 +  status = XenNet_D0Entry(xi);
   1.821 +  if (!NT_SUCCESS(status))
   1.822 +  {
   1.823 +    KdPrint(("Failed to go to D0 (%08x)\n", status));
   1.824 +    goto err;
   1.825 +  }
   1.826 +
   1.827 +  registration_attributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
   1.828 +  registration_attributes.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
   1.829 +  registration_attributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
   1.830 +  registration_attributes.MiniportAdapterContext = xi;
   1.831 +  registration_attributes.AttributeFlags = 0;
   1.832 +  registration_attributes.AttributeFlags |= NDIS_MINIPORT_ATTRIBUTES_HARDWARE_DEVICE;
   1.833 +  registration_attributes.AttributeFlags |= NDIS_MINIPORT_ATTRIBUTES_SURPRISE_REMOVE_OK;
   1.834 +  registration_attributes.CheckForHangTimeInSeconds = 0; /* use default */
   1.835 +  registration_attributes.InterfaceType = NdisInterfacePNPBus; /* or PnP??? */
   1.836 +  status = NdisMSetMiniportAttributes(xi->adapter_handle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&registration_attributes);
   1.837 +  if (!NT_SUCCESS(status))
   1.838 +  {
   1.839 +    KdPrint(("NdisMSetMiniportAttributes(registration) failed (%08x)\n", status));
   1.840 +    goto err;
   1.841 +  }
   1.842 +  
   1.843 +  general_attributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
   1.844 +  general_attributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; /* revision 2 is NDIS 6.2 */
   1.845 +  general_attributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
   1.846 +  general_attributes.Flags = 0;
   1.847 +  general_attributes.MediaType = NdisMedium802_3;
   1.848 +  general_attributes.PhysicalMediumType = NdisPhysicalMediumOther;
   1.849 +  general_attributes.MtuSize = xi->config_mtu;
   1.850 +  general_attributes.MaxXmitLinkSpeed = MAX_LINK_SPEED;
   1.851 +  general_attributes.XmitLinkSpeed = MAX_LINK_SPEED;
   1.852 +  general_attributes.MaxRcvLinkSpeed = MAX_LINK_SPEED;
   1.853 +  general_attributes.RcvLinkSpeed = MAX_LINK_SPEED;
   1.854 +  general_attributes.MediaConnectState = MediaConnectStateConnected;
   1.855 +  general_attributes.MediaDuplexState = MediaDuplexStateFull;
   1.856 +  general_attributes.LookaheadSize = xi->current_lookahead;
   1.857 +  general_attributes.PowerManagementCapabilities = NULL;
   1.858 +  general_attributes.MacOptions = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | 
   1.859 +        NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
   1.860 +        NDIS_MAC_OPTION_NO_LOOPBACK;
   1.861 +  general_attributes.SupportedPacketFilters = SUPPORTED_PACKET_FILTERS;
   1.862 +  general_attributes.MaxMulticastListSize = MULTICAST_LIST_MAX_SIZE;
   1.863 +  general_attributes.MacAddressLength = 6;
   1.864 +  NdisMoveMemory(general_attributes.PermanentMacAddress, xi->perm_mac_addr, general_attributes.MacAddressLength);
   1.865 +  NdisMoveMemory(general_attributes.CurrentMacAddress, xi->curr_mac_addr, general_attributes.MacAddressLength);
   1.866 +  general_attributes.RecvScaleCapabilities = NULL; /* we do want to support this soon */
   1.867 +  general_attributes.AccessType = NET_IF_ACCESS_BROADCAST;
   1.868 +  general_attributes.DirectionType = NET_IF_DIRECTION_SENDRECEIVE;
   1.869 +  general_attributes.ConnectionType = NET_IF_CONNECTION_DEDICATED;
   1.870 +  general_attributes.IfType = IF_TYPE_ETHERNET_CSMACD;
   1.871 +  general_attributes.IfConnectorPresent = TRUE;
   1.872 +  general_attributes.SupportedStatistics = NDIS_STATISTICS_XMIT_OK_SUPPORTED              
   1.873 +    | NDIS_STATISTICS_RCV_OK_SUPPORTED               
   1.874 +    | NDIS_STATISTICS_XMIT_ERROR_SUPPORTED           
   1.875 +    | NDIS_STATISTICS_RCV_ERROR_SUPPORTED            
   1.876 +    | NDIS_STATISTICS_RCV_NO_BUFFER_SUPPORTED        
   1.877 +    | NDIS_STATISTICS_DIRECTED_BYTES_XMIT_SUPPORTED  
   1.878 +    | NDIS_STATISTICS_DIRECTED_FRAMES_XMIT_SUPPORTED 
   1.879 +    | NDIS_STATISTICS_MULTICAST_BYTES_XMIT_SUPPORTED 
   1.880 +    | NDIS_STATISTICS_MULTICAST_FRAMES_XMIT_SUPPORTED
   1.881 +    | NDIS_STATISTICS_BROADCAST_BYTES_XMIT_SUPPORTED 
   1.882 +    | NDIS_STATISTICS_BROADCAST_FRAMES_XMIT_SUPPORTED
   1.883 +    | NDIS_STATISTICS_DIRECTED_BYTES_RCV_SUPPORTED   
   1.884 +    | NDIS_STATISTICS_DIRECTED_FRAMES_RCV_SUPPORTED  
   1.885 +    | NDIS_STATISTICS_MULTICAST_BYTES_RCV_SUPPORTED  
   1.886 +    | NDIS_STATISTICS_MULTICAST_FRAMES_RCV_SUPPORTED 
   1.887 +    | NDIS_STATISTICS_BROADCAST_BYTES_RCV_SUPPORTED  
   1.888 +    | NDIS_STATISTICS_BROADCAST_FRAMES_RCV_SUPPORTED 
   1.889 +    | NDIS_STATISTICS_RCV_CRC_ERROR_SUPPORTED        
   1.890 +    | NDIS_STATISTICS_TRANSMIT_QUEUE_LENGTH_SUPPORTED
   1.891 +    | NDIS_STATISTICS_BYTES_RCV_SUPPORTED            
   1.892 +    | NDIS_STATISTICS_BYTES_XMIT_SUPPORTED           
   1.893 +    | NDIS_STATISTICS_RCV_DISCARDS_SUPPORTED         
   1.894 +    | NDIS_STATISTICS_GEN_STATISTICS_SUPPORTED       
   1.895 +    | NDIS_STATISTICS_XMIT_DISCARDS_SUPPORTED;
   1.896 +  general_attributes.SupportedPauseFunctions = NdisPauseFunctionsUnsupported;
   1.897 +  general_attributes.DataBackFillSize = 0; // see NdisRetreatNetBufferDataStart
   1.898 +  general_attributes.ContextBackFillSize = 0; // ?? NFI ??
   1.899 +  general_attributes.SupportedOidList = supported_oids;
   1.900 +  general_attributes.SupportedOidListLength = sizeof(supported_oids);
   1.901 +  general_attributes.AutoNegotiationFlags = NDIS_LINK_STATE_XMIT_LINK_SPEED_AUTO_NEGOTIATED
   1.902 +    | NDIS_LINK_STATE_RCV_LINK_SPEED_AUTO_NEGOTIATED
   1.903 +    | NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED;
   1.904 +  //general_attributes.PowerManagementCapabilitiesEx = NULL; // >= 6.20
   1.905 +  status = NdisMSetMiniportAttributes(xi->adapter_handle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&general_attributes);
   1.906 +  if (!NT_SUCCESS(status))
   1.907 +  {
   1.908 +    KdPrint(("NdisMSetMiniportAttributes(general) failed (%08x)\n", status));
   1.909 +    goto err;
   1.910 +  }
   1.911 +
   1.912 +  return NDIS_STATUS_SUCCESS;
   1.913 +  
   1.914 +err:
   1.915 +  NdisFreeMemory(xi, 0, 0);
   1.916 +  FUNCTION_EXIT_STATUS(status);
   1.917 +
   1.918 +  return status;
   1.919 +}
   1.920 +
   1.921 +#if 0
   1.922 +NDIS_STATUS
   1.923 +XenNet_D0Exit(struct xennet_info *xi)
   1.924 +{
   1.925 +  FUNCTION_ENTER();
   1.926 +  KdPrint((__DRIVER_NAME "     IRQL = %d\n", KeGetCurrentIrql()));
   1.927 +
   1.928 +  xi->shutting_down = TRUE;
   1.929 +  KeMemoryBarrier(); /* make sure everyone sees that we are now shutting down */
   1.930 +
   1.931 +  XenNet_TxShutdown(xi);
   1.932 +  XenNet_RxShutdown(xi);
   1.933 +
   1.934 +  xi->connected = FALSE;
   1.935 +  KeMemoryBarrier(); /* make sure everyone sees that we are now disconnected */
   1.936 +
   1.937 +  xi->vectors.XenPci_XenShutdownDevice(xi->vectors.context);
   1.938 +
   1.939 +  FUNCTION_EXIT();
   1.940 +  
   1.941 +  return STATUS_SUCCESS;
   1.942 +}
   1.943 +#endif
   1.944 +
   1.945 +static VOID
   1.946 +XenNet_DevicePnPEventNotify(NDIS_HANDLE adapter_context, PNET_DEVICE_PNP_EVENT pnp_event)
   1.947 +{
   1.948 +  UNREFERENCED_PARAMETER(adapter_context);
   1.949 +
   1.950 +  FUNCTION_ENTER();
   1.951 +  switch (pnp_event->DevicePnPEvent)
   1.952 +  {
   1.953 +  case NdisDevicePnPEventSurpriseRemoved:
   1.954 +    KdPrint((__DRIVER_NAME "     NdisDevicePnPEventSurpriseRemoved\n"));
   1.955 +    break;
   1.956 +  case NdisDevicePnPEventPowerProfileChanged :
   1.957 +    KdPrint((__DRIVER_NAME "     NdisDevicePnPEventPowerProfileChanged\n"));
   1.958 +    break;
   1.959 +  default:
   1.960 +    KdPrint((__DRIVER_NAME "     NdisDevicePnPEvent%d\n", pnp_event->DevicePnPEvent));
   1.961 +    break;
   1.962 +  }
   1.963 +  FUNCTION_EXIT();
   1.964 +}
   1.965 +
   1.966 +/* called at <= HIGH_IRQL, or PASSIVE_LEVEL, depending on shutdown_action */
   1.967 +VOID
   1.968 +XenNet_Shutdown(NDIS_HANDLE adapter_context, NDIS_SHUTDOWN_ACTION shutdown_action)
   1.969 +{
   1.970 +  UNREFERENCED_PARAMETER(adapter_context);
   1.971 +  UNREFERENCED_PARAMETER(shutdown_action);
   1.972 +
   1.973 +  FUNCTION_ENTER();
   1.974 +  FUNCTION_EXIT();
   1.975 +}
   1.976 +
   1.977 +static BOOLEAN
   1.978 +XenNet_CheckForHang(NDIS_HANDLE adapter_context)
   1.979 +{
   1.980 +  UNREFERENCED_PARAMETER(adapter_context);
   1.981 +
   1.982 +  //FUNCTION_ENTER();
   1.983 +  //FUNCTION_EXIT();
   1.984 +  return FALSE;
   1.985 +}
   1.986 +
   1.987 +/* Opposite of XenNet_Init */
   1.988 +static VOID
   1.989 +XenNet_Halt(NDIS_HANDLE adapter_context, NDIS_HALT_ACTION halt_action)
   1.990 +{
   1.991 +  struct xennet_info *xi = adapter_context;
   1.992 +  UNREFERENCED_PARAMETER(halt_action);
   1.993 +
   1.994 +  FUNCTION_ENTER();
   1.995 +  
   1.996 +  //XenNet_D0Exit(xi);
   1.997 +
   1.998 +  NdisFreeMemory(xi, 0, 0);
   1.999 +
  1.1000 +  FUNCTION_EXIT();
  1.1001 +}
  1.1002 +
  1.1003 +static NDIS_STATUS 
  1.1004 +XenNet_Reset(NDIS_HANDLE adapter_context, PBOOLEAN addressing_reset)
  1.1005 +{
  1.1006 +  UNREFERENCED_PARAMETER(adapter_context);
  1.1007 +
  1.1008 +  FUNCTION_ENTER();
  1.1009 +  *addressing_reset = FALSE;
  1.1010 +  FUNCTION_EXIT();
  1.1011 +  return NDIS_STATUS_SUCCESS;
  1.1012 +}
  1.1013 +
  1.1014 +/* called at PASSIVE_LEVEL */
  1.1015 +static NDIS_STATUS
  1.1016 +XenNet_Pause(NDIS_HANDLE adapter_context, PNDIS_MINIPORT_PAUSE_PARAMETERS pause_parameters)
  1.1017 +{
  1.1018 +  UNREFERENCED_PARAMETER(adapter_context);
  1.1019 +  UNREFERENCED_PARAMETER(pause_parameters);
  1.1020 +  FUNCTION_ENTER();
  1.1021 +  FUNCTION_EXIT();
  1.1022 +  return STATUS_SUCCESS;
  1.1023 +}
  1.1024 +
  1.1025 +/* called at PASSIVE_LEVEL */
  1.1026 +static NDIS_STATUS
  1.1027 +XenNet_Restart(NDIS_HANDLE adapter_context, PNDIS_MINIPORT_RESTART_PARAMETERS restart_parameters)
  1.1028 +{
  1.1029 +  UNREFERENCED_PARAMETER(adapter_context);
  1.1030 +  UNREFERENCED_PARAMETER(restart_parameters);
  1.1031 +  FUNCTION_ENTER();
  1.1032 +  FUNCTION_EXIT();
  1.1033 +  return STATUS_SUCCESS;
  1.1034 +}
  1.1035 +
  1.1036 +static VOID
  1.1037 +XenNet_Unload(PDRIVER_OBJECT driver_object)
  1.1038 +{
  1.1039 +  UNREFERENCED_PARAMETER(driver_object);
  1.1040 +  FUNCTION_ENTER();
  1.1041 +  NdisMDeregisterMiniportDriver(driver_handle);
  1.1042 +  FUNCTION_EXIT();
  1.1043 +}
  1.1044 +
  1.1045 +static NDIS_STATUS
  1.1046 +XenNet_SetOptions(NDIS_HANDLE driver_handle, NDIS_HANDLE driver_context)
  1.1047 +{
  1.1048 +  UNREFERENCED_PARAMETER(driver_handle);
  1.1049 +  UNREFERENCED_PARAMETER(driver_context);
  1.1050 +  FUNCTION_ENTER();
  1.1051 +  FUNCTION_EXIT();
  1.1052 +  return STATUS_SUCCESS;
  1.1053 +}
  1.1054 +
  1.1055 +NTSTATUS
  1.1056 +DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path)
  1.1057 +{
  1.1058 +  NTSTATUS status;  
  1.1059 +  NDIS_MINIPORT_DRIVER_CHARACTERISTICS mini_chars;
  1.1060 +  ULONG ndis_version;
  1.1061 +  
  1.1062 +  FUNCTION_ENTER();
  1.1063 +
  1.1064 +  ndis_version = NdisGetVersion();
  1.1065 +  KdPrint((__DRIVER_NAME "     ndis_version = %08x\n", ndis_version));
  1.1066 +
  1.1067 +  NdisZeroMemory(&mini_chars, sizeof(mini_chars));
  1.1068 +
  1.1069 +  mini_chars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
  1.1070 +  mini_chars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
  1.1071 +  mini_chars.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
  1.1072 +
  1.1073 +  mini_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
  1.1074 +  mini_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
  1.1075 +  mini_chars.MajorDriverVersion = VENDOR_DRIVER_VERSION_MAJOR;
  1.1076 +  mini_chars.MinorDriverVersion = VENDOR_DRIVER_VERSION_MINOR;
  1.1077 +
  1.1078 +  KdPrint((__DRIVER_NAME "     MajorNdisVersion = %d,  MinorNdisVersion = %d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION));
  1.1079 +
  1.1080 +  mini_chars.Flags = NDIS_WDM_DRIVER;
  1.1081 +  
  1.1082 +  mini_chars.SetOptionsHandler = XenNet_SetOptions;
  1.1083 +  mini_chars.InitializeHandlerEx = XenNet_Initialize;
  1.1084 +  mini_chars.HaltHandlerEx = XenNet_Halt;
  1.1085 +  mini_chars.UnloadHandler = XenNet_Unload;
  1.1086 +  mini_chars.PauseHandler = XenNet_Pause;
  1.1087 +  mini_chars.RestartHandler = XenNet_Restart;
  1.1088 +  mini_chars.CheckForHangHandlerEx = XenNet_CheckForHang;
  1.1089 +  mini_chars.ResetHandlerEx = XenNet_Reset;
  1.1090 +  mini_chars.DevicePnPEventNotifyHandler = XenNet_DevicePnPEventNotify;
  1.1091 +  mini_chars.ShutdownHandlerEx = XenNet_Shutdown;
  1.1092 +
  1.1093 +  mini_chars.OidRequestHandler = XenNet_OidRequest;
  1.1094 +  mini_chars.CancelOidRequestHandler = XenNet_CancelOidRequest;
  1.1095 +  #if 0 // these must be for NDIS > 6.0 ?
  1.1096 +  mini_chars.DirectOidRequestHandler = NULL;
  1.1097 +  mini_chars.CancelDirectOidRequestHandler = NULL;
  1.1098 +  #endif
  1.1099 +
  1.1100 +  mini_chars.SendNetBufferListsHandler = XenNet_SendNetBufferLists;
  1.1101 +  mini_chars.CancelSendHandler = XenNet_CancelSend;
  1.1102 +
  1.1103 +  mini_chars.ReturnNetBufferListsHandler = XenNet_ReturnNetBufferLists;
  1.1104 +
  1.1105 +  status = NdisMRegisterMiniportDriver(driver_object, registry_path, NULL, &mini_chars, &driver_handle);
  1.1106 +  if (!NT_SUCCESS(status))
  1.1107 +  {
  1.1108 +    KdPrint((__DRIVER_NAME "     NdisMRegisterMiniportDriver failed, status = 0x%x\n", status));
  1.1109 +    return status;
  1.1110 +  }
  1.1111 +
  1.1112 +  FUNCTION_EXIT();
  1.1113 +
  1.1114 +  return status;
  1.1115 +}
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/xennet/xennet6.h	Mon May 02 00:17:33 2011 +1000
     2.3 @@ -0,0 +1,453 @@
     2.4 +/*
     2.5 +PV Drivers for Windows Xen HVM Domains
     2.6 +Copyright (C) 2007 James Harper
     2.7 +Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
     2.8 +
     2.9 +This program is free software; you can redistribute it and/or
    2.10 +modify it under the terms of the GNU General Public License
    2.11 +as published by the Free Software Foundation; either version 2
    2.12 +of the License, or (at your option) any later version.
    2.13 +
    2.14 +This program is distributed in the hope that it will be useful,
    2.15 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.16 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.17 +GNU General Public License for more details.
    2.18 +
    2.19 +You should have received a copy of the GNU General Public License
    2.20 +along with this program; if not, write to the Free Software
    2.21 +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    2.22 +*/
    2.23 +
    2.24 +#pragma warning(disable: 4201)
    2.25 +#pragma warning(disable: 4214)
    2.26 +
    2.27 +#include <ntddk.h>
    2.28 +#include <wdm.h>
    2.29 +#define NDIS_MINIPORT_DRIVER 1
    2.30 +#define NDIS60_MINIPORT 1
    2.31 +#define NDIS_SUPPORT_NDIS6 1
    2.32 +#include <ndis.h>
    2.33 +#define NTSTRSAFE_LIB
    2.34 +#include <ntstrsafe.h>
    2.35 +#include <liblfds.h>
    2.36 +
    2.37 +#define VENDOR_DRIVER_VERSION_MAJOR 0
    2.38 +#define VENDOR_DRIVER_VERSION_MINOR 10
    2.39 +
    2.40 +#define MAX_LINK_SPEED 10000000; /* there is not really any theoretical maximum... */
    2.41 +
    2.42 +#define VENDOR_DRIVER_VERSION (((VENDOR_DRIVER_VERSION_MAJOR) << 16) | (VENDOR_DRIVER_VERSION_MINOR))
    2.43 +
    2.44 +#define __DRIVER_NAME "XenNet"
    2.45 +
    2.46 +#define NB_LIST_ENTRY_FIELD MiniportReserved[0] // TX
    2.47 +#define NB_HEADER_BUF_FIELD MiniportReserved[0] // RX
    2.48 +#define NB_NBL_FIELD MiniportReserved[2] // TX
    2.49 +#define NB_LIST_ENTRY(_nb) (*(PLIST_ENTRY)&(_nb)->NB_LIST_ENTRY_FIELD)
    2.50 +#define NB_NBL(_nb) (*(PNET_BUFFER_LIST *)&(_nb)->NB_NBL_FIELD)
    2.51 +#define NB_HEADER_BUF(_nb) (*(shared_buffer_t **)&(_nb)->NB_HEADER_BUF_FIELD)
    2.52 +
    2.53 +#define NBL_REF_FIELD MiniportReserved[0] // TX
    2.54 +#define NBL_PACKET_COUNT_FIELD MiniportReserved[0] // RX
    2.55 +#define NBL_LAST_NB_FIELD MiniportReserved[1] // RX
    2.56 +#define NBL_REF(_nbl) (*(ULONG_PTR *)&(_nbl)->NBL_REF_FIELD)
    2.57 +#define NBL_PACKET_COUNT(_nbl) (*(ULONG_PTR *)&(_nbl)->NBL_PACKET_COUNT_FIELD)
    2.58 +#define NBL_LAST_NB(_nbl) (*(PNET_BUFFER *)&(_nbl)->NBL_LAST_NB_FIELD)
    2.59 +
    2.60 +#include <xen_windows.h>
    2.61 +#include <memory.h>
    2.62 +#include <grant_table.h>
    2.63 +#include <event_channel.h>
    2.64 +#include <hvm/params.h>
    2.65 +#include <hvm/hvm_op.h>
    2.66 +#include <xen_public.h>
    2.67 +#include <io/ring.h>
    2.68 +#include <io/netif.h>
    2.69 +#include <io/xenbus.h>
    2.70 +#include <stdlib.h>
    2.71 +#define XENNET_POOL_TAG (ULONG) 'XenN'
    2.72 +
    2.73 +/* Xen macros use these, so they need to be redefined to Win equivs */
    2.74 +#define wmb() KeMemoryBarrier()
    2.75 +#define mb() KeMemoryBarrier()
    2.76 +
    2.77 +#define GRANT_INVALID_REF 0
    2.78 +
    2.79 +#define NAME_SIZE 64
    2.80 +
    2.81 +#define ETH_ALEN 6
    2.82 +
    2.83 +/*
    2.84 +#define __NET_USHORT_BYTE_0(x) ((USHORT)(x & 0xFF))
    2.85 +#define __NET_USHORT_BYTE_1(x) ((USHORT)((PUCHAR)&x)[1] & 0xFF)
    2.86 +
    2.87 +#define GET_NET_USHORT(x) ((__NET_USHORT_BYTE_0(x) << 8) | __NET_USHORT_BYTE_1(x))
    2.88 +#define SET_NET_USHORT(y, x) *((USHORT *)&(y)) = ((__NET_USHORT_BYTE_0(x) << 8) | __NET_USHORT_BYTE_1(x))
    2.89 +*/
    2.90 +
    2.91 +static FORCEINLINE USHORT
    2.92 +GET_NET_USHORT(USHORT data)
    2.93 +{
    2.94 +  return (data << 8) | (data >> 8);
    2.95 +}
    2.96 +
    2.97 +static FORCEINLINE USHORT
    2.98 +GET_NET_PUSHORT(PVOID pdata)
    2.99 +{
   2.100 +  return (*((PUSHORT)pdata) << 8) | (*((PUSHORT)pdata) >> 8);
   2.101 +}
   2.102 +
   2.103 +static FORCEINLINE VOID
   2.104 +SET_NET_USHORT(PVOID ptr, USHORT data)
   2.105 +{
   2.106 +  *((PUSHORT)ptr) = GET_NET_USHORT(data);
   2.107 +}
   2.108 +
   2.109 +static FORCEINLINE ULONG
   2.110 +GET_NET_ULONG(ULONG data)
   2.111 +{
   2.112 +  ULONG tmp;
   2.113 +  
   2.114 +  tmp = ((data & 0x00ff00ff) << 8) | ((data & 0xff00ff00) >> 8);
   2.115 +  return (tmp << 16) | (tmp >> 16);
   2.116 +}
   2.117 +
   2.118 +static FORCEINLINE ULONG
   2.119 +GET_NET_PULONG(PVOID pdata)
   2.120 +{
   2.121 +  ULONG tmp;
   2.122 +  
   2.123 +  tmp = ((*((PULONG)pdata) & 0x00ff00ff) << 8) | ((*((PULONG)pdata) & 0xff00ff00) >> 8);
   2.124 +  return (tmp << 16) | (tmp >> 16);
   2.125 +}
   2.126 +
   2.127 +static FORCEINLINE VOID
   2.128 +SET_NET_ULONG(PVOID ptr, ULONG data)
   2.129 +{
   2.130 +  *((PULONG)ptr) = GET_NET_ULONG(data);
   2.131 +}
   2.132 +/*
   2.133 +#define GET_NET_ULONG(x) ((GET_NET_USHORT(x) << 16) | GET_NET_USHORT(((PUCHAR)&x)[2]))
   2.134 +#define SET_NET_ULONG(y, x) *((ULONG *)&(y)) = ((GET_NET_USHORT(x) << 16) | GET_NET_USHORT(((PUCHAR)&x)[2]))
   2.135 +*/
   2.136 +
   2.137 +#define SUPPORTED_PACKET_FILTERS (\
   2.138 +  NDIS_PACKET_TYPE_DIRECTED | \
   2.139 +  NDIS_PACKET_TYPE_MULTICAST | \
   2.140 +  NDIS_PACKET_TYPE_BROADCAST | \
   2.141 +  NDIS_PACKET_TYPE_PROMISCUOUS | \
   2.142 +  NDIS_PACKET_TYPE_ALL_MULTICAST)
   2.143 +
   2.144 +/* couldn't get regular xen ring macros to work...*/
   2.145 +#define __NET_RING_SIZE(type, _sz) \
   2.146 +    (__RD32( \
   2.147 +    (_sz - sizeof(struct type##_sring) + sizeof(union type##_sring_entry)) \
   2.148 +    / sizeof(union type##_sring_entry)))
   2.149 +
   2.150 +#define NET_TX_RING_SIZE __NET_RING_SIZE(netif_tx, PAGE_SIZE)
   2.151 +#define NET_RX_RING_SIZE __NET_RING_SIZE(netif_rx, PAGE_SIZE)
   2.152 +
   2.153 +#pragma warning(disable: 4127) // conditional expression is constant
   2.154 +
   2.155 +#define MIN_LARGE_SEND_SEGMENTS 4
   2.156 +
   2.157 +/* TODO: crank this up if we support higher mtus? */
   2.158 +#define XN_HDR_SIZE 14
   2.159 +#define XN_MAX_DATA_SIZE 1500
   2.160 +#define XN_MIN_FRAME_SIZE 60
   2.161 +#define XN_MAX_FRAME_SIZE (XN_HDR_SIZE + XN_DATA_SIZE)
   2.162 +/*
   2.163 +#if !defined(OFFLOAD_LARGE_SEND)
   2.164 +  #define XN_MAX_PKT_SIZE (XN_HDR_SIZE + XN_DATA_SIZE)
   2.165 +#else
   2.166 +  #define XN_MAX_PKT_SIZE MAX_LARGE_SEND_OFFLOAD
   2.167 +#endif
   2.168 +*/
   2.169 +
   2.170 +#define XN_MAX_SEND_PKTS 16
   2.171 +
   2.172 +#define XENSOURCE_MAC_HDR 0x00163E
   2.173 +#define XN_VENDOR_DESC "Xensource"
   2.174 +#define MAX_XENBUS_STR_LEN 128
   2.175 +
   2.176 +#define RX_MIN_TARGET 8
   2.177 +#define RX_DFL_MIN_TARGET 256
   2.178 +#define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
   2.179 +
   2.180 +//#define MAX_BUFFERS_PER_PACKET NET_RX_RING_SIZE
   2.181 +
   2.182 +#define MIN_ETH_HEADER_LENGTH 14
   2.183 +#define MAX_ETH_HEADER_LENGTH 14
   2.184 +#define MIN_IP4_HEADER_LENGTH 20
   2.185 +#define MAX_IP4_HEADER_LENGTH (15 * 4)
   2.186 +#define MIN_TCP_HEADER_LENGTH 20
   2.187 +#define MAX_TCP_HEADER_LENGTH (15 * 4)
   2.188 +#define MAX_PKT_HEADER_LENGTH (MAX_ETH_HEADER_LENGTH + MAX_IP4_HEADER_LENGTH + MAX_TCP_HEADER_LENGTH)
   2.189 +
   2.190 +#define MIN_LOOKAHEAD_LENGTH (MAX_IP4_HEADER_LENGTH + MAX_TCP_HEADER_LENGTH)
   2.191 +#define MAX_LOOKAHEAD_LENGTH 256
   2.192 +
   2.193 +#define LINUX_MAX_SG_ELEMENTS 19
   2.194 +
   2.195 +struct _shared_buffer_t;
   2.196 +
   2.197 +typedef struct _shared_buffer_t shared_buffer_t;
   2.198 +
   2.199 +struct _shared_buffer_t
   2.200 +{
   2.201 +  struct netif_rx_response rsp;
   2.202 +  shared_buffer_t *next;
   2.203 +  grant_ref_t gref;
   2.204 +  //USHORT offset;
   2.205 +  PVOID virtual;
   2.206 +  PMDL mdl;
   2.207 +  //USHORT id;
   2.208 +  volatile LONG ref_count;
   2.209 +};
   2.210 +
   2.211 +typedef struct
   2.212 +{
   2.213 +  PNET_BUFFER nb; /* only set on the last packet */
   2.214 +  PVOID *cb;
   2.215 +  grant_ref_t gref;
   2.216 +} tx_shadow_t;
   2.217 +
   2.218 +typedef struct {
   2.219 +  PMDL first_mdl;
   2.220 +  PMDL curr_mdl;
   2.221 +  shared_buffer_t *first_pb;
   2.222 +  shared_buffer_t *curr_pb;
   2.223 +  PUCHAR first_mdl_virtual;
   2.224 +  //ULONG mdl_count;
   2.225 +  ULONG first_mdl_offset;
   2.226 +  ULONG curr_mdl_offset;
   2.227 +  USHORT mss;
   2.228 +  //NDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
   2.229 +  //BOOLEAN csum_blank;
   2.230 +  //BOOLEAN data_validated;
   2.231 +  BOOLEAN split_required;
   2.232 +  UCHAR ip_version;
   2.233 +  PUCHAR header;
   2.234 +  ULONG first_mdl_length;
   2.235 +  ULONG header_length;
   2.236 +  UCHAR ip_proto;
   2.237 +  ULONG total_length;
   2.238 +  USHORT ip4_header_length;
   2.239 +  USHORT ip4_length;
   2.240 +  USHORT tcp_header_length;
   2.241 +  BOOLEAN tcp_has_options;
   2.242 +  USHORT tcp_length;
   2.243 +  USHORT tcp_remaining;
   2.244 +  ULONG tcp_seq;
   2.245 +  /* anything past here doesn't get cleared automatically by the ClearPacketInfo */
   2.246 +  UCHAR header_data[MAX_LOOKAHEAD_LENGTH + MAX_ETH_HEADER_LENGTH];
   2.247 +} packet_info_t;
   2.248 +
   2.249 +#define PAGE_LIST_SIZE (max(NET_RX_RING_SIZE, NET_TX_RING_SIZE) * 4)
   2.250 +#define MULTICAST_LIST_MAX_SIZE 32
   2.251 +
   2.252 +struct xennet_info
   2.253 +{
   2.254 +  BOOLEAN inactive;
   2.255 +  
   2.256 +  /* Base device vars */
   2.257 +  PDEVICE_OBJECT pdo;
   2.258 +  PDEVICE_OBJECT fdo;
   2.259 +  PDEVICE_OBJECT lower_do;
   2.260 +  //WDFDEVICE wdf_device;
   2.261 +  WCHAR dev_desc[NAME_SIZE];
   2.262 +
   2.263 +  /* NDIS-related vars */
   2.264 +  NDIS_HANDLE adapter_handle;
   2.265 +  ULONG packet_filter;
   2.266 +  BOOLEAN connected;
   2.267 +  BOOLEAN shutting_down;
   2.268 +  BOOLEAN tx_shutting_down;
   2.269 +  BOOLEAN rx_shutting_down;
   2.270 +  uint8_t perm_mac_addr[ETH_ALEN];
   2.271 +  uint8_t curr_mac_addr[ETH_ALEN];
   2.272 +  ULONG current_lookahead;
   2.273 +  NDIS_DEVICE_POWER_STATE new_power_state;
   2.274 +  NDIS_DEVICE_POWER_STATE power_state;
   2.275 +  PIO_WORKITEM power_workitem;
   2.276 +
   2.277 +  /* Misc. Xen vars */
   2.278 +  XENPCI_VECTORS vectors;
   2.279 +  PXENPCI_DEVICE_STATE device_state;
   2.280 +  evtchn_port_t event_channel;
   2.281 +  ULONG state;
   2.282 +  char backend_path[MAX_XENBUS_STR_LEN];
   2.283 +  ULONG backend_state;
   2.284 +  PVOID config_page;
   2.285 +  UCHAR multicast_list[MULTICAST_LIST_MAX_SIZE][6];
   2.286 +  ULONG multicast_list_size;
   2.287 +  KDPC suspend_dpc;
   2.288 +  PIO_WORKITEM resume_work_item;
   2.289 +  KSPIN_LOCK resume_lock;
   2.290 +  KDPC rxtx_dpc;
   2.291 +
   2.292 +  /* tx related - protected by tx_lock */
   2.293 +  KSPIN_LOCK tx_lock;
   2.294 +  LIST_ENTRY tx_waiting_pkt_list;
   2.295 +  struct netif_tx_front_ring tx;
   2.296 +  ULONG tx_ring_free;
   2.297 +  tx_shadow_t tx_shadows[NET_TX_RING_SIZE];
   2.298 +  //NDIS_HANDLE tx_buffer_pool;
   2.299 +#define TX_HEADER_BUFFER_SIZE 512
   2.300 +//#define TX_COALESCE_BUFFERS (NET_TX_RING_SIZE >> 2)
   2.301 +#define TX_COALESCE_BUFFERS (NET_TX_RING_SIZE)
   2.302 +  KEVENT tx_idle_event;
   2.303 +  ULONG tx_outstanding;
   2.304 +  ULONG tx_id_free;
   2.305 +  USHORT tx_id_list[NET_TX_RING_SIZE];
   2.306 +  NPAGED_LOOKASIDE_LIST tx_lookaside_list;
   2.307 +
   2.308 +  /* rx_related - protected by rx_lock */
   2.309 +  KSPIN_LOCK rx_lock;
   2.310 +  struct netif_rx_front_ring rx;
   2.311 +  ULONG rx_id_free;
   2.312 +  packet_info_t *rxpi;
   2.313 +  KEVENT packet_returned_event;
   2.314 +  //NDIS_MINIPORT_TIMER rx_timer;
   2.315 +  KTIMER rx_timer;
   2.316 +  KDPC rx_timer_dpc;
   2.317 +  NDIS_HANDLE rx_nbl_pool;
   2.318 +  NDIS_HANDLE rx_nb_pool;
   2.319 +  volatile LONG rx_pb_free;
   2.320 +  //struct stack_state *rx_packet_stack;
   2.321 +  struct stack_state *rx_pb_stack;
   2.322 +  shared_buffer_t *rx_ring_pbs[NET_RX_RING_SIZE];
   2.323 +  NPAGED_LOOKASIDE_LIST rx_lookaside_list;
   2.324 +  /* Receive-ring batched refills. */
   2.325 +  ULONG rx_target;
   2.326 +  ULONG rx_max_target;
   2.327 +  ULONG rx_min_target;
   2.328 +  shared_buffer_t *rx_partial_buf;
   2.329 +  BOOLEAN rx_partial_extra_info_flag ;
   2.330 +  BOOLEAN rx_partial_more_data_flag;
   2.331 +
   2.332 +  /* how many packets are in the net stack atm */
   2.333 +  LONG rx_outstanding;
   2.334 +
   2.335 +  /* config vars from registry */
   2.336 +  ULONG config_sg;
   2.337 +  ULONG config_csum;
   2.338 +  ULONG config_csum_rx_check;
   2.339 +  ULONG config_csum_rx_dont_fix;
   2.340 +  ULONG config_gso;
   2.341 +  ULONG config_mtu;
   2.342 +  ULONG config_rx_interrupt_moderation;
   2.343 +
   2.344 +  //NDIS_TASK_TCP_IP_CHECKSUM setting_csum;
   2.345 +  ULONG setting_max_offload;
   2.346 +
   2.347 +  /* config stuff calculated from the above */
   2.348 +  ULONG config_max_pkt_size;
   2.349 +
   2.350 +  /* stats */
   2.351 +  ULONG64 stat_tx_ok;
   2.352 +  ULONG64 stat_rx_ok;
   2.353 +  ULONG64 stat_tx_error;
   2.354 +  ULONG64 stat_rx_error;
   2.355 +  ULONG64 stat_rx_no_buffer;
   2.356 +  
   2.357 +} typedef xennet_info_t;
   2.358 +
   2.359 +MINIPORT_OID_REQUEST XenNet_OidRequest;
   2.360 +MINIPORT_CANCEL_OID_REQUEST XenNet_CancelOidRequest;
   2.361 +
   2.362 +MINIPORT_SEND_NET_BUFFER_LISTS XenNet_SendNetBufferLists;
   2.363 +MINIPORT_CANCEL_SEND XenNet_CancelSend;
   2.364 +
   2.365 +MINIPORT_RETURN_NET_BUFFER_LISTS XenNet_ReturnNetBufferLists;
   2.366 +
   2.367 +BOOLEAN
   2.368 +XenNet_RxInit(xennet_info_t *xi);
   2.369 +
   2.370 +BOOLEAN
   2.371 +XenNet_RxShutdown(xennet_info_t *xi);
   2.372 +
   2.373 +VOID
   2.374 +XenNet_RxResumeStart(xennet_info_t *xi);
   2.375 +
   2.376 +VOID
   2.377 +XenNet_RxResumeEnd(xennet_info_t *xi);
   2.378 +
   2.379 +BOOLEAN
   2.380 +XenNet_RxBufferCheck(struct xennet_info *xi);
   2.381 +
   2.382 +VOID
   2.383 +XenNet_TxResumeStart(xennet_info_t *xi);
   2.384 +
   2.385 +VOID
   2.386 +XenNet_TxResumeEnd(xennet_info_t *xi);
   2.387 +
   2.388 +BOOLEAN
   2.389 +XenNet_TxInit(xennet_info_t *xi);
   2.390 +
   2.391 +BOOLEAN
   2.392 +XenNet_TxShutdown(xennet_info_t *xi);
   2.393 +
   2.394 +VOID
   2.395 +XenNet_TxBufferGC(struct xennet_info *xi, BOOLEAN dont_set_event);
   2.396 +
   2.397 +#if 0
   2.398 +NDIS_STATUS
   2.399 +XenNet_D0Entry(struct xennet_info *xi);
   2.400 +NDIS_STATUS
   2.401 +XenNet_D0Exit(struct xennet_info *xi);
   2.402 +IO_WORKITEM_ROUTINE
   2.403 +XenNet_SetPower;
   2.404 +#endif
   2.405 +
   2.406 +/* return values */
   2.407 +#define PARSE_OK 0
   2.408 +#define PARSE_TOO_SMALL 1 /* first buffer is too small */
   2.409 +#define PARSE_UNKNOWN_TYPE 2
   2.410 +
   2.411 +BOOLEAN
   2.412 +XenNet_BuildHeader(packet_info_t *pi, PVOID header, ULONG new_header_size);
   2.413 +ULONG
   2.414 +XenNet_ParsePacketHeader(packet_info_t *pi, PUCHAR buffer, ULONG min_header_size);
   2.415 +BOOLEAN
   2.416 +XenNet_FilterAcceptPacket(struct xennet_info *xi,packet_info_t *pi);
   2.417 +
   2.418 +VOID
   2.419 +XenNet_SumIpHeader(
   2.420 +  PUCHAR header,
   2.421 +  USHORT ip4_header_length
   2.422 +);
   2.423 +
   2.424 +static __forceinline VOID
   2.425 +XenNet_ClearPacketInfo(packet_info_t *pi)
   2.426 +{
   2.427 +  RtlZeroMemory(pi, sizeof(packet_info_t) - FIELD_OFFSET(packet_info_t, header_data));
   2.428 +}
   2.429 +
   2.430 +/* Get some data from the current packet, but don't cross a page boundry. */
   2.431 +static __forceinline ULONG
   2.432 +XenNet_QueryData(packet_info_t *pi, ULONG length)
   2.433 +{
   2.434 +  ULONG offset_in_page;
   2.435 +  
   2.436 +  if (length > MmGetMdlByteCount(pi->curr_mdl) - pi->curr_mdl_offset)
   2.437 +    length = MmGetMdlByteCount(pi->curr_mdl) - pi->curr_mdl_offset;
   2.438 +
   2.439 +  offset_in_page = (MmGetMdlByteOffset(pi->curr_mdl) + pi->curr_mdl_offset) & (PAGE_SIZE - 1);
   2.440 +  if (offset_in_page + length > PAGE_SIZE)
   2.441 +    length = PAGE_SIZE - offset_in_page;
   2.442 +  
   2.443 +  return length;
   2.444 +}
   2.445 +
   2.446 +/* Move the pointers forward by the given amount. No error checking is done.  */
   2.447 +static __forceinline VOID
   2.448 +XenNet_EatData(packet_info_t *pi, ULONG length)
   2.449 +{
   2.450 +  pi->curr_mdl_offset += length;
   2.451 +  if (pi->curr_mdl_offset >= MmGetMdlByteCount(pi->curr_mdl))
   2.452 +  {
   2.453 +    pi->curr_mdl_offset -= MmGetMdlByteCount(pi->curr_mdl);
   2.454 +    NdisGetNextMdl(pi->curr_mdl, &pi->curr_mdl);
   2.455 +  }
   2.456 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/xennet/xennet6_common.c	Mon May 02 00:17:33 2011 +1000
     3.3 @@ -0,0 +1,296 @@
     3.4 +/*
     3.5 +PV Net Driver for Windows Xen HVM Domains
     3.6 +Copyright (C) 2007 James Harper
     3.7 +Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
     3.8 +
     3.9 +This program is free software; you can redistribute it and/or
    3.10 +modify it under the terms of the GNU General Public License
    3.11 +as published by the Free Software Foundation; either version 2
    3.12 +of the License, or (at your option) any later version.
    3.13 +
    3.14 +This program is distributed in the hope that it will be useful,
    3.15 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.16 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.17 +GNU General Public License for more details.
    3.18 +
    3.19 +You should have received a copy of the GNU General Public License
    3.20 +along with this program; if not, write to the Free Software
    3.21 +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    3.22 +*/
    3.23 +
    3.24 +#include "xennet6.h"
    3.25 +
    3.26 +/* Increase the header to a certain size */
    3.27 +BOOLEAN
    3.28 +XenNet_BuildHeader(packet_info_t *pi, PUCHAR header, ULONG new_header_size)
    3.29 +{
    3.30 +  ULONG bytes_remaining;
    3.31 +
    3.32 +  FUNCTION_ENTER();
    3.33 +
    3.34 +  if (!header)
    3.35 +    header = pi->header;
    3.36 +
    3.37 +  if (new_header_size <= pi->header_length)
    3.38 +  {
    3.39 +    FUNCTION_EXIT();
    3.40 +    return TRUE; /* header is already at least the required size */
    3.41 +  }
    3.42 +
    3.43 +  if (header == pi->first_mdl_virtual)
    3.44 +  {
    3.45 +    /* still working in the first buffer */
    3.46 +    if (new_header_size <= pi->first_mdl_length)
    3.47 +    {
    3.48 +      KdPrint((__DRIVER_NAME "     new_header_size <= pi->first_mdl_length\n"));
    3.49 +      pi->header_length = new_header_size;
    3.50 +      if (pi->header_length == pi->first_mdl_length)
    3.51 +      {
    3.52 +        NdisGetNextBuffer(pi->curr_mdl, &pi->curr_mdl);
    3.53 +        pi->curr_mdl_offset = 0;
    3.54 +        if (pi->curr_pb)
    3.55 +          pi->curr_pb = pi->curr_pb->next;
    3.56 +      }
    3.57 +      else
    3.58 +      {
    3.59 +        pi->curr_mdl_offset = (USHORT)new_header_size;
    3.60 +      }
    3.61 +      FUNCTION_EXIT();
    3.62 +      return TRUE;
    3.63 +    }
    3.64 +    else
    3.65 +    {
    3.66 +      KdPrint((__DRIVER_NAME "     Switching to header_data\n"));
    3.67 +      memcpy(pi->header_data, header, pi->header_length);
    3.68 +      header = pi->header = pi->header_data;
    3.69 +    }
    3.70 +  }
    3.71 +  
    3.72 +  bytes_remaining = new_header_size - pi->header_length;
    3.73 +  // 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
    3.74 +
    3.75 +  KdPrint((__DRIVER_NAME "     A bytes_remaining = %d, pi->curr_mdl = %p\n", bytes_remaining, pi->curr_mdl));
    3.76 +  while (bytes_remaining && pi->curr_mdl)
    3.77 +  {
    3.78 +    ULONG copy_size;
    3.79 +    
    3.80 +    ASSERT(pi->curr_mdl);
    3.81 +    KdPrint((__DRIVER_NAME "     B bytes_remaining = %d, pi->curr_mdl = %p\n", bytes_remaining, pi->curr_mdl));
    3.82 +    if (MmGetMdlByteCount(pi->curr_mdl))
    3.83 +    {
    3.84 +      PUCHAR src_addr;
    3.85 +      src_addr = MmGetSystemAddressForMdlSafe(pi->curr_mdl, NormalPagePriority);
    3.86 +      if (!src_addr)
    3.87 +      {
    3.88 +        FUNCTION_EXIT();
    3.89 +        return FALSE;
    3.90 +      }
    3.91 +      copy_size = min(bytes_remaining, MmGetMdlByteCount(pi->curr_mdl) - pi->curr_mdl_offset);
    3.92 +      KdPrint((__DRIVER_NAME "     B copy_size = %d\n", copy_size));
    3.93 +      memcpy(header + pi->header_length,
    3.94 +        src_addr + pi->curr_mdl_offset, copy_size);
    3.95 +      pi->curr_mdl_offset = (USHORT)(pi->curr_mdl_offset + copy_size);
    3.96 +      pi->header_length += copy_size;
    3.97 +      bytes_remaining -= copy_size;
    3.98 +    }
    3.99 +    if (pi->curr_mdl_offset == MmGetMdlByteCount(pi->curr_mdl))
   3.100 +    {
   3.101 +      NdisGetNextBuffer(pi->curr_mdl, &pi->curr_mdl);
   3.102 +      if (pi->curr_pb)
   3.103 +        pi->curr_pb = pi->curr_pb->next;
   3.104 +      pi->curr_mdl_offset = 0;
   3.105 +    }
   3.106 +  }
   3.107 +  KdPrint((__DRIVER_NAME "     C bytes_remaining = %d, pi->curr_mdl = %p\n", bytes_remaining, pi->curr_mdl));
   3.108 +  if (bytes_remaining)
   3.109 +  {
   3.110 +    KdPrint((__DRIVER_NAME "     bytes_remaining\n"));
   3.111 +    FUNCTION_EXIT();
   3.112 +    return FALSE;
   3.113 +  }
   3.114 +  FUNCTION_EXIT();
   3.115 +  return TRUE;
   3.116 +}
   3.117 +
   3.118 +ULONG
   3.119 +XenNet_ParsePacketHeader(packet_info_t *pi, PUCHAR alt_buffer, ULONG min_header_size)
   3.120 +{
   3.121 +  FUNCTION_ENTER();
   3.122 +
   3.123 +  ASSERT(pi->first_mdl);
   3.124 +  
   3.125 +  NdisQueryMdl(pi->first_mdl, (PVOID)&pi->first_mdl_virtual, &pi->first_mdl_length, NormalPagePriority);
   3.126 +  pi->curr_mdl = pi->first_mdl;
   3.127 +  if (alt_buffer)
   3.128 +    pi->header = alt_buffer;
   3.129 +  else
   3.130 +    pi->header = pi->first_mdl_virtual;
   3.131 +
   3.132 +  pi->header_length = 0;
   3.133 +  pi->curr_mdl_offset = pi->first_mdl_offset;
   3.134 +
   3.135 +  XenNet_BuildHeader(pi, NULL, min_header_size);
   3.136 +  
   3.137 +  if (!XenNet_BuildHeader(pi, NULL, (ULONG)XN_HDR_SIZE))
   3.138 +  {
   3.139 +    KdPrint((__DRIVER_NAME "     packet too small (Ethernet Header)\n"));
   3.140 +    return PARSE_TOO_SMALL;
   3.141 +  }
   3.142 +
   3.143 +  switch (GET_NET_PUSHORT(&pi->header[12])) // L2 protocol field
   3.144 +  {
   3.145 +  case 0x0800: /* IPv4 */
   3.146 +    KdPrint((__DRIVER_NAME "     IP\n"));
   3.147 +    if (pi->header_length < (ULONG)(XN_HDR_SIZE + 20))
   3.148 +    {
   3.149 +      if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + 20)))
   3.150 +      {
   3.151 +        KdPrint((__DRIVER_NAME "     packet too small (IP Header)\n"));
   3.152 +        return PARSE_TOO_SMALL;
   3.153 +      }
   3.154 +    }
   3.155 +    pi->ip_version = (pi->header[XN_HDR_SIZE + 0] & 0xF0) >> 4;
   3.156 +    if (pi->ip_version != 4)
   3.157 +    {
   3.158 +      KdPrint((__DRIVER_NAME "     ip_version = %d\n", pi->ip_version));
   3.159 +      return PARSE_UNKNOWN_TYPE;
   3.160 +    }
   3.161 +    pi->ip4_header_length = (pi->header[XN_HDR_SIZE + 0] & 0x0F) << 2;
   3.162 +    if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20))
   3.163 +    {
   3.164 +      if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20)))
   3.165 +      {
   3.166 +        KdPrint((__DRIVER_NAME "     packet too small (IP Header + IP Options + TCP Header)\n"));
   3.167 +        return PARSE_TOO_SMALL;
   3.168 +      }
   3.169 +    }
   3.170 +    break;
   3.171 +  case 0x86DD:  /* IPv6 */
   3.172 +    KdPrint((__DRIVER_NAME "     IPv6\n"));
   3.173 +    KdPrint((__DRIVER_NAME "     (not currently used)\n"));
   3.174 +    return PARSE_UNKNOWN_TYPE;
   3.175 +  default:
   3.176 +    KdPrint((__DRIVER_NAME "     Not IP (%04x)\n", GET_NET_PUSHORT(&pi->header[12])));
   3.177 +    return PARSE_UNKNOWN_TYPE;
   3.178 +  }
   3.179 +  pi->ip_proto = pi->header[XN_HDR_SIZE + 9];
   3.180 +  switch (pi->ip_proto)
   3.181 +  {
   3.182 +  case 6:  // TCP
   3.183 +  case 17: // UDP
   3.184 +    break;
   3.185 +  default:
   3.186 +    KdPrint((__DRIVER_NAME "     Not TCP/UDP (%d)\n", pi->ip_proto));
   3.187 +    return PARSE_UNKNOWN_TYPE;
   3.188 +  }
   3.189 +  pi->ip4_length = GET_NET_PUSHORT(&pi->header[XN_HDR_SIZE + 2]);
   3.190 +  pi->tcp_header_length = (pi->header[XN_HDR_SIZE + pi->ip4_header_length + 12] & 0xf0) >> 2;
   3.191 +
   3.192 +  if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length))
   3.193 +  {
   3.194 +    if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length)))
   3.195 +    {
   3.196 +      KdPrint((__DRIVER_NAME "     packet too small (IP Header + IP Options + TCP Header + TCP Options)\n"));
   3.197 +      return PARSE_TOO_SMALL;
   3.198 +    }
   3.199 +  }
   3.200 +  
   3.201 +  if ((ULONG)XN_HDR_SIZE + pi->ip4_length > pi->total_length)
   3.202 +  {
   3.203 +    KdPrint((__DRIVER_NAME "     XN_HDR_SIZE + ip4_length (%d) > total_length (%d)\n", XN_HDR_SIZE + pi->ip4_length, pi->total_length));
   3.204 +    return PARSE_UNKNOWN_TYPE;
   3.205 +  }
   3.206 +
   3.207 +  pi->tcp_length = pi->ip4_length - pi->ip4_header_length - pi->tcp_header_length;
   3.208 +  pi->tcp_remaining = pi->tcp_length;
   3.209 +  pi->tcp_seq = GET_NET_PULONG(&pi->header[XN_HDR_SIZE + pi->ip4_header_length + 4]);
   3.210 +  pi->tcp_has_options = (BOOLEAN)(pi->tcp_header_length > 20);
   3.211 +  if (pi->mss > 0 && pi->tcp_length > pi->mss)
   3.212 +    pi->split_required = TRUE;
   3.213 +
   3.214 +  KdPrint((__DRIVER_NAME "     ip4_length = %d\n", pi->ip4_length));
   3.215 +  KdPrint((__DRIVER_NAME "     tcp_length = %d\n", pi->tcp_length));
   3.216 +  FUNCTION_EXIT();
   3.217 +  
   3.218 +  return PARSE_OK;
   3.219 +}
   3.220 +
   3.221 +VOID
   3.222 +XenNet_SumIpHeader(
   3.223 +  PUCHAR header,
   3.224 +  USHORT ip4_header_length
   3.225 +)
   3.226 +{
   3.227 +  ULONG csum = 0;
   3.228 +  USHORT i;
   3.229 +
   3.230 +  ASSERT(ip4_header_length > 12);
   3.231 +  ASSERT(!(ip4_header_length & 1));
   3.232 +
   3.233 +  header[XN_HDR_SIZE + 10] = 0;
   3.234 +  header[XN_HDR_SIZE + 11] = 0;
   3.235 +  for (i = 0; i < ip4_header_length; i += 2)
   3.236 +  {
   3.237 +    csum += GET_NET_PUSHORT(&header[XN_HDR_SIZE + i]);
   3.238 +  }
   3.239 +  while (csum & 0xFFFF0000)
   3.240 +    csum = (csum & 0xFFFF) + (csum >> 16);
   3.241 +  csum = ~csum;
   3.242 +  SET_NET_USHORT(&header[XN_HDR_SIZE + 10], (USHORT)csum);
   3.243 +}
   3.244 +
   3.245 +BOOLEAN
   3.246 +XenNet_FilterAcceptPacket(struct xennet_info *xi,packet_info_t *pi)
   3.247 +{
   3.248 +  BOOLEAN is_multicast = FALSE;
   3.249 +  BOOLEAN is_my_multicast = FALSE;
   3.250 +  BOOLEAN is_broadcast = FALSE;
   3.251 +  BOOLEAN is_directed = FALSE;
   3.252 +  ULONG i;
   3.253 +
   3.254 +  if (pi->header[0] == 0xFF && pi->header[1] == 0xFF
   3.255 +      && pi->header[2] == 0xFF && pi->header[3] == 0xFF
   3.256 +      && pi->header[4] == 0xFF && pi->header[5] == 0xFF)
   3.257 +  {
   3.258 +    is_broadcast = TRUE;
   3.259 +  }
   3.260 +  else if (pi->header[0] & 0x01)
   3.261 +  {
   3.262 +    is_multicast = TRUE;
   3.263 +    for (i = 0; i < xi->multicast_list_size; i++)
   3.264 +    {
   3.265 +      if (memcmp(xi->multicast_list[i], pi->header, 6) == 0)
   3.266 +        break;
   3.267 +    }
   3.268 +    if (i < xi->multicast_list_size)
   3.269 +    {
   3.270 +      is_my_multicast = TRUE;
   3.271 +    }    
   3.272 +  }
   3.273 +  if (memcmp(xi->curr_mac_addr, pi->header, ETH_ALEN) == 0)
   3.274 +  {
   3.275 +    is_directed = TRUE;
   3.276 +  }
   3.277 +
   3.278 +  if (is_directed && (xi->packet_filter & NDIS_PACKET_TYPE_DIRECTED))
   3.279 +  {
   3.280 +    return TRUE;
   3.281 +  }  
   3.282 +  if (is_my_multicast && (xi->packet_filter & NDIS_PACKET_TYPE_MULTICAST))
   3.283 +  {
   3.284 +    return TRUE;
   3.285 +  }
   3.286 +  if (is_multicast && (xi->packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST))
   3.287 +  {
   3.288 +    return TRUE;
   3.289 +  }
   3.290 +  if (is_broadcast && (xi->packet_filter & NDIS_PACKET_TYPE_BROADCAST))
   3.291 +  {
   3.292 +    return TRUE;
   3.293 +  }
   3.294 +  if (xi->packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS)
   3.295 +  {
   3.296 +    return TRUE;
   3.297 +  }
   3.298 +  return FALSE;
   3.299 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/xennet/xennet6_oid.c	Mon May 02 00:17:33 2011 +1000
     4.3 @@ -0,0 +1,843 @@
     4.4 +/*
     4.5 +PV Net Driver for Windows Xen HVM Domains
     4.6 +Copyright (C) 2007 James Harper
     4.7 +Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
     4.8 +
     4.9 +This program is free software; you can redistribute it and/or
    4.10 +modify it under the terms of the GNU General Public License
    4.11 +as published by the Free Software Foundation; either version 2
    4.12 +of the License, or (at your option) any later version.
    4.13 +
    4.14 +This program is distributed in the hope that it will be useful,
    4.15 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.16 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.17 +GNU General Public License for more details.
    4.18 +
    4.19 +You should have received a copy of the GNU General Public License
    4.20 +along with this program; if not, write to the Free Software
    4.21 +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    4.22 +*/
    4.23 +
    4.24 +#include "xennet6.h"
    4.25 +
    4.26 +/* return 4 or 8 depending on size of buffer */
    4.27 +#define HANDLE_STAT_RETURN \
    4.28 +  {if (InformationBufferLength == 4) { \
    4.29 +    len = 4; *BytesNeeded = 8; \
    4.30 +    } else { \
    4.31 +    len = 8; \
    4.32 +    } }
    4.33 +
    4.34 +#define SET_LEN_AND_BREAK_IF_SHORT(_len) do { len = _len; if (len > InformationBufferLength) break; } while(0)
    4.35 +  
    4.36 +static NDIS_STATUS
    4.37 +XenNet_QueryInformation(
    4.38 +  IN NDIS_HANDLE MiniportAdapterContext,
    4.39 +  IN NDIS_OID Oid,
    4.40 +  IN PVOID InformationBuffer,
    4.41 +  IN ULONG InformationBufferLength,
    4.42 +  OUT PUINT BytesWritten,
    4.43 +  OUT PUINT BytesNeeded)
    4.44 +{
    4.45 +  NDIS_STATUS status = NDIS_STATUS_SUCCESS;
    4.46 +  struct xennet_info *xi = MiniportAdapterContext;
    4.47 +  BOOLEAN used_temp_buffer = TRUE;
    4.48 +  UINT len = 4;
    4.49 +  ULONG64 temp_data;
    4.50 +  PVOID data = &temp_data;
    4.51 +  PNDIS_INTERRUPT_MODERATION_PARAMETERS nimp;
    4.52 +#if 0
    4.53 +  UCHAR vendor_desc[] = XN_VENDOR_DESC;
    4.54 +  PNDIS_TASK_OFFLOAD_HEADER ntoh;
    4.55 +  PNDIS_TASK_OFFLOAD nto;
    4.56 +  PNDIS_TASK_TCP_IP_CHECKSUM nttic;
    4.57 +  PNDIS_TASK_TCP_LARGE_SEND nttls;
    4.58 +  PNDIS_PNP_CAPABILITIES npc;
    4.59 +#endif
    4.60 +
    4.61 +  *BytesNeeded = 0;
    4.62 +  *BytesWritten = 0;
    4.63 +
    4.64 +// FUNCTION_ENTER()
    4.65 +
    4.66 +  switch(Oid)
    4.67 +  {
    4.68 +#if 0
    4.69 +    case OID_GEN_SUPPORTED_LIST:
    4.70 +      data = supported_oids;
    4.71 +      len = sizeof(supported_oids);
    4.72 +      break;
    4.73 +    case OID_GEN_HARDWARE_STATUS:
    4.74 +      if (!xi->connected)
    4.75 +      {
    4.76 +        temp_data = NdisHardwareStatusInitializing;
    4.77 +        FUNCTION_MSG("NdisHardwareStatusInitializing\n");
    4.78 +      }
    4.79 +      else
    4.80 +      {
    4.81 +        temp_data = NdisHardwareStatusReady;
    4.82 +        FUNCTION_MSG("NdisHardwareStatusReady\n");
    4.83 +      }
    4.84 +      break;
    4.85 +    case OID_GEN_MEDIA_SUPPORTED:
    4.86 +      temp_data = NdisMedium802_3;
    4.87 +      break;
    4.88 +    case OID_GEN_MEDIA_IN_USE:
    4.89 +      temp_data = NdisMedium802_3;
    4.90 +      break;
    4.91 +    case OID_GEN_MAXIMUM_LOOKAHEAD:
    4.92 +      temp_data = MAX_LOOKAHEAD_LENGTH; //xi->config_mtu;
    4.93 +      break;
    4.94 +    case OID_GEN_MAXIMUM_FRAME_SIZE:
    4.95 +      temp_data = xi->config_mtu;
    4.96 +      break;
    4.97 +    case OID_GEN_LINK_SPEED:
    4.98 +      temp_data = 10000000; /* 1Gb */
    4.99 +      break;
   4.100 +    case OID_GEN_TRANSMIT_BUFFER_SPACE:
   4.101 +      /* multiply this by some small number as we can queue additional packets */
   4.102 +      temp_data = PAGE_SIZE * NET_TX_RING_SIZE * 4;
   4.103 +      break;
   4.104 +    case OID_GEN_RECEIVE_BUFFER_SPACE:
   4.105 +      temp_data = PAGE_SIZE * NET_RX_RING_SIZE * 2;
   4.106 +      break;
   4.107 +    case OID_GEN_TRANSMIT_BLOCK_SIZE:
   4.108 +      temp_data = PAGE_SIZE; //XN_MAX_PKT_SIZE;
   4.109 +      break;
   4.110 +    case OID_GEN_RECEIVE_BLOCK_SIZE:
   4.111 +      temp_data = PAGE_SIZE; //XN_MAX_PKT_SIZE;
   4.112 +      break;
   4.113 +    case OID_GEN_VENDOR_ID:
   4.114 +      temp_data = 0xFFFFFF; // Not guaranteed to be XENSOURCE_MAC_HDR;
   4.115 +      break;
   4.116 +    case OID_GEN_VENDOR_DESCRIPTION:
   4.117 +      data = vendor_desc;
   4.118 +      len = sizeof(vendor_desc);
   4.119 +      break;
   4.120 +    case OID_GEN_DRIVER_VERSION:
   4.121 +      temp_data = (NDIS_MINIPORT_MAJOR_VERSION << 8) | NDIS_MINIPORT_MINOR_VERSION;
   4.122 +      len = 2;
   4.123 +      break;
   4.124 +    case OID_GEN_VENDOR_DRIVER_VERSION:
   4.125 +      temp_data = VENDOR_DRIVER_VERSION;
   4.126 +      len = 4;
   4.127 +      break;
   4.128 +    case OID_GEN_MAC_OPTIONS:
   4.129 +      temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | 
   4.130 +        NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
   4.131 +        NDIS_MAC_OPTION_NO_LOOPBACK;
   4.132 +      break;
   4.133 +    case OID_GEN_MEDIA_CONNECT_STATUS:
   4.134 +      if (xi->connected && !xi->inactive)
   4.135 +        temp_data = NdisMediaStateConnected;
   4.136 +      else
   4.137 +        temp_data = NdisMediaStateDisconnected;
   4.138 +      break;
   4.139 +    case OID_GEN_MAXIMUM_SEND_PACKETS:
   4.140 +      /* this is actually ignored for deserialised drivers like us */
   4.141 +      temp_data = 0; //XN_MAX_SEND_PKTS;
   4.142 +      break;
   4.143 +    case OID_GEN_RCV_OK:
   4.144 +      temp_data = xi->stat_rx_ok;
   4.145 +      HANDLE_STAT_RETURN;
   4.146 +      break;
   4.147 +    case OID_GEN_XMIT_ERROR:
   4.148 +      temp_data = xi->stat_tx_error;
   4.149 +      HANDLE_STAT_RETURN;
   4.150 +      break;
   4.151 +    case OID_GEN_RCV_ERROR:
   4.152 +      temp_data = xi->stat_rx_error;
   4.153 +      HANDLE_STAT_RETURN;
   4.154 +      break;
   4.155 +    case OID_GEN_RCV_NO_BUFFER:
   4.156 +      temp_data = xi->stat_rx_no_buffer;
   4.157 +      HANDLE_STAT_RETURN;
   4.158 +      break;
   4.159 +    case OID_802_3_PERMANENT_ADDRESS:
   4.160 +      data = xi->perm_mac_addr;
   4.161 +      len = ETH_ALEN;
   4.162 +      break;
   4.163 +    case OID_802_3_RCV_ERROR_ALIGNMENT:
   4.164 +    case OID_802_3_XMIT_ONE_COLLISION:
   4.165 +    case OID_802_3_XMIT_MORE_COLLISIONS:
   4.166 +      temp_data = 0;
   4.167 +      HANDLE_STAT_RETURN;
   4.168 +      break;
   4.169 +    case OID_802_3_MAXIMUM_LIST_SIZE:
   4.170 +      temp_data = MULTICAST_LIST_MAX_SIZE;
   4.171 +      break;
   4.172 +    case OID_TCP_TASK_OFFLOAD:
   4.173 +      KdPrint(("Get OID_TCP_TASK_OFFLOAD\n"));
   4.174 +      /* it's times like this that C really sucks */
   4.175 +
   4.176 +      len = sizeof(NDIS_TASK_OFFLOAD_HEADER);
   4.177 +
   4.178 +      if (xi->config_csum)
   4.179 +      {
   4.180 +        len += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
   4.181 +          + sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
   4.182 +      }
   4.183 +
   4.184 +      if (xi->config_gso)
   4.185 +      {
   4.186 +        len += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
   4.187 +          + sizeof(NDIS_TASK_TCP_LARGE_SEND);
   4.188 +      }
   4.189 +
   4.190 +      //len += 1024;
   4.191 +
   4.192 +      if (len > InformationBufferLength)
   4.193 +      {
   4.194 +          break;
   4.195 +      }
   4.196 +
   4.197 +      ntoh = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer;
   4.198 +      if (ntoh->Version != NDIS_TASK_OFFLOAD_VERSION
   4.199 +        || ntoh->Size != sizeof(*ntoh)
   4.200 +        || !(
   4.201 +          ntoh->EncapsulationFormat.Encapsulation == IEEE_802_3_Encapsulation
   4.202 +          || (ntoh->EncapsulationFormat.Encapsulation == UNSPECIFIED_Encapsulation
   4.203 +              && ntoh->EncapsulationFormat.EncapsulationHeaderSize == XN_HDR_SIZE)))
   4.204 +      {
   4.205 +        status = NDIS_STATUS_NOT_SUPPORTED;
   4.206 +        break;
   4.207 +      }
   4.208 +      ntoh->OffsetFirstTask = 0; 
   4.209 +      nto = NULL;
   4.210 +
   4.211 +      if (xi->config_csum)
   4.212 +      {
   4.213 +        if (ntoh->OffsetFirstTask == 0)
   4.214 +        {
   4.215 +          ntoh->OffsetFirstTask = ntoh->Size;
   4.216 +          nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + ntoh->OffsetFirstTask);
   4.217 +        }
   4.218 +        else
   4.219 +        {
   4.220 +          nto->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
   4.221 +            + nto->TaskBufferLength;
   4.222 +          nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(nto) + nto->OffsetNextTask);
   4.223 +        }
   4.224 +        /* fill in first nto */
   4.225 +        nto->Version = NDIS_TASK_OFFLOAD_VERSION;
   4.226 +        nto->Size = sizeof(NDIS_TASK_OFFLOAD);
   4.227 +        nto->Task = TcpIpChecksumNdisTask;
   4.228 +        nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
   4.229 +
   4.230 +        KdPrint(("config_csum enabled\n"));
   4.231 +        KdPrint(("nto = %p\n", nto));
   4.232 +        KdPrint(("nto->Size = %d\n", nto->Size));
   4.233 +        KdPrint(("nto->TaskBufferLength = %d\n", nto->TaskBufferLength));
   4.234 +
   4.235 +        /* fill in checksum offload struct */
   4.236 +        nttic = (PNDIS_TASK_TCP_IP_CHECKSUM)nto->TaskBuffer;
   4.237 +        nttic->V4Transmit.IpChecksum = 0;
   4.238 +        nttic->V4Transmit.IpOptionsSupported = 0;
   4.239 +        nttic->V4Transmit.TcpChecksum = 1;
   4.240 +        nttic->V4Transmit.TcpOptionsSupported = 1;
   4.241 +        nttic->V4Transmit.UdpChecksum = 1;
   4.242 +        nttic->V4Receive.IpChecksum = 1;
   4.243 +        nttic->V4Receive.IpOptionsSupported = 1;
   4.244 +        nttic->V4Receive.TcpChecksum = 1;
   4.245 +        nttic->V4Receive.TcpOptionsSupported = 1;
   4.246 +        nttic->V4Receive.UdpChecksum = 1;
   4.247 +        nttic->V6Transmit.IpOptionsSupported = 0;
   4.248 +        nttic->V6Transmit.TcpOptionsSupported = 0;
   4.249 +        nttic->V6Transmit.TcpChecksum = 0;
   4.250 +        nttic->V6Transmit.UdpChecksum = 0;
   4.251 +        nttic->V6Receive.IpOptionsSupported = 0;
   4.252 +        nttic->V6Receive.TcpOptionsSupported = 0;
   4.253 +        nttic->V6Receive.TcpChecksum = 0;
   4.254 +        nttic->V6Receive.UdpChecksum = 0;
   4.255 +      }
   4.256 +      if (xi->config_gso)
   4.257 +      {
   4.258 +        if (ntoh->OffsetFirstTask == 0)
   4.259 +        {
   4.260 +          ntoh->OffsetFirstTask = ntoh->Size;
   4.261 +          nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + ntoh->OffsetFirstTask);
   4.262 +        }
   4.263 +        else
   4.264 +        {
   4.265 +          nto->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
   4.266 +            + nto->TaskBufferLength;
   4.267 +          nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(nto) + nto->OffsetNextTask);
   4.268 +        }
   4.269 +  
   4.270 +        /* fill in second nto */
   4.271 +        nto->Version = NDIS_TASK_OFFLOAD_VERSION;
   4.272 +        nto->Size = sizeof(NDIS_TASK_OFFLOAD);
   4.273 +        nto->Task = TcpLargeSendNdisTask;
   4.274 +        nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND);
   4.275 +
   4.276 +        KdPrint(("config_gso enabled\n"));
   4.277 +        KdPrint(("nto = %p\n", nto));
   4.278 +        KdPrint(("nto->Size = %d\n", nto->Size));
   4.279 +        KdPrint(("nto->TaskBufferLength = %d\n", nto->TaskBufferLength));
   4.280 +  
   4.281 +        /* fill in large send struct */
   4.282 +        nttls = (PNDIS_TASK_TCP_LARGE_SEND)nto->TaskBuffer;
   4.283 +        nttls->Version = 0;
   4.284 +        nttls->MaxOffLoadSize = xi->config_gso;
   4.285 +        nttls->MinSegmentCount = MIN_LARGE_SEND_SEGMENTS;
   4.286 +        nttls->TcpOptions = FALSE; /* linux can't handle this */
   4.287 +        nttls->IpOptions = FALSE; /* linux can't handle this */
   4.288 +        KdPrint(("&(nttls->IpOptions) = %p\n", &(nttls->IpOptions)));        
   4.289 +      }
   4.290 +
   4.291 +      if (nto)
   4.292 +        nto->OffsetNextTask = 0; /* last one */
   4.293 +
   4.294 +      used_temp_buffer = FALSE;
   4.295 +      break;
   4.296 +    case OID_IP4_OFFLOAD_STATS:
   4.297 +    case OID_IP6_OFFLOAD_STATS:
   4.298 +      /* these are called often so just ignore then quietly */
   4.299 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.300 +      break;
   4.301 +
   4.302 +    case OID_PNP_CAPABILITIES:
   4.303 +      KdPrint(("Get OID_PNP_CAPABILITIES\n"));
   4.304 +      len = sizeof(NDIS_PNP_CAPABILITIES);
   4.305 +      if (len > InformationBufferLength)
   4.306 +        break;
   4.307 +      npc = (PNDIS_PNP_CAPABILITIES)InformationBuffer;
   4.308 +      npc->Flags = 0;
   4.309 +      npc->WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
   4.310 +      npc->WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified;
   4.311 +      npc->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
   4.312 +      used_temp_buffer = FALSE;
   4.313 +      break;
   4.314 +    case OID_PNP_QUERY_POWER:
   4.315 +      KdPrint(("Get OID_PNP_CAPABILITIES\n"));
   4.316 +      used_temp_buffer = FALSE;
   4.317 +      break;
   4.318 +
   4.319 +#endif
   4.320 +    case OID_GEN_MAXIMUM_TOTAL_SIZE:
   4.321 +      temp_data = xi->config_mtu + XN_HDR_SIZE;
   4.322 +      break;
   4.323 +    case OID_GEN_INTERRUPT_MODERATION:
   4.324 +      SET_LEN_AND_BREAK_IF_SHORT(sizeof(NDIS_INTERRUPT_MODERATION_PARAMETERS));
   4.325 +      nimp = (PNDIS_INTERRUPT_MODERATION_PARAMETERS)InformationBuffer;
   4.326 +      nimp->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
   4.327 +      nimp->Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
   4.328 +      nimp->Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
   4.329 +      nimp->Flags = 0;
   4.330 +      nimp->InterruptModeration = NdisInterruptModerationNotSupported;
   4.331 +      break;
   4.332 +    case OID_GEN_CURRENT_PACKET_FILTER:
   4.333 +      temp_data = xi->packet_filter;
   4.334 +      break;
   4.335 +    case OID_GEN_CURRENT_LOOKAHEAD:
   4.336 +      temp_data = xi->current_lookahead;
   4.337 +      break;
   4.338 +    case OID_802_3_CURRENT_ADDRESS:
   4.339 +      data = xi->curr_mac_addr;
   4.340 +      len = ETH_ALEN;
   4.341 +      break;
   4.342 +    case OID_802_3_PERMANENT_ADDRESS:
   4.343 +      data = xi->perm_mac_addr;
   4.344 +      len = ETH_ALEN;
   4.345 +      break;
   4.346 +    case OID_802_3_MULTICAST_LIST:
   4.347 +      data = xi->multicast_list;
   4.348 +      len = xi->multicast_list_size * 6;
   4.349 +      break;
   4.350 +    case OID_GEN_XMIT_OK:
   4.351 +      temp_data = xi->stat_tx_ok;
   4.352 +      HANDLE_STAT_RETURN;
   4.353 +      break;
   4.354 +    default:
   4.355 +      KdPrint(("Get Unknown OID 0x%x\n", Oid));
   4.356 +    /* silently fail these */
   4.357 +    case OID_GEN_MACHINE_NAME:
   4.358 +    case OID_GEN_SUPPORTED_GUIDS:
   4.359 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.360 +    break;
   4.361 +  }
   4.362 +
   4.363 +  if (!NT_SUCCESS(status))
   4.364 +  {
   4.365 +    //FUNCTION_EXIT_STATUS(status);
   4.366 +    return status;
   4.367 +  }
   4.368 +
   4.369 +  if (len > InformationBufferLength)
   4.370 +  {
   4.371 +    *BytesNeeded = len;
   4.372 +    FUNCTION_MSG("(BUFFER_TOO_SHORT %d > %d)\n", len, InformationBufferLength);
   4.373 +    return NDIS_STATUS_BUFFER_TOO_SHORT;
   4.374 +  }
   4.375 +
   4.376 +  *BytesWritten = len;
   4.377 +  if (len && used_temp_buffer)
   4.378 +  {
   4.379 +    NdisMoveMemory((PUCHAR)InformationBuffer, data, len);
   4.380 +  }
   4.381 +
   4.382 +  //KdPrint(("Got OID 0x%x\n", Oid));
   4.383 +//  KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
   4.384 +
   4.385 +  return status;
   4.386 +}
   4.387 +
   4.388 +NDIS_STATUS
   4.389 +XenNet_SetInformation(
   4.390 +  IN NDIS_HANDLE adapter_context,
   4.391 +  IN NDIS_OID Oid,
   4.392 +  IN PVOID InformationBuffer,
   4.393 +  IN ULONG InformationBufferLength,
   4.394 +  OUT PUINT BytesRead,
   4.395 +  OUT PUINT BytesNeeded
   4.396 +  )
   4.397 +{
   4.398 +  NTSTATUS status;
   4.399 +  struct xennet_info *xi = adapter_context;
   4.400 +  PULONG64 data = InformationBuffer;
   4.401 +  ULONG i;
   4.402 +  UCHAR *multicast_list;
   4.403 +#if 0
   4.404 +  PNDIS_TASK_OFFLOAD_HEADER ntoh;
   4.405 +  PNDIS_TASK_OFFLOAD nto;
   4.406 +  PNDIS_TASK_TCP_IP_CHECKSUM nttic = NULL;
   4.407 +  PNDIS_TASK_TCP_LARGE_SEND nttls = NULL;
   4.408 +  int offset;
   4.409 +#endif
   4.410 +  //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
   4.411 +
   4.412 +  UNREFERENCED_PARAMETER(BytesRead);
   4.413 +  UNREFERENCED_PARAMETER(BytesNeeded);
   4.414 +  switch(Oid)
   4.415 +  {
   4.416 +#if 0
   4.417 +    case OID_GEN_SUPPORTED_LIST:
   4.418 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.419 +      KdPrint(("Unsupported set OID_GEN_SUPPORTED_LIST\n"));
   4.420 +      break;
   4.421 +    case OID_GEN_HARDWARE_STATUS:
   4.422 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.423 +      KdPrint(("Unsupported set OID_GEN_HARDWARE_STATUS\n"));
   4.424 +      break;
   4.425 +    case OID_GEN_MEDIA_SUPPORTED:
   4.426 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.427 +      KdPrint(("Unsupported set OID_GEN_MEDIA_SUPPORTED\n"));
   4.428 +      break;
   4.429 +    case OID_GEN_MEDIA_IN_USE:
   4.430 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.431 +      KdPrint(("Unsupported set OID_GEN_MEDIA_IN_USE\n"));
   4.432 +      break;
   4.433 +    case OID_GEN_MAXIMUM_LOOKAHEAD:
   4.434 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.435 +      KdPrint(("Unsupported set OID_GEN_MAXIMUM_LOOKAHEAD\n"));
   4.436 +      break;
   4.437 +    case OID_GEN_MAXIMUM_FRAME_SIZE:
   4.438 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.439 +      KdPrint(("Unsupported set OID_GEN_MAXIMUM_FRAME_SIZE\n"));
   4.440 +      break;
   4.441 +    case OID_GEN_LINK_SPEED:
   4.442 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.443 +      KdPrint(("Unsupported set OID_GEN_LINK_SPEED\n"));
   4.444 +      break;
   4.445 +    case OID_GEN_TRANSMIT_BUFFER_SPACE:
   4.446 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.447 +      KdPrint(("Unsupported set OID_GEN_TRANSMIT_BUFFER_SPACE\n"));
   4.448 +      break;
   4.449 +    case OID_GEN_RECEIVE_BUFFER_SPACE:
   4.450 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.451 +      KdPrint(("Unsupported set OID_GEN_RECEIVE_BUFFER_SPACE\n"));
   4.452 +      break;
   4.453 +    case OID_GEN_TRANSMIT_BLOCK_SIZE:
   4.454 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.455 +      KdPrint(("Unsupported set OID_GEN_TRANSMIT_BLOCK_SIZE\n"));
   4.456 +      break;
   4.457 +    case OID_GEN_RECEIVE_BLOCK_SIZE:
   4.458 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.459 +      KdPrint(("Unsupported set OID_GEN_RECEIVE_BLOCK_SIZE\n"));
   4.460 +      break;
   4.461 +    case OID_GEN_VENDOR_ID:
   4.462 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.463 +      KdPrint(("Unsupported set OID_GEN_VENDOR_ID\n"));
   4.464 +      break;
   4.465 +    case OID_GEN_VENDOR_DESCRIPTION:
   4.466 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.467 +      KdPrint(("Unsupported set OID_GEN_VENDOR_DESCRIPTION\n"));
   4.468 +      break;
   4.469 +    case OID_GEN_DRIVER_VERSION:
   4.470 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.471 +      KdPrint(("Unsupported set OID_GEN_DRIVER_VERSION\n"));
   4.472 +      break;
   4.473 +    case OID_GEN_MAXIMUM_TOTAL_SIZE:
   4.474 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.475 +      KdPrint(("Unsupported set OID_GEN_MAXIMUM_TOTAL_SIZE\n"));
   4.476 +      break;
   4.477 +    case OID_GEN_PROTOCOL_OPTIONS:
   4.478 +      KdPrint(("Unsupported set OID_GEN_PROTOCOL_OPTIONS\n"));
   4.479 +      // TODO - actually do this...
   4.480 +      status = NDIS_STATUS_SUCCESS;
   4.481 +      break;
   4.482 +    case OID_GEN_MAC_OPTIONS:
   4.483 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.484 +      KdPrint(("Unsupported set OID_GEN_MAC_OPTIONS\n"));
   4.485 +      break;
   4.486 +    case OID_GEN_MEDIA_CONNECT_STATUS:
   4.487 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.488 +      KdPrint(("Unsupported set OID_GEN_MEDIA_CONNECT_STATUS\n"));
   4.489 +      break;
   4.490 +    case OID_GEN_MAXIMUM_SEND_PACKETS:
   4.491 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.492 +      KdPrint(("Unsupported set OID_GEN_MAXIMUM_SEND_PACKETS\n"));
   4.493 +      break;
   4.494 +    case OID_GEN_XMIT_OK:
   4.495 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.496 +      KdPrint(("Unsupported set OID_GEN_XMIT_OK\n"));
   4.497 +      break;
   4.498 +    case OID_GEN_RCV_OK:
   4.499 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.500 +      KdPrint(("Unsupported set OID_GEN_RCV_OK\n"));
   4.501 +      break;
   4.502 +    case OID_GEN_XMIT_ERROR:
   4.503 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.504 +      KdPrint(("Unsupported set OID_GEN_XMIT_ERROR\n"));
   4.505 +      break;
   4.506 +    case OID_GEN_RCV_ERROR:
   4.507 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.508 +      KdPrint(("Unsupported set OID_GEN_RCV_ERROR\n"));
   4.509 +      break;
   4.510 +    case OID_GEN_RCV_NO_BUFFER:
   4.511 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.512 +      KdPrint(("Unsupported set OID_GEN_RCV_NO_BUFFER\n"));
   4.513 +      break;
   4.514 +    case OID_802_3_CURRENT_ADDRESS:
   4.515 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.516 +      KdPrint(("Unsupported set OID_802_3_CURRENT_ADDRESS\n"));
   4.517 +      break;
   4.518 +    case OID_802_3_MULTICAST_LIST:
   4.519 +      KdPrint(("     Set OID_802_3_MULTICAST_LIST\n"));
   4.520 +      KdPrint(("       Length = %d\n", InformationBufferLength));
   4.521 +      KdPrint(("       Entries = %d\n", InformationBufferLength / 6));
   4.522 +      if (InformationBufferLength > MULTICAST_LIST_MAX_SIZE * 6)
   4.523 +      {
   4.524 +        status = NDIS_STATUS_MULTICAST_FULL;
   4.525 +        break;
   4.526 +      }
   4.527 +      
   4.528 +      if (InformationBufferLength % 6 != 0)
   4.529 +      {
   4.530 +        status = NDIS_STATUS_MULTICAST_FULL;
   4.531 +        break;
   4.532 +      }
   4.533 +      multicast_list = InformationBuffer;
   4.534 +      for (i = 0; i < InformationBufferLength / 6; i++)
   4.535 +      {
   4.536 +        if (!(multicast_list[i * 6 + 0] & 0x01))
   4.537 +        {
   4.538 +          KdPrint(("       Address %d (%02x:%02x:%02x:%02x:%02x:%02x) is not a multicast address\n", i,
   4.539 +            (ULONG)multicast_list[i * 6 + 0], (ULONG)multicast_list[i * 6 + 1], 
   4.540 +            (ULONG)multicast_list[i * 6 + 2], (ULONG)multicast_list[i * 6 + 3], 
   4.541 +            (ULONG)multicast_list[i * 6 + 4], (ULONG)multicast_list[i * 6 + 5]));
   4.542 +          /* the docs say that we should return NDIS_STATUS_MULTICAST_FULL if we get an invalid multicast address but I'm not sure if that's the case... */
   4.543 +        }
   4.544 +      }
   4.545 +      memcpy(xi->multicast_list, InformationBuffer, InformationBufferLength);
   4.546 +      xi->multicast_list_size = InformationBufferLength / 6;
   4.547 +      status = NDIS_STATUS_SUCCESS;
   4.548 +      break;
   4.549 +    case OID_802_3_MAXIMUM_LIST_SIZE:
   4.550 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.551 +      KdPrint(("Unsupported set OID_802_3_MAXIMUM_LIST_SIZE\n"));
   4.552 +      break;
   4.553 +    case OID_TCP_TASK_OFFLOAD:
   4.554 +      status = NDIS_STATUS_SUCCESS;
   4.555 +      KdPrint(("Set OID_TCP_TASK_OFFLOAD\n"));
   4.556 +      // we should disable everything here, then enable what has been set
   4.557 +      ntoh = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer;
   4.558 +      if (ntoh->Version != NDIS_TASK_OFFLOAD_VERSION)
   4.559 +      {
   4.560 +        KdPrint(("Invalid version (%d passed but must be %d)\n", ntoh->Version, NDIS_TASK_OFFLOAD_VERSION));
   4.561 +        status = NDIS_STATUS_INVALID_DATA;
   4.562 +        break;
   4.563 +      }
   4.564 +      if (ntoh->Version != NDIS_TASK_OFFLOAD_VERSION || ntoh->Size != sizeof(NDIS_TASK_OFFLOAD_HEADER))
   4.565 +      {
   4.566 +        KdPrint(("Invalid size (%d passed but must be %d)\n", ntoh->Size, sizeof(NDIS_TASK_OFFLOAD_HEADER)));
   4.567 +        status = NDIS_STATUS_INVALID_DATA;
   4.568 +        break;
   4.569 +      }
   4.570 +      *BytesRead = sizeof(NDIS_TASK_OFFLOAD_HEADER);
   4.571 +      offset = ntoh->OffsetFirstTask;
   4.572 +      nto = (PNDIS_TASK_OFFLOAD)ntoh; // not really, just to get the first offset right
   4.573 +      while (offset != 0)
   4.574 +      {
   4.575 +        *BytesRead += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer);
   4.576 +        nto = (PNDIS_TASK_OFFLOAD)(((PUCHAR)nto) + offset);
   4.577 +        switch (nto->Task)
   4.578 +        {
   4.579 +        case TcpIpChecksumNdisTask:
   4.580 +          *BytesRead += sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
   4.581 +          nttic = (PNDIS_TASK_TCP_IP_CHECKSUM)nto->TaskBuffer;
   4.582 +          KdPrint(("TcpIpChecksumNdisTask\n"));
   4.583 +          KdPrint(("  V4Transmit.IpOptionsSupported  = %d\n", nttic->V4Transmit.IpOptionsSupported));
   4.584 +          KdPrint(("  V4Transmit.TcpOptionsSupported = %d\n", nttic->V4Transmit.TcpOptionsSupported));
   4.585 +          KdPrint(("  V4Transmit.TcpChecksum         = %d\n", nttic->V4Transmit.TcpChecksum));
   4.586 +          KdPrint(("  V4Transmit.UdpChecksum         = %d\n", nttic->V4Transmit.UdpChecksum));
   4.587 +          KdPrint(("  V4Transmit.IpChecksum          = %d\n", nttic->V4Transmit.IpChecksum));
   4.588 +          KdPrint(("  V4Receive.IpOptionsSupported   = %d\n", nttic->V4Receive.IpOptionsSupported));
   4.589 +          KdPrint(("  V4Receive.TcpOptionsSupported  = %d\n", nttic->V4Receive.TcpOptionsSupported));
   4.590 +          KdPrint(("  V4Receive.TcpChecksum          = %d\n", nttic->V4Receive.TcpChecksum));
   4.591 +          KdPrint(("  V4Receive.UdpChecksum          = %d\n", nttic->V4Receive.UdpChecksum));
   4.592 +          KdPrint(("  V4Receive.IpChecksum           = %d\n", nttic->V4Receive.IpChecksum));
   4.593 +          KdPrint(("  V6Transmit.IpOptionsSupported  = %d\n", nttic->V6Transmit.IpOptionsSupported));
   4.594 +          KdPrint(("  V6Transmit.TcpOptionsSupported = %d\n", nttic->V6Transmit.TcpOptionsSupported));
   4.595 +          KdPrint(("  V6Transmit.TcpChecksum         = %d\n", nttic->V6Transmit.TcpChecksum));
   4.596 +          KdPrint(("  V6Transmit.UdpChecksum         = %d\n", nttic->V6Transmit.UdpChecksum));
   4.597 +          KdPrint(("  V6Receive.IpOptionsSupported   = %d\n", nttic->V6Receive.IpOptionsSupported));
   4.598 +          KdPrint(("  V6Receive.TcpOptionsSupported  = %d\n", nttic->V6Receive.TcpOptionsSupported));
   4.599 +          KdPrint(("  V6Receive.TcpChecksum          = %d\n", nttic->V6Receive.TcpChecksum));
   4.600 +          KdPrint(("  V6Receive.UdpChecksum          = %d\n", nttic->V6Receive.UdpChecksum));
   4.601 +          /* check for stuff we outright don't support */
   4.602 +          if (nttic->V6Transmit.IpOptionsSupported ||
   4.603 +            nttic->V6Transmit.TcpOptionsSupported ||
   4.604 +            nttic->V6Transmit.TcpChecksum ||
   4.605 +            nttic->V6Transmit.UdpChecksum ||
   4.606 +            nttic->V6Receive.IpOptionsSupported ||
   4.607 +            nttic->V6Receive.TcpOptionsSupported ||
   4.608 +            nttic->V6Receive.TcpChecksum ||
   4.609 +            nttic->V6Receive.UdpChecksum)
   4.610 +          {
   4.611 +            KdPrint(("IPv6 offload not supported\n"));
   4.612 +            status = NDIS_STATUS_INVALID_DATA;
   4.613 +            nttic = NULL;
   4.614 +            break;
   4.615 +          }
   4.616 +          if (nttic->V4Transmit.IpOptionsSupported ||
   4.617 +            nttic->V4Transmit.IpChecksum)
   4.618 +          {
   4.619 +            KdPrint(("IPv4 IP Transmit offload not supported\n"));
   4.620 +            status = NDIS_STATUS_INVALID_DATA;
   4.621 +            nttic = NULL;
   4.622 +            break;
   4.623 +          }
   4.624 +          if (nttic->V4Receive.IpOptionsSupported &&
   4.625 +            !nttic->V4Receive.IpChecksum)
   4.626 +          {
   4.627 +            KdPrint(("Invalid combination\n"));
   4.628 +            status = NDIS_STATUS_INVALID_DATA;
   4.629 +            nttic = NULL;
   4.630 +            break;
   4.631 +          }
   4.632 +          if (nttic->V4Transmit.TcpOptionsSupported &&
   4.633 +            !nttic->V4Transmit.TcpChecksum)
   4.634 +          {
   4.635 +            KdPrint(("Invalid combination\n"));
   4.636 +            status = NDIS_STATUS_INVALID_DATA;
   4.637 +            nttic = NULL;
   4.638 +            break;
   4.639 +          }
   4.640 +          if (nttic->V4Receive.TcpOptionsSupported &&
   4.641 +            !nttic->V4Receive.TcpChecksum)
   4.642 +          {
   4.643 +            KdPrint(("Invalid combination\n"));
   4.644 +            status = NDIS_STATUS_INVALID_DATA;
   4.645 +            nttic = NULL;
   4.646 +            break;
   4.647 +          }
   4.648 +          break;
   4.649 +        case TcpLargeSendNdisTask:
   4.650 +          *BytesRead += sizeof(NDIS_TASK_TCP_LARGE_SEND);
   4.651 +          KdPrint(("TcpLargeSendNdisTask\n"));
   4.652 +          nttls = (PNDIS_TASK_TCP_LARGE_SEND)nto->TaskBuffer;
   4.653 +          KdPrint(("  MaxOffLoadSize                 = %d\n", nttls->MaxOffLoadSize));
   4.654 +          KdPrint(("  MinSegmentCount                = %d\n", nttls->MinSegmentCount));
   4.655 +          KdPrint(("  TcpOptions                     = %d\n", nttls->TcpOptions));
   4.656 +          KdPrint(("  IpOptions                      = %d\n", nttls->IpOptions));
   4.657 +          if (nttls->MinSegmentCount != MIN_LARGE_SEND_SEGMENTS)
   4.658 +          {
   4.659 +            KdPrint(("     MinSegmentCount should be %d\n", MIN_LARGE_SEND_SEGMENTS));
   4.660 +            status = NDIS_STATUS_INVALID_DATA;
   4.661 +            nttls = NULL;
   4.662 +            break;
   4.663 +          }
   4.664 +          if (nttls->IpOptions)
   4.665 +          {
   4.666 +            KdPrint(("     IpOptions not supported\n"));
   4.667 +            status = NDIS_STATUS_INVALID_DATA;
   4.668 +            nttls = NULL;
   4.669 +            break;
   4.670 +          }
   4.671 +          if (nttls->TcpOptions)
   4.672 +          {
   4.673 +            KdPrint(("     TcpOptions not supported\n"));
   4.674 +            status = NDIS_STATUS_INVALID_DATA;
   4.675 +            nttls = NULL;
   4.676 +            break;
   4.677 +          }
   4.678 +          break;
   4.679 +        default:
   4.680 +          KdPrint(("     Unknown Task %d\n", nto->Task));
   4.681 +        }
   4.682 +        offset = nto->OffsetNextTask;
   4.683 +      }
   4.684 +      if (nttic != NULL)
   4.685 +        xi->setting_csum = *nttic;
   4.686 +      else
   4.687 +      {
   4.688 +        RtlZeroMemory(&xi->setting_csum, sizeof(NDIS_TASK_TCP_IP_CHECKSUM));
   4.689 +        KdPrint(("     csum offload disabled\n", nto->Task));
   4.690 +      }        
   4.691 +      if (nttls != NULL)
   4.692 +        xi->setting_max_offload = nttls->MaxOffLoadSize;
   4.693 +      else
   4.694 +      {
   4.695 +        xi->setting_max_offload = 0;
   4.696 +        KdPrint(("     LSO disabled\n", nto->Task));
   4.697 +      }
   4.698 +      break;
   4.699 +    case OID_PNP_SET_POWER:
   4.700 +      KdPrint(("     Set OID_PNP_SET_POWER\n"));
   4.701 +      xi->new_power_state = *(PNDIS_DEVICE_POWER_STATE)InformationBuffer;
   4.702 +      IoQueueWorkItem(xi->power_workitem, XenNet_SetPower, DelayedWorkQueue, xi);
   4.703 +      status = NDIS_STATUS_PENDING;
   4.704 +      break;
   4.705 +#endif
   4.706 +    case OID_GEN_CURRENT_PACKET_FILTER:
   4.707 +      KdPrint(("Set OID_GEN_CURRENT_PACKET_FILTER (xi = %p)\n", xi));
   4.708 +      if (*(ULONG *)data & NDIS_PACKET_TYPE_DIRECTED)
   4.709 +        KdPrint(("  NDIS_PACKET_TYPE_DIRECTED\n"));
   4.710 +      if (*(ULONG *)data & NDIS_PACKET_TYPE_MULTICAST)
   4.711 +        KdPrint(("  NDIS_PACKET_TYPE_MULTICAST\n"));
   4.712 +      if (*(ULONG *)data & NDIS_PACKET_TYPE_ALL_MULTICAST)
   4.713 +        KdPrint(("  NDIS_PACKET_TYPE_ALL_MULTICAST\n"));
   4.714 +      if (*(ULONG *)data & NDIS_PACKET_TYPE_BROADCAST)
   4.715 +        KdPrint(("  NDIS_PACKET_TYPE_BROADCAST\n"));
   4.716 +      if (*(ULONG *)data & NDIS_PACKET_TYPE_PROMISCUOUS)
   4.717 +        KdPrint(("  NDIS_PACKET_TYPE_PROMISCUOUS\n"));
   4.718 +      if (*(ULONG *)data & NDIS_PACKET_TYPE_ALL_FUNCTIONAL)
   4.719 +        KdPrint(("  NDIS_PACKET_TYPE_ALL_FUNCTIONAL (not supported)\n"));
   4.720 +      if (*(ULONG *)data & NDIS_PACKET_TYPE_ALL_LOCAL)
   4.721 +        KdPrint(("  NDIS_PACKET_TYPE_ALL_LOCAL (not supported)\n"));  
   4.722 +      if (*(ULONG *)data & NDIS_PACKET_TYPE_FUNCTIONAL)
   4.723 +        KdPrint(("  NDIS_PACKET_TYPE_FUNCTIONAL (not supported)\n"));
   4.724 +      if (*(ULONG *)data & NDIS_PACKET_TYPE_GROUP)
   4.725 +        KdPrint(("  NDIS_PACKET_TYPE_GROUP (not supported)\n"));
   4.726 +      if (*(ULONG *)data & ~SUPPORTED_PACKET_FILTERS)
   4.727 +      {
   4.728 +        status = NDIS_STATUS_NOT_SUPPORTED;
   4.729 +        KdPrint(("  returning NDIS_STATUS_NOT_SUPPORTED\n"));
   4.730 +        break;
   4.731 +      }
   4.732 +      xi->packet_filter = *(ULONG *)data;
   4.733 +      status = NDIS_STATUS_SUCCESS;
   4.734 +      break;
   4.735 +    case OID_802_3_MULTICAST_LIST:
   4.736 +      KdPrint(("     Set OID_802_3_MULTICAST_LIST\n"));
   4.737 +      KdPrint(("       Length = %d\n", InformationBufferLength));
   4.738 +      KdPrint(("       Entries = %d\n", InformationBufferLength / 6));
   4.739 +      if (InformationBufferLength > MULTICAST_LIST_MAX_SIZE * 6)
   4.740 +      {
   4.741 +        status = NDIS_STATUS_MULTICAST_FULL;
   4.742 +        break;
   4.743 +      }
   4.744 +      
   4.745 +      if (InformationBufferLength % 6 != 0)
   4.746 +      {
   4.747 +        status = NDIS_STATUS_MULTICAST_FULL;
   4.748 +        break;
   4.749 +      }
   4.750 +      multicast_list = InformationBuffer;
   4.751 +      for (i = 0; i < InformationBufferLength / 6; i++)
   4.752 +      {
   4.753 +        if (!(multicast_list[i * 6 + 0] & 0x01))
   4.754 +        {
   4.755 +          KdPrint(("       Address %d (%02x:%02x:%02x:%02x:%02x:%02x) is not a multicast address\n", i,
   4.756 +            (ULONG)multicast_list[i * 6 + 0], (ULONG)multicast_list[i * 6 + 1], 
   4.757 +            (ULONG)multicast_list[i * 6 + 2], (ULONG)multicast_list[i * 6 + 3], 
   4.758 +            (ULONG)multicast_list[i * 6 + 4], (ULONG)multicast_list[i * 6 + 5]));
   4.759 +          /* the docs say that we should return NDIS_STATUS_MULTICAST_FULL if we get an invalid multicast address but I'm not sure if that's the case... */
   4.760 +        }
   4.761 +      }
   4.762 +      memcpy(xi->multicast_list, InformationBuffer, InformationBufferLength);
   4.763 +      xi->multicast_list_size = InformationBufferLength / 6;
   4.764 +      status = NDIS_STATUS_SUCCESS;
   4.765 +      break;
   4.766 +    case OID_GEN_CURRENT_LOOKAHEAD:
   4.767 +      xi->current_lookahead = *(ULONG *)data;
   4.768 +      KdPrint(("Set OID_GEN_CURRENT_LOOKAHEAD %d (%p)\n", xi->current_lookahead, xi));
   4.769 +      status = NDIS_STATUS_SUCCESS;
   4.770 +      break;
   4.771 +    default:
   4.772 +      KdPrint(("Set Unknown OID 0x%x\n", Oid));
   4.773 +    case OID_GEN_NETWORK_LAYER_ADDRESSES: /* this could tell us what IP addresses there are for us to send arps after a suspend/resume */
   4.774 +      status = NDIS_STATUS_NOT_SUPPORTED;
   4.775 +      break;
   4.776 +  }
   4.777 +  //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
   4.778 +  return status;
   4.779 +}
   4.780 +
   4.781 +#if 0
   4.782 +set 0001021a OID_GEN_MACHINE_NAME
   4.783 +get 00010111 OID_GEN_MAXIMUM_TOTAL_SIZE
   4.784 +get 00010209 OID_GEN_INTERRUPT_MODERATION
   4.785 +set 0001010e OID_GEN_CURRENT_PACKET_FILTER
   4.786 +set 0001010f OID_GEN_CURRENT_LOOKAHEAD
   4.787 +get 00010117 OID_GEN_SUPPORTED_GUIDS
   4.788 +
   4.789 +stat 00020101 OID_GEN_XMIT_OK
   4.790 +#endif
   4.791 +
   4.792 +NDIS_STATUS
   4.793 +XenNet_OidRequest(NDIS_HANDLE adapter_context, PNDIS_OID_REQUEST oid_request)
   4.794 +{
   4.795 +  NTSTATUS status;
   4.796 +  
   4.797 +  FUNCTION_ENTER();
   4.798 +  switch(oid_request->RequestType)
   4.799 +  {
   4.800 +  case NdisRequestQueryInformation:
   4.801 +    FUNCTION_MSG("RequestType = NdisRequestQueryInformation\n");
   4.802 +    //FUNCTION_MSG("Oid = %08x\n", oid_request->DATA.QUERY_INFORMATION.Oid);
   4.803 +    status = XenNet_QueryInformation(adapter_context,
   4.804 +      oid_request->DATA.QUERY_INFORMATION.Oid,
   4.805 +      oid_request->DATA.QUERY_INFORMATION.InformationBuffer,
   4.806 +      oid_request->DATA.QUERY_INFORMATION.InformationBufferLength,
   4.807 +      &oid_request->DATA.QUERY_INFORMATION.BytesWritten,
   4.808 +      &oid_request->DATA.QUERY_INFORMATION.BytesNeeded);
   4.809 +    break;
   4.810 +  case NdisRequestSetInformation:
   4.811 +    FUNCTION_MSG("RequestType = NdisRequestSetInformation\n");
   4.812 +    //FUNCTION_MSG("Oid = %08x\n", oid_request->DATA.SET_INFORMATION.Oid);
   4.813 +    status = XenNet_SetInformation(adapter_context,
   4.814 +      oid_request->DATA.SET_INFORMATION.Oid,
   4.815 +      oid_request->DATA.SET_INFORMATION.InformationBuffer,
   4.816 +      oid_request->DATA.SET_INFORMATION.InformationBufferLength,
   4.817 +      &oid_request->DATA.SET_INFORMATION.BytesRead,
   4.818 +      &oid_request->DATA.SET_INFORMATION.BytesNeeded);
   4.819 +    break;
   4.820 +  case NdisRequestQueryStatistics:
   4.821 +    FUNCTION_MSG("RequestType = NdisRequestQueryStatistics\n");
   4.822 +    //FUNCTION_MSG("Oid = %08x\n", oid_request->DATA.METHOD_INFORMATION.Oid);
   4.823 +    status = XenNet_QueryInformation(adapter_context,
   4.824 +      oid_request->DATA.QUERY_INFORMATION.Oid,
   4.825 +      oid_request->DATA.QUERY_INFORMATION.InformationBuffer,
   4.826 +      oid_request->DATA.QUERY_INFORMATION.InformationBufferLength,
   4.827 +      &oid_request->DATA.QUERY_INFORMATION.BytesWritten,
   4.828 +      &oid_request->DATA.QUERY_INFORMATION.BytesNeeded);
   4.829 +    break;
   4.830 +  default:
   4.831 +    FUNCTION_MSG("RequestType = NdisRequestQuery%d\n", oid_request->RequestType);
   4.832 +    status = NDIS_STATUS_NOT_SUPPORTED;
   4.833 +    break;
   4.834 +  }
   4.835 +  FUNCTION_EXIT();
   4.836 +  return status;
   4.837 +}
   4.838 +
   4.839 +VOID
   4.840 +XenNet_CancelOidRequest(NDIS_HANDLE adapter_context, PVOID request_id)
   4.841 +{
   4.842 +  UNREFERENCED_PARAMETER(adapter_context);
   4.843 +  UNREFERENCED_PARAMETER(request_id);
   4.844 +  FUNCTION_ENTER();
   4.845 +  FUNCTION_EXIT();
   4.846 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/xennet/xennet6_rx.c	Mon May 02 00:17:33 2011 +1000
     5.3 @@ -0,0 +1,1260 @@
     5.4 +/*
     5.5 +PV Net Driver for Windows Xen HVM Domains
     5.6 +Copyright (C) 2007 James Harper
     5.7 +Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
     5.8 +
     5.9 +This program is free software; you can redistribute it and/or
    5.10 +modify it under the terms of the GNU General Public License
    5.11 +as published by the Free Software Foundation; either version 2
    5.12 +of the License, or (at your option) any later version.
    5.13 +
    5.14 +This program is distributed in the hope that it will be useful,
    5.15 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.16 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.17 +GNU General Public License for more details.
    5.18 +
    5.19 +You should have received a copy of the GNU General Public License
    5.20 +along with this program; if not, write to the Free Software
    5.21 +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    5.22 +*/
    5.23 +
    5.24 +#include "xennet6.h"
    5.25 +
    5.26 +static __inline shared_buffer_t *
    5.27 +get_pb_from_freelist(struct xennet_info *xi)
    5.28 +{
    5.29 +  shared_buffer_t *pb;
    5.30 +  PVOID ptr_ref;
    5.31 +
    5.32 +  if (stack_pop(xi->rx_pb_stack, &ptr_ref))
    5.33 +  {
    5.34 +    pb = ptr_ref;
    5.35 +    pb->ref_count = 1;
    5.36 +    InterlockedDecrement(&xi->rx_pb_free);
    5.37 +    return pb;
    5.38 +  }
    5.39 +
    5.40 +  /* don't allocate a new one if we are shutting down */
    5.41 +  if (xi->shutting_down)
    5.42 +    return NULL;
    5.43 +    
    5.44 +  pb = NdisAllocateMemoryWithTagPriority(xi->adapter_handle, sizeof(shared_buffer_t), XENNET_POOL_TAG, LowPoolPriority);
    5.45 +  if (!pb)
    5.46 +    return NULL;
    5.47 +  pb->virtual = NdisAllocateMemoryWithTagPriority(xi->adapter_handle, PAGE_SIZE, XENNET_POOL_TAG, LowPoolPriority);
    5.48 +  if (!pb->virtual)
    5.49 +  {
    5.50 +    NdisFreeMemory(pb, sizeof(shared_buffer_t), 0);
    5.51 +    return NULL;
    5.52 +  }
    5.53 +  pb->mdl = IoAllocateMdl(pb->virtual, PAGE_SIZE, FALSE, FALSE, NULL);
    5.54 +  if (!pb->mdl)
    5.55 +  {
    5.56 +    NdisFreeMemory(pb, PAGE_SIZE, 0);
    5.57 +    NdisFreeMemory(pb->virtual, sizeof(shared_buffer_t), 0);
    5.58 +    return NULL;
    5.59 +  }
    5.60 +  pb->gref = (grant_ref_t)xi->vectors.GntTbl_GrantAccess(xi->vectors.context, 0,
    5.61 +            (ULONG)(MmGetPhysicalAddress(pb->virtual).QuadPart >> PAGE_SHIFT), FALSE, INVALID_GRANT_REF, (ULONG)'XNRX');
    5.62 +  if (pb->gref == INVALID_GRANT_REF)
    5.63 +  {
    5.64 +    IoFreeMdl(pb->mdl);
    5.65 +    NdisFreeMemory(pb, PAGE_SIZE, 0);
    5.66 +    NdisFreeMemory(pb->virtual, sizeof(shared_buffer_t), 0);
    5.67 +    return NULL;
    5.68 +  }
    5.69 +  MmBuildMdlForNonPagedPool(pb->mdl);
    5.70 +  pb->ref_count = 1;
    5.71 +  return pb;
    5.72 +}
    5.73 +
    5.74 +static __inline VOID
    5.75 +ref_pb(struct xennet_info *xi, shared_buffer_t *pb)
    5.76 +{
    5.77 +  UNREFERENCED_PARAMETER(xi);
    5.78 +  InterlockedIncrement(&pb->ref_count);
    5.79 +}
    5.80 +
    5.81 +static __inline VOID
    5.82 +put_pb_on_freelist(struct xennet_info *xi, shared_buffer_t *pb)
    5.83 +{
    5.84 +  if (InterlockedDecrement(&pb->ref_count) == 0)
    5.85 +  {
    5.86 +    //NdisAdjustBufferLength(pb->buffer, PAGE_SIZE);
    5.87 +    //NDIS_BUFFER_LINKAGE(pb->buffer) = NULL;
    5.88 +    pb->next = NULL;
    5.89 +    stack_push(xi->rx_pb_stack, pb);
    5.90 +    InterlockedIncrement(&xi->rx_pb_free);
    5.91 +  }
    5.92 +}
    5.93 +// Called at DISPATCH_LEVEL with rx lock held
    5.94 +static NDIS_STATUS
    5.95 +XenNet_FillRing(struct xennet_info *xi)
    5.96 +{
    5.97 +  unsigned short id;
    5.98 +  shared_buffer_t *page_buf;
    5.99 +  ULONG i, notify;
   5.100 +  ULONG batch_target;
   5.101 +  RING_IDX req_prod = xi->rx.req_prod_pvt;
   5.102 +  netif_rx_request_t *req;
   5.103 +
   5.104 +  FUNCTION_ENTER();
   5.105 +
   5.106 +  batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
   5.107 +
   5.108 +  if (batch_target < (xi->rx_target >> 2))
   5.109 +  {
   5.110 +    FUNCTION_EXIT();
   5.111 +    return NDIS_STATUS_SUCCESS; /* only refill if we are less than 3/4 full already */
   5.112 +  }
   5.113 +
   5.114 +  for (i = 0; i < batch_target; i++)
   5.115 +  {
   5.116 +    page_buf = get_pb_from_freelist(xi);
   5.117 +    if (!page_buf)
   5.118 +    {
   5.119 +      KdPrint((__DRIVER_NAME "     Added %d out of %d buffers to rx ring (no free pages)\n", i, batch_target));
   5.120 +      break;
   5.121 +    }
   5.122 +    xi->rx_id_free--;
   5.123 +
   5.124 +    /* Give to netback */
   5.125 +    id = (USHORT)((req_prod + i) & (NET_RX_RING_SIZE - 1));
   5.126 +    ASSERT(xi->rx_ring_pbs[id] == NULL);
   5.127 +    xi->rx_ring_pbs[id] = page_buf;
   5.128 +    req = RING_GET_REQUEST(&xi->rx, req_prod + i);
   5.129 +    req->id = id;
   5.130 +    req->gref = page_buf->gref;
   5.131 +    ASSERT(req->gref != INVALID_GRANT_REF);
   5.132 +  }
   5.133 +  KeMemoryBarrier();
   5.134 +  xi->rx.req_prod_pvt = req_prod + i;
   5.135 +  RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
   5.136 +  if (notify)
   5.137 +  {
   5.138 +    xi->vectors.EvtChn_Notify(xi->vectors.context, xi->event_channel);
   5.139 +  }
   5.140 +
   5.141 +  FUNCTION_EXIT();
   5.142 +
   5.143 +  return NDIS_STATUS_SUCCESS;
   5.144 +}
   5.145 +
   5.146 +#if 0
   5.147 +/* lock free */
   5.148 +static PNDIS_PACKET
   5.149 +get_packet_from_freelist(struct xennet_info *xi)
   5.150 +{
   5.151 +  NDIS_STATUS status;
   5.152 +  PNDIS_PACKET packet;
   5.153 +  PVOID ptr_ref;
   5.154 +
   5.155 +  if (stack_pop(xi->rx_packet_stack, &ptr_ref))
   5.156 +  {
   5.157 +    packet = ptr_ref;
   5.158 +    InterlockedIncrement(&total_allocated_packets);
   5.159 +    return packet;
   5.160 +  }
   5.161 +  
   5.162 +  if (xi->rx_shutting_down) /* don't keep allocating new packets on shutdown */
   5.163 +    return NULL;
   5.164 +
   5.165 +  NdisAllocatePacket(&status, &packet, xi->rx_packet_pool);
   5.166 +  if (status != NDIS_STATUS_SUCCESS)
   5.167 +  {
   5.168 +    KdPrint((__DRIVER_NAME "     cannot allocate packet\n"));
   5.169 +    return NULL;
   5.170 +  }
   5.171 +  NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
   5.172 +  NdisZeroMemory(packet->MiniportReservedEx, sizeof(packet->MiniportReservedEx));
   5.173 +  InterlockedIncrement(&total_allocated_packets);
   5.174 +  return packet;
   5.175 +}
   5.176 +
   5.177 +/* lock free */
   5.178 +static VOID
   5.179 +put_packet_on_freelist(struct xennet_info *xi, PNDIS_PACKET packet)
   5.180 +{
   5.181 +  PNDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
   5.182 +
   5.183 +  UNREFERENCED_PARAMETER(xi);
   5.184 +  
   5.185 +  InterlockedDecrement(&total_allocated_packets);
   5.186 +
   5.187 +  NdisReinitializePacket(packet);
   5.188 +  RtlZeroMemory(NDIS_PACKET_EXTENSION_FROM_PACKET(packet), sizeof(NDIS_PACKET_EXTENSION));
   5.189 +  csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(
   5.190 +    packet, TcpIpChecksumPacketInfo);
   5.191 +  csum_info->Value = 0;
   5.192 +
   5.193 +  stack_push(xi->rx_packet_stack, packet);
   5.194 +}
   5.195 +#endif
   5.196 +
   5.197 +static BOOLEAN
   5.198 +XenNet_MakePacket(struct xennet_info *xi, PNET_BUFFER_LIST nbl, packet_info_t *pi)
   5.199 +{
   5.200 +  PNET_BUFFER nb;
   5.201 +  PMDL mdl_head, mdl_tail, curr_mdl;
   5.202 +  USHORT new_ip4_length;
   5.203 +  PUCHAR header_va;
   5.204 +  ULONG out_remaining;
   5.205 +  ULONG tcp_length;
   5.206 +  ULONG header_extra;
   5.207 +  shared_buffer_t *header_buf;
   5.208 +
   5.209 +  FUNCTION_ENTER();
   5.210 +  
   5.211 +  ASSERT(!pi->split_required);
   5.212 +  nb = NdisAllocateNetBuffer(xi->rx_nb_pool, NULL, 0, 0);
   5.213 +  if (!nb)
   5.214 +  {
   5.215 +    /* buffers will be freed in MakePackets */
   5.216 +    KdPrint((__DRIVER_NAME "     No free packets\n"));
   5.217 +    FUNCTION_EXIT();
   5.218 +    return FALSE;
   5.219 +  }
   5.220 +
   5.221 +  /* is all this allocation and setup good for performance? would it be better on a lock free list? */
   5.222 +  header_buf = NdisAllocateFromNPagedLookasideList(&xi->rx_lookaside_list);
   5.223 +  if (!header_buf)
   5.224 +  {
   5.225 +    KdPrint((__DRIVER_NAME "     No free header buffers\n"));
   5.226 +    NdisFreeNetBuffer(nb);
   5.227 +    FUNCTION_EXIT();
   5.228 +    return FALSE;
   5.229 +  }
   5.230 +  header_va = (PUCHAR)(header_buf + 1);
   5.231 +  NdisZeroMemory(header_buf, sizeof(shared_buffer_t));
   5.232 +  NdisMoveMemory(header_va, pi->header, pi->header_length);
   5.233 +  //KdPrint((__DRIVER_NAME "     header_length = %d, current_lookahead = %d\n", pi->header_length, xi->current_lookahead));
   5.234 +  //KdPrint((__DRIVER_NAME "     ip4_header_length = %d\n", pi->ip4_header_length));
   5.235 +  //KdPrint((__DRIVER_NAME "     tcp_header_length = %d\n", pi->tcp_header_length));
   5.236 +  /* make sure we satisfy the lookahead requirement */
   5.237 +  if (pi->split_required)
   5.238 +  {
   5.239 +#if 0  
   5.240 +    /* for split packets we need to make sure the 'header' is no bigger than header+mss bytes */
   5.241 +    XenNet_BuildHeader(pi, header_va, min((ULONG)MAX_ETH_HEADER_LENGTH + pi->ip4_header_length + pi->tcp_header_length + pi->mss, MAX_ETH_HEADER_LENGTH + max(MIN_LOOKAHEAD_LENGTH, xi->current_lookahead)));
   5.242 +#endif
   5.243 +  }
   5.244 +  else
   5.245 +  {
   5.246 +    XenNet_BuildHeader(pi, header_va, max(MIN_LOOKAHEAD_LENGTH, xi->current_lookahead) + MAX_ETH_HEADER_LENGTH);
   5.247 +  }
   5.248 +  header_extra = pi->header_length - (MAX_ETH_HEADER_LENGTH + pi->ip4_header_length + pi->tcp_header_length);
   5.249 +  ASSERT(pi->header_length <= MAX_ETH_HEADER_LENGTH + MAX_LOOKAHEAD_LENGTH);
   5.250 +  curr_mdl = IoAllocateMdl(header_va, pi->header_length, FALSE, FALSE, NULL);
   5.251 +  if (!curr_mdl)
   5.252 +  {
   5.253 +    KdPrint((__DRIVER_NAME "     No free header buffers\n"));
   5.254 +    NdisFreeToNPagedLookasideList(&xi->rx_lookaside_list, header_buf);
   5.255 +    NdisFreeNetBuffer(nb);
   5.256 +    FUNCTION_EXIT();
   5.257 +    return FALSE;
   5.258 +  }
   5.259 +  MmBuildMdlForNonPagedPool(curr_mdl);
   5.260 +  mdl_head = mdl_tail = curr_mdl;
   5.261 +  NB_HEADER_BUF(nb) = header_buf;
   5.262 +  header_buf->next = pi->curr_pb;
   5.263 +  NET_BUFFER_FIRST_MDL(nb) = mdl_head;
   5.264 +  NET_BUFFER_CURRENT_MDL(nb) = mdl_head;
   5.265 +  NET_BUFFER_CURRENT_MDL_OFFSET(nb) = 0;
   5.266 +  NET_BUFFER_DATA_OFFSET(nb) = 0;
   5.267 +  NET_BUFFER_DATA_LENGTH(nb) = pi->header_length;
   5.268 +
   5.269 +  // TODO: if there are only a few bytes left on the first buffer then add them to the header buffer too... maybe
   5.270 +
   5.271 +  if (pi->split_required)
   5.272 +  {
   5.273 +    tcp_length = (USHORT)min(pi->mss, pi->tcp_remaining);
   5.274 +    new_ip4_length = (USHORT)(pi->ip4_header_length + pi->tcp_header_length + tcp_length);
   5.275 +    //KdPrint((__DRIVER_NAME "     new_ip4_length = %d\n", new_ip4_length));
   5.276 +    //KdPrint((__DRIVER_NAME "     this tcp_length = %d\n", tcp_length));
   5.277 +    SET_NET_USHORT(&header_va[XN_HDR_SIZE + 2], new_ip4_length);
   5.278 +    SET_NET_ULONG(&header_va[XN_HDR_SIZE + pi->ip4_header_length + 4], pi->tcp_seq);
   5.279 +    pi->tcp_seq += tcp_length;
   5.280 +    pi->tcp_remaining = (USHORT)(pi->tcp_remaining - tcp_length);
   5.281 +    /* part of the packet is already present in the header buffer for lookahead */
   5.282 +    out_remaining = tcp_length - header_extra;
   5.283 +    ASSERT((LONG)out_remaining >= 0);
   5.284 +  }
   5.285 +  else
   5.286 +  {
   5.287 +    out_remaining = pi->total_length - pi->header_length;
   5.288 +    ASSERT((LONG)out_remaining >= 0);
   5.289 +  }
   5.290 +  KdPrint((__DRIVER_NAME "     before loop - out_remaining = %d\n", out_remaining));
   5.291 +
   5.292 +  while (out_remaining != 0)
   5.293 +  {
   5.294 +    //ULONG in_buffer_offset;
   5.295 +    ULONG in_buffer_length;
   5.296 +    ULONG out_length;
   5.297 +    
   5.298 +    KdPrint((__DRIVER_NAME "     in loop - out_remaining = %d, curr_buffer = %p, curr_pb = %p\n", out_remaining, pi->curr_mdl, pi->curr_pb));
   5.299 +    if (!pi->curr_mdl || !pi->curr_pb)
   5.300 +    {
   5.301 +      KdPrint((__DRIVER_NAME "     out of buffers for packet\n"));
   5.302 +      KdPrint((__DRIVER_NAME "     out_remaining = %d, curr_buffer = %p, curr_pb = %p\n", out_remaining, pi->curr_mdl, pi->curr_pb));
   5.303 +      // TODO: free some stuff or we'll leak
   5.304 +      /* unchain buffers then free packet */
   5.305 +      FUNCTION_EXIT();
   5.306 +      return FALSE;
   5.307 +    }
   5.308 +
   5.309 +    //NdisQueryBufferOffset(pi->curr_buffer, &in_buffer_offset, &in_buffer_length);
   5.310 +    in_buffer_length = MmGetMdlByteCount(pi->curr_mdl);
   5.311 +    out_length = min(out_remaining, in_buffer_length - pi->curr_mdl_offset);
   5.312 +    //NdisCopyBuffer(&status, &out_buffer, xi->rx_buffer_pool, pi->curr_buffer, pi->curr_mdl_offset, out_length);
   5.313 +    curr_mdl = IoAllocateMdl((PUCHAR)MmGetMdlVirtualAddress(pi->curr_mdl) + pi->curr_mdl_offset, out_length, FALSE, FALSE, NULL);
   5.314 +    ASSERT(curr_mdl);
   5.315 +    IoBuildPartialMdl(pi->curr_mdl, curr_mdl, (PUCHAR)MmGetMdlVirtualAddress(pi->curr_mdl) + pi->curr_mdl_offset, out_length);
   5.316 +    mdl_tail->Next = curr_mdl;
   5.317 +    mdl_tail = curr_mdl;
   5.318 +    curr_mdl->Next = NULL;
   5.319 +    NET_BUFFER_DATA_LENGTH(nb) += out_length;
   5.320 +    ref_pb(xi, pi->curr_pb);
   5.321 +    pi->curr_mdl_offset = (USHORT)(pi->curr_mdl_offset + out_length);
   5.322 +    if (pi->curr_mdl_offset == in_buffer_length)
   5.323 +    {
   5.324 +      pi->curr_mdl = pi->curr_mdl->Next;
   5.325 +      pi->curr_pb = pi->curr_pb->next;
   5.326 +      pi->curr_mdl_offset = 0;
   5.327 +    }
   5.328 +    out_remaining -= out_length;
   5.329 +  }
   5.330 +  if (pi->split_required)
   5.331 +  {
   5.332 +    //XenNet_SumIpHeader(header_va, pi->ip4_header_length);
   5.333 +  }
   5.334 +  if (header_extra > 0)
   5.335 +    pi->header_length -= header_extra;
   5.336 +  //ASSERT(*(shared_buffer_t **)&packet->MiniportReservedEx[0]);
   5.337 +  
   5.338 +  NBL_PACKET_COUNT(nbl)++;
   5.339 +  if (!NET_BUFFER_LIST_FIRST_NB(nbl))
   5.340 +  {
   5.341 +    NET_BUFFER_LIST_FIRST_NB(nbl) = nb;
   5.342 +  }
   5.343 +  else
   5.344 +  {
   5.345 +    NET_BUFFER_NEXT_NB(NBL_LAST_NB(nbl)) = nb;
   5.346 +  }
   5.347 +  NBL_LAST_NB(nbl) = nb;
   5.348 +  NET_BUFFER_NEXT_NB(nb) = NULL; /*is this already done for me? */
   5.349 +  FUNCTION_EXIT();
   5.350 +  return TRUE;
   5.351 +}
   5.352 +
   5.353 +#if 0
   5.354 +/*
   5.355 + Windows appears to insist that the checksum on received packets is correct, and won't
   5.356 + believe us when we lie about it, which happens when the packet is generated on the
   5.357 + same bridge in Dom0. Doh!
   5.358 + This is only for TCP and UDP packets. IP checksums appear to be correct anyways.
   5.359 +*/
   5.360 +
   5.361 +static BOOLEAN
   5.362 +XenNet_SumPacketData(
   5.363 +  packet_info_t *pi,
   5.364 +  PNDIS_PACKET packet,
   5.365 +  BOOLEAN set_csum
   5.366 +)
   5.367 +{
   5.368 +  USHORT i;
   5.369 +  PUCHAR buffer;
   5.370 +  PMDL mdl;
   5.371 +  UINT total_length;
   5.372 +  UINT data_length;
   5.373 +  UINT buffer_length;
   5.374 +  USHORT buffer_offset;
   5.375 +  ULONG csum;
   5.376 +  PUSHORT csum_ptr;
   5.377 +  USHORT remaining;
   5.378 +  USHORT ip4_length;
   5.379 +  BOOLEAN csum_span = TRUE; /* when the USHORT to be checksummed spans a buffer */
   5.380 +  
   5.381 +  //FUNCTION_ENTER();
   5.382 +
   5.383 +  NdisGetFirstBufferFromPacketSafe(packet, &mdl, &buffer, &buffer_length, &total_length, NormalPagePriority);
   5.384 +  ASSERT(mdl);
   5.385 +
   5.386 +  ip4_length = GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 2]);
   5.387 +  data_length = ip4_length + XN_HDR_SIZE;
   5.388 +  
   5.389 +  if ((USHORT)data_length > total_length)
   5.390 +  {
   5.391 +    KdPrint((__DRIVER_NAME "     Size Mismatch %d (ip4_length + XN_HDR_SIZE) != %d (total_length)\n", ip4_length + XN_HDR_SIZE, total_length));
   5.392 +    return FALSE;
   5.393 +  }
   5.394 +
   5.395 +  switch (pi->ip_proto)
   5.396 +  {
   5.397 +  case 6:
   5.398 +    ASSERT(buffer_length >= (USHORT)(XN_HDR_SIZE + pi->ip4_header_length + 17));
   5.399 +    csum_ptr = (USHORT *)&buffer[XN_HDR_SIZE + pi->ip4_header_length + 16];
   5.400 +    break;
   5.401 +  case 17:
   5.402 +    ASSERT(buffer_length >= (USHORT)(XN_HDR_SIZE + pi->ip4_header_length + 7));
   5.403 +    csum_ptr = (USHORT *)&buffer[XN_HDR_SIZE + pi->ip4_header_length + 6];
   5.404 +    break;
   5.405 +  default:
   5.406 +    KdPrint((__DRIVER_NAME "     Don't know how to calc sum for IP Proto %d\n", pi->ip_proto));
   5.407 +    //FUNCTION_EXIT();
   5.408 +    return FALSE; // should never happen
   5.409 +  }
   5.410 +
   5.411 +  if (set_csum)  
   5.412 +    *csum_ptr = 0;
   5.413 +
   5.414 +  csum = 0;
   5.415 +  csum += GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 12]) + GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 14]); // src
   5.416 +  csum += GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 16]) + GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 18]); // dst
   5.417 +  csum += ((USHORT)buffer[XN_HDR_SIZE + 9]);
   5.418 +
   5.419 +  remaining = ip4_length - pi->ip4_header_length;
   5.420 +
   5.421 +  csum += remaining;
   5.422 +  
   5.423 +  csum_span = FALSE;
   5.424 +  buffer_offset = i = XN_HDR_SIZE + pi->ip4_header_length;
   5.425 +  while (i < data_length)
   5.426 +  {
   5.427 +    /* don't include the checksum field itself in the calculation */
   5.428 +    if ((pi->ip_proto == 6 && i == XN_HDR_SIZE + pi->ip4_header_length + 16) || (pi->ip_proto == 17 && i == XN_HDR_SIZE + pi->ip4_header_length + 6))
   5.429 +    {
   5.430 +      /* we know that this always happens in the header buffer so we are guaranteed the full two bytes */
   5.431 +      i += 2;
   5.432 +      buffer_offset += 2;
   5.433 +      continue;
   5.434 +    }
   5.435 +    if (csum_span)
   5.436 +    {
   5.437 +      /* the other half of the next bit */
   5.438 +      ASSERT(buffer_offset == 0);
   5.439 +      csum += (USHORT)buffer[buffer_offset];
   5.440 +      csum_span = FALSE;
   5.441 +      i += 1;
   5.442 +      buffer_offset += 1;
   5.443 +    }
   5.444 +    else if (buffer_offset == buffer_length - 1)
   5.445 +    {
   5.446 +      /* deal with a buffer ending on an odd byte boundary */
   5.447 +      csum += (USHORT)buffer[buffer_offset] << 8;
   5.448 +      csum_span = TRUE;
   5.449 +      i += 1;
   5.450 +      buffer_offset += 1;
   5.451 +    }
   5.452 +    else
   5.453 +    {
   5.454 +      csum += GET_NET_PUSHORT(&buffer[buffer_offset]);
   5.455 +      i += 2;
   5.456 +      buffer_offset += 2;
   5.457 +    }
   5.458 +    if (buffer_offset == buffer_length && i < total_length)
   5.459 +    {
   5.460 +      NdisGetNextBuffer(mdl, &mdl);
   5.461 +      if (mdl == NULL)
   5.462 +      {
   5.463 +        KdPrint((__DRIVER_NAME "     Ran out of buffers\n"));
   5.464 +        return FALSE; // should never happen
   5.465 +      }
   5.466 +      NdisQueryBufferSafe(mdl, &buffer, &buffer_length, NormalPagePriority);
   5.467 +      ASSERT(buffer_length);
   5.468 +      buffer_offset = 0;
   5.469 +    }
   5.470 +  }
   5.471 +      
   5.472 +  while (csum & 0xFFFF0000)
   5.473 +    csum = (csum & 0xFFFF) + (csum >> 16);
   5.474 +  
   5.475 +  if (set_csum)
   5.476 +  {
   5.477 +    *csum_ptr = (USHORT)~GET_NET_USHORT((USHORT)csum);
   5.478 +  }
   5.479 +  else
   5.480 +  {
   5.481 +    //FUNCTION_EXIT();
   5.482 +    return (BOOLEAN)(*csum_ptr == (USHORT)~GET_NET_USHORT((USHORT)csum));
   5.483 +  }
   5.484 +  //FUNCTION_EXIT();
   5.485 +  return TRUE;
   5.486 +}
   5.487 +#endif
   5.488 +
   5.489 +static PNET_BUFFER_LIST
   5.490 +XenNet_MakePackets(struct xennet_info *xi, packet_info_t *pi)
   5.491 +{
   5.492 +  PNET_BUFFER_LIST nbl = NULL;
   5.493 +  //UCHAR psh;
   5.494 +  //PNDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
   5.495 +  ULONG parse_result;  
   5.496 +  //PNDIS_BUFFER buffer;
   5.497 +  shared_buffer_t *page_buf;
   5.498 +
   5.499 +  FUNCTION_ENTER();
   5.500 +
   5.501 +  parse_result = XenNet_ParsePacketHeader(pi, NULL, 0);
   5.502 +KdPrint((__DRIVER_NAME "     A\n"));
   5.503 +
   5.504 +  if (!XenNet_FilterAcceptPacket(xi, pi))
   5.505 +  {
   5.506 +KdPrint((__DRIVER_NAME "     B\n"));
   5.507 +    goto done;
   5.508 +  }
   5.509 +KdPrint((__DRIVER_NAME "     C\n"));
   5.510 +
   5.511 +  nbl = NdisAllocateNetBufferList(xi->rx_nbl_pool, 0, 0);
   5.512 +KdPrint((__DRIVER_NAME "     D\n"));
   5.513 +  NBL_PACKET_COUNT(nbl) = 0;
   5.514 +KdPrint((__DRIVER_NAME "     E\n"));
   5.515 +
   5.516 +  switch (pi->ip_proto)
   5.517 +  {
   5.518 +  case 6:  // TCP
   5.519 +KdPrint((__DRIVER_NAME "     F\n"));
   5.520 +    if (pi->split_required)
   5.521 +      break;
   5.522 +    // fallthrough
   5.523 +  case 17:  // UDP
   5.524 +KdPrint((__DRIVER_NAME "     G\n"));
   5.525 +    if (!XenNet_MakePacket(xi, nbl, pi))
   5.526 +    {
   5.527 +      KdPrint((__DRIVER_NAME "     Ran out of packets\n"));
   5.528 +      xi->stat_rx_no_buffer++;
   5.529 +      goto done;
   5.530 +    }
   5.531 +KdPrint((__DRIVER_NAME "     H\n"));
   5.532 +    if (parse_result == PARSE_OK)
   5.533 +    {
   5.534 +KdPrint((__DRIVER_NAME "     I\n"));
   5.535 +#if 0
   5.536 +      BOOLEAN checksum_offload = FALSE;
   5.537 +      csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(
   5.538 +        packet, TcpIpChecksumPacketInfo);
   5.539 +      ASSERT(csum_info->Value == 0);
   5.540 +      if (pi->csum_blank || pi->data_validated)
   5.541 +      {
   5.542 +        if (xi->setting_csum.V4Receive.TcpChecksum && pi->ip_proto == 6)
   5.543 +        {
   5.544 +          if (!pi->tcp_has_options || xi->setting_csum.V4Receive.TcpOptionsSupported)
   5.545 +          {
   5.546 +            csum_info->Receive.NdisPacketIpChecksumSucceeded = TRUE;
   5.547 +            csum_info->Receive.NdisPacketTcpChecksumSucceeded = TRUE;
   5.548 +            checksum_offload = TRUE;
   5.549 +          }
   5.550 +        }
   5.551 +        else if (xi->setting_csum.V4Receive.UdpChecksum && pi->ip_proto == 17)
   5.552 +        {
   5.553 +          csum_info->Receive.NdisPacketIpChecksumSucceeded = TRUE;
   5.554 +          csum_info->Receive.NdisPacketUdpChecksumSucceeded = TRUE;
   5.555 +          checksum_offload = TRUE;
   5.556 +        }
   5.557 +        if (pi->csum_blank && (!xi->config_csum_rx_dont_fix || !checksum_offload))
   5.558 +        {
   5.559 +          XenNet_SumPacketData(pi, packet, TRUE);
   5.560 +        }
   5.561 +      }
   5.562 +      else if (xi->config_csum_rx_check)
   5.563 +      {
   5.564 +        if (xi->setting_csum.V4Receive.TcpChecksum && pi->ip_proto == 6)
   5.565 +        {
   5.566 +          if (XenNet_SumPacketData(pi, packet, FALSE))
   5.567 +          {
   5.568 +            csum_info->Receive.NdisPacketTcpChecksumSucceeded = TRUE;
   5.569 +          }
   5.570 +          else
   5.571 +          {
   5.572 +            csum_info->Receive.NdisPacketTcpChecksumFailed = TRUE;
   5.573 +          }
   5.574 +        } else if (xi->setting_csum.V4Receive.UdpChecksum && pi->ip_proto == 17)
   5.575 +        {
   5.576 +          if (XenNet_SumPacketData(pi, packet, FALSE))
   5.577 +          {
   5.578 +            csum_info->Receive.NdisPacketUdpChecksumSucceeded = TRUE;
   5.579 +          }
   5.580 +          else
   5.581 +          {
   5.582 +            csum_info->Receive.NdisPacketUdpChecksumFailed = TRUE;
   5.583 +          }
   5.584 +        }
   5.585 +      }
   5.586 +#endif
   5.587 +    }
   5.588 +    goto done;
   5.589 +  default:
   5.590 +KdPrint((__DRIVER_NAME "     J\n"));
   5.591 +    if (!XenNet_MakePacket(xi, nbl, pi))
   5.592 +    {
   5.593 +      KdPrint((__DRIVER_NAME "     Ran out of packets\n"));
   5.594 +      xi->stat_rx_no_buffer++;
   5.595 +      goto done;
   5.596 +    }
   5.597 +KdPrint((__DRIVER_NAME "     K\n"));
   5.598 +    goto done;
   5.599 +  }
   5.600 +  KdPrint((__DRIVER_NAME "     What are we doing here???\n"));
   5.601 +#if 0  
   5.602 +  pi->tcp_remaining = pi->tcp_length;
   5.603 +
   5.604 +  /* we can make certain assumptions here as the following code is only for tcp4 */
   5.605 +  psh = pi->header[XN_HDR_SIZE + pi->ip4_header_length + 13] & 8;
   5.606 +  while (pi->tcp_remaining)
   5.607 +  {
   5.608 +    PUCHAR header_va;
   5.609 +    PMDL mdl;
   5.610 +    UINT total_length;
   5.611 +    UINT buffer_length;
   5.612 +    packet = XenNet_MakePacket(xi, nbl, pi);
   5.613 +    if (!packet)
   5.614 +    {
   5.615 +      //KdPrint((__DRIVER_NAME "     Ran out of packets\n"));
   5.616 +      xi->stat_rx_no_buffer++;
   5.617 +      break; /* we are out of memory - just drop the packets */
   5.618 +    }
   5.619 +    if (xi->setting_csum.V4Receive.TcpChecksum)
   5.620 +    {
   5.621 +      csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(
   5.622 +        packet, TcpIpChecksumPacketInfo);
   5.623 +      csum_info->Receive.NdisPacketIpChecksumSucceeded = TRUE;
   5.624 +      csum_info->Receive.NdisPacketTcpChecksumSucceeded = TRUE;
   5.625 +    }
   5.626 +    if (psh)
   5.627 +    {
   5.628 +      NdisGetFirstBufferFromPacketSafe(packet, &mdl, &header_va, &buffer_length, &total_length, NormalPagePriority);
   5.629 +      if (pi->tcp_remaining)
   5.630 +        header_va[XN_HDR_SIZE + pi->ip4_header_length + 13] &= ~8;
   5.631 +      else
   5.632 +        header_va[XN_HDR_SIZE + pi->ip4_header_length + 13] |= 8;
   5.633 +    }
   5.634 +    XenNet_SumPacketData(pi, packet, TRUE);
   5.635 +    entry = (PLIST_ENTRY)&packet->MiniportReservedEx[sizeof(PVOID)];
   5.636 +    InsertTailList(rx_packet_list, entry);
   5.637 +    packet_count++;
   5.638 +  }
   5.639 +#endif
   5.640 +done:
   5.641 +  if (nbl && !NBL_PACKET_COUNT(nbl))
   5.642 +  {
   5.643 +    NdisFreeNetBufferList(nbl);
   5.644 +    nbl = NULL;
   5.645 +  }
   5.646 +  page_buf = pi->first_pb;
   5.647 +  while (page_buf)
   5.648 +  {
   5.649 +    shared_buffer_t *next_pb = page_buf->next;
   5.650 +    put_pb_on_freelist(xi, page_buf); /* this doesn't actually free the page_puf if there are outstanding references */
   5.651 +    page_buf = next_pb;
   5.652 +  }
   5.653 +  XenNet_ClearPacketInfo(pi);
   5.654 +  FUNCTION_EXIT();
   5.655 +  return nbl;
   5.656 +}
   5.657 +
   5.658 +/* called at <= DISPATCH_LEVEL */
   5.659 +/* it's okay for return packet to be called while resume_state != RUNNING as the packet will simply be added back to the freelist, the grants will be fixed later */
   5.660 +VOID
   5.661 +XenNet_ReturnNetBufferLists(NDIS_HANDLE adapter_context, PNET_BUFFER_LIST curr_nbl, ULONG return_flags)
   5.662 +{
   5.663 +  struct xennet_info *xi = adapter_context;
   5.664 +  UNREFERENCED_PARAMETER(return_flags);
   5.665 +
   5.666 +  FUNCTION_ENTER();
   5.667 +
   5.668 +  //KdPrint((__DRIVER_NAME "     page_buf = %p\n", page_buf));
   5.669 +
   5.670 +  while (curr_nbl)
   5.671 +  {
   5.672 +    PNET_BUFFER_LIST next_nbl;
   5.673 +    PNET_BUFFER curr_nb;
   5.674 +    
   5.675 +    next_nbl = NET_BUFFER_LIST_NEXT_NBL(curr_nbl);
   5.676 +    curr_nb = NET_BUFFER_LIST_FIRST_NB(curr_nbl);
   5.677 +    while (curr_nb)
   5.678 +    {
   5.679 +      PNET_BUFFER next_nb;
   5.680 +      PMDL curr_mdl;
   5.681 +      shared_buffer_t *page_buf;
   5.682 +      
   5.683 +      next_nb = NET_BUFFER_NEXT_NB(curr_nb);
   5.684 +      curr_mdl = NET_BUFFER_FIRST_MDL(curr_nb);
   5.685 +      page_buf = NB_HEADER_BUF(curr_nb);
   5.686 +      while (curr_mdl)
   5.687 +      {
   5.688 +        shared_buffer_t *next_buf;
   5.689 +        PMDL next_mdl;
   5.690 +        
   5.691 +        ASSERT(page_buf);
   5.692 +        next_mdl = curr_mdl->Next;
   5.693 +        next_buf = page_buf->next;
   5.694 +        if (!page_buf->virtual)
   5.695 +        {
   5.696 +          /* this isn't actually a share_buffer, it is some memory allocated for the header - just free it */
   5.697 +          NdisFreeToNPagedLookasideList(&xi->rx_lookaside_list, (PUCHAR)MmGetMdlVirtualAddress(curr_mdl) - sizeof(shared_buffer_t));
   5.698 +          IoFreeMdl(curr_mdl);
   5.699 +        }
   5.700 +        else
   5.701 +        {
   5.702 +          //KdPrint((__DRIVER_NAME "     returning page_buf %p with id %d\n", page_buf, page_buf->id));
   5.703 +          if (curr_mdl != page_buf->mdl)
   5.704 +          {
   5.705 +            KdPrint((__DRIVER_NAME "     curr_mdl = %p, page_buf->mdl = %p\n", curr_mdl, page_buf->mdl));
   5.706 +            IoFreeMdl(curr_mdl);
   5.707 +          }
   5.708 +          put_pb_on_freelist(xi, page_buf);
   5.709 +        }
   5.710 +        curr_mdl = next_mdl;
   5.711 +        page_buf = next_buf;
   5.712 +      }
   5.713 +
   5.714 +      NdisFreeNetBuffer(curr_nb);
   5.715 +      InterlockedDecrement(&xi->rx_outstanding);
   5.716 +
   5.717 +      curr_nb = next_nb;
   5.718 +    }
   5.719 +    NdisFreeNetBufferList(curr_nbl);
   5.720 +    curr_nbl = next_nbl;
   5.721 +  }
   5.722 +  
   5.723 +  if (!xi->rx_outstanding && xi->rx_shutting_down)
   5.724 +    KeSetEvent(&xi->packet_returned_event, IO_NO_INCREMENT, FALSE);
   5.725 +
   5.726 +  FUNCTION_EXIT();
   5.727 +}
   5.728 +
   5.729 +#define MAXIMUM_PACKETS_PER_INDICATE 32
   5.730 +
   5.731 +/* We limit the number of packets per interrupt so that acks get a chance
   5.732 +under high rx load. The DPC is immediately re-scheduled */
   5.733 +#define MAXIMUM_PACKETS_PER_INTERRUPT 32 /* this is calculated before large packet split */
   5.734 +#define MAXIMUM_DATA_PER_INTERRUPT (MAXIMUM_PACKETS_PER_INTERRUPT * 1500) /* help account for large packets */
   5.735 +
   5.736 +// Called at DISPATCH_LEVEL
   5.737 +BOOLEAN
   5.738 +XenNet_RxBufferCheck(struct xennet_info *xi)
   5.739 +{
   5.740 +  RING_IDX cons, prod;
   5.741 +  LIST_ENTRY rx_packet_list;
   5.742 +  ULONG packet_count = 0;
   5.743 +  ULONG packet_data = 0;
   5.744 +  ULONG buffer_count = 0;
   5.745 +  USHORT id;
   5.746 +  int more_to_do = FALSE;
   5.747 +  shared_buffer_t *page_buf;
   5.748 +  //LIST_ENTRY rx_header_only_packet_list;
   5.749 +  //PLIST_ENTRY entry;
   5.750 +  PNET_BUFFER_LIST nbl_head = NULL;
   5.751 +  PNET_BUFFER_LIST nbl_tail = NULL;
   5.752 +  ULONG nbl_count = 0;
   5.753 +  ULONG interim_packet_data = 0;
   5.754 +  struct netif_extra_info *ei;
   5.755 +  packet_info_t *pi = &xi->rxpi[KeGetCurrentProcessorNumber() & 0xff];
   5.756 +  shared_buffer_t *head_buf = NULL;
   5.757 +  shared_buffer_t *tail_buf = NULL;
   5.758 +  shared_buffer_t *last_buf = NULL;
   5.759 +  BOOLEAN extra_info_flag = FALSE;
   5.760 +  BOOLEAN more_data_flag = FALSE;
   5.761 +  BOOLEAN dont_set_event;
   5.762 +
   5.763 +  FUNCTION_ENTER();
   5.764 +
   5.765 +  if (!xi->connected)
   5.766 +    return FALSE; /* a delayed DPC could let this come through... just do nothing */
   5.767 +
   5.768 +  InitializeListHead(&rx_packet_list);
   5.769 +
   5.770 +  /* get all the buffers off the ring as quickly as possible so the lock is held for a minimum amount of time */
   5.771 +
   5.772 +  KeAcquireSpinLockAtDpcLevel(&xi->rx_lock);
   5.773 +  
   5.774 +  if (xi->rx_shutting_down)
   5.775 +  {
   5.776 +    /* there is a chance that our Dpc had been queued just before the shutdown... */
   5.777 +    KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
   5.778 +    return FALSE;
   5.779 +  }
   5.780 +
   5.781 +  if (xi->rx_partial_buf)
   5.782 +  {
   5.783 +    head_buf = xi->rx_partial_buf;
   5.784 +    tail_buf = xi->rx_partial_buf;
   5.785 +    while (tail_buf->next)
   5.786 +      tail_buf = tail_buf->next;
   5.787 +    more_data_flag = xi->rx_partial_more_data_flag;
   5.788 +    extra_info_flag = xi->rx_partial_extra_info_flag;
   5.789 +    xi->rx_partial_buf = NULL;
   5.790 +  }
   5.791 +
   5.792 +  do {
   5.793 +    prod = xi->rx.sring->rsp_prod;
   5.794 +    KeMemoryBarrier(); /* Ensure we see responses up to 'prod'. */
   5.795 +
   5.796 +    for (cons = xi->rx.rsp_cons; cons != prod && packet_count < MAXIMUM_PACKETS_PER_INTERRUPT && packet_data < MAXIMUM_DATA_PER_INTERRUPT; cons++)
   5.797 +    {
   5.798 +      id = (USHORT)(cons & (NET_RX_RING_SIZE - 1));
   5.799 +      page_buf = xi->rx_ring_pbs[id];
   5.800 +      ASSERT(page_buf);
   5.801 +      xi->rx_ring_pbs[id] = NULL;
   5.802 +      xi->rx_id_free++;
   5.803 +      memcpy(&page_buf->rsp, RING_GET_RESPONSE(&xi->rx, cons), max(sizeof(struct netif_rx_response), sizeof(struct netif_extra_info)));
   5.804 +KdPrint((__DRIVER_NAME "     got buffer from ring\n"));
   5.805 +      if (!extra_info_flag)
   5.806 +      {
   5.807 +        if (page_buf->rsp.status <= 0
   5.808 +          || page_buf->rsp.offset + page_buf->rsp.status > PAGE_SIZE)
   5.809 +        {
   5.810 +          KdPrint((__DRIVER_NAME "     Error: rsp offset %d, size %d\n",
   5.811 +            page_buf->rsp.offset, page_buf->rsp.status));
   5.812 +          ASSERT(!extra_info_flag);
   5.813 +          put_pb_on_freelist(xi, page_buf);
   5.814 +          continue;
   5.815 +        }
   5.816 +      }
   5.817 +      
   5.818 +      if (!head_buf)
   5.819 +      {
   5.820 +        head_buf = page_buf;
   5.821 +        tail_buf = page_buf;
   5.822 +      }
   5.823 +      else
   5.824 +      {
   5.825 +        tail_buf->next = page_buf;
   5.826 +        tail_buf = page_buf;
   5.827 +      }
   5.828 +      page_buf->next = NULL;
   5.829 +
   5.830 +      if (extra_info_flag)
   5.831 +      {
   5.832 +        ei = (struct netif_extra_info *)&page_buf->rsp;
   5.833 +        extra_info_flag = ei->flags & XEN_NETIF_EXTRA_FLAG_MORE;
   5.834 +      }
   5.835 +      else
   5.836 +      {
   5.837 +        more_data_flag = (BOOLEAN)(page_buf->rsp.flags & NETRXF_more_data);
   5.838 +        extra_info_flag = (BOOLEAN)(page_buf->rsp.flags & NETRXF_extra_info);
   5.839 +        interim_packet_data += page_buf->rsp.status;
   5.840 +      }
   5.841 +      
   5.842 +      if (!extra_info_flag && !more_data_flag)
   5.843 +      {
   5.844 +        last_buf = page_buf;
   5.845 +        packet_count++;
   5.846 +        packet_data += interim_packet_data;
   5.847 +        interim_packet_data = 0;
   5.848 +      }
   5.849 +      buffer_count++;
   5.850 +    }
   5.851 +    xi->rx.rsp_cons = cons;
   5.852 +
   5.853 +    /* Give netback more buffers */
   5.854 +    XenNet_FillRing(xi);
   5.855 +
   5.856 +    if (packet_count >= MAXIMUM_PACKETS_PER_INTERRUPT || packet_data >= MAXIMUM_DATA_PER_INTERRUPT)
   5.857 +      break;
   5.858 +
   5.859 +    more_to_do = RING_HAS_UNCONSUMED_RESPONSES(&xi->rx);
   5.860 +    if (!more_to_do)
   5.861 +    {
   5.862 +      xi->rx.sring->rsp_event = xi->rx.rsp_cons + 1;
   5.863 +      KeMemoryBarrier();
   5.864 +      more_to_do = RING_HAS_UNCONSUMED_RESPONSES(&xi->rx);
   5.865 +    }
   5.866 +  } while (more_to_do);
   5.867 +  
   5.868 +  /* anything past last_buf belongs to an incomplete packet... */
   5.869 +  if (last_buf && last_buf->next)
   5.870 +  {
   5.871 +    KdPrint((__DRIVER_NAME "     Partial receive\n"));
   5.872 +    xi->rx_partial_buf = last_buf->next;
   5.873 +    xi->rx_partial_more_data_flag = more_data_flag;
   5.874 +    xi->rx_partial_extra_info_flag = extra_info_flag;
   5.875 +    last_buf->next = NULL;
   5.876 +  }
   5.877 +
   5.878 +  KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
   5.879 +
   5.880 +  if (packet_count >= MAXIMUM_PACKETS_PER_INTERRUPT || packet_data >= MAXIMUM_DATA_PER_INTERRUPT)
   5.881 +  {
   5.882 +    /* fire again immediately */
   5.883 +    //KdPrint((__DRIVER_NAME "     Dpc Duration Exceeded\n"));
   5.884 +    /* we want the Dpc on the end of the queue. By definition we are already on the right CPU so we know the Dpc queue will be run immediately */
   5.885 +    KeSetImportanceDpc(&xi->rxtx_dpc, MediumImportance);
   5.886 +    KeInsertQueueDpc(&xi->rxtx_dpc, NULL, NULL);
   5.887 +    /* dont set an event in TX path */
   5.888 +    dont_set_event = TRUE;
   5.889 +  }
   5.890 +  else
   5.891 +  {
   5.892 +    /* make sure the Dpc queue is run immediately next interrupt */
   5.893 +    KeSetImportanceDpc(&xi->rxtx_dpc, HighImportance);
   5.894 +    /* set an event in TX path */
   5.895 +    dont_set_event = FALSE;
   5.896 +  }
   5.897 +
   5.898 +  /* make packets out of the buffers */
   5.899 +  page_buf = head_buf;
   5.900 +  extra_info_flag = FALSE;
   5.901 +  more_data_flag = FALSE;
   5.902 +
   5.903 +  while (page_buf)
   5.904 +  {
   5.905 +    shared_buffer_t *next_buf = page_buf->next;
   5.906 +    PMDL mdl;
   5.907 +
   5.908 +    page_buf->next = NULL;
   5.909 +    if (extra_info_flag)
   5.910 +    {
   5.911 +      //KdPrint((__DRIVER_NAME "     processing extra info\n"));
   5.912 +      ei = (struct netif_extra_info *)&page_buf->rsp;
   5.913 +      extra_info_flag = ei->flags & XEN_NETIF_EXTRA_FLAG_MORE;
   5.914 +      switch (ei->type)
   5.915 +      {
   5.916 +      case XEN_NETIF_EXTRA_TYPE_GSO:
   5.917 +        switch (ei->u.gso.type)
   5.918 +        {
   5.919 +        case XEN_NETIF_GSO_TYPE_TCPV4:
   5.920 +          pi->mss = ei->u.gso.size;
   5.921 +          //KdPrint((__DRIVER_NAME "     mss = %d\n", pi->mss));
   5.922 +          // TODO - put this assertion somewhere ASSERT(header_len + pi->mss <= PAGE_SIZE); // this limits MTU to PAGE_SIZE - XN_HEADER_LEN
   5.923 +          break;
   5.924 +        default:
   5.925 +          KdPrint((__DRIVER_NAME "     Unknown GSO type (%d) detected\n", ei->u.gso.type));
   5.926 +          break;
   5.927 +        }
   5.928 +        break;
   5.929 +      default:
   5.930 +        KdPrint((__DRIVER_NAME "     Unknown extra info type (%d) detected\n", ei->type));
   5.931 +        break;
   5.932 +      }
   5.933 +      put_pb_on_freelist(xi, page_buf);
   5.934 +    }
   5.935 +    else
   5.936 +    {
   5.937 +      ASSERT(!page_buf->rsp.offset);
   5.938 +      if (!more_data_flag) // handling the packet's 1st buffer
   5.939 +      {
   5.940 +#if 0
   5.941 +        if (page_buf->rsp.flags & NETRXF_csum_blank)
   5.942 +          pi->csum_blank = TRUE;
   5.943 +        if (page_buf->rsp.flags & NETRXF_data_validated)
   5.944 +          pi->data_validated = TRUE;
   5.945 +#endif
   5.946 +      }
   5.947 +      mdl = page_buf->mdl;
   5.948 +      mdl->ByteCount = page_buf->rsp.status; //NdisAdjustBufferLength(mdl, page_buf->rsp.status);
   5.949 +      //KdPrint((__DRIVER_NAME "     buffer = %p, pb = %p\n", buffer, page_buf));
   5.950 +      if (pi->first_pb)
   5.951 +      {
   5.952 +        ASSERT(pi->curr_pb);
   5.953 +        //KdPrint((__DRIVER_NAME "     additional buffer\n"));
   5.954 +        pi->curr_pb->next = page_buf;
   5.955 +        pi->curr_pb = page_buf;
   5.956 +        ASSERT(pi->curr_mdl);
   5.957 +        pi->curr_mdl->Next = mdl;
   5.958 +        pi->curr_mdl = mdl;
   5.959 +      }
   5.960 +      else
   5.961 +      {
   5.962 +        pi->first_pb = page_buf;
   5.963 +        pi->curr_pb = page_buf;
   5.964 +        pi->first_mdl = mdl;
   5.965 +        pi->curr_mdl = mdl;
   5.966 +      }
   5.967 +      //pi->mdl_count++;
   5.968 +      extra_info_flag = (BOOLEAN)(page_buf->rsp.flags & NETRXF_extra_info);
   5.969 +      more_data_flag = (BOOLEAN)(page_buf->rsp.flags & NETRXF_more_data);
   5.970 +      pi->total_length = pi->total_length + page_buf->rsp.status;
   5.971 +    }
   5.972 +
   5.973 +    /* Packet done, add it to the list */
   5.974 +    if (!more_data_flag && !extra_info_flag)
   5.975 +    {
   5.976 +      PNET_BUFFER_LIST nbl;
   5.977 +      pi->curr_pb = pi->first_pb;
   5.978 +      pi->curr_mdl = pi->first_mdl;
   5.979 +      nbl = XenNet_MakePackets(xi, pi);
   5.980 +KdPrint((__DRIVER_NAME "     A\n"));
   5.981 +      if (nbl)
   5.982 +      {
   5.983 +KdPrint((__DRIVER_NAME "     B\n"));
   5.984 +        packet_count += NBL_PACKET_COUNT(nbl);
   5.985 +KdPrint((__DRIVER_NAME "     C %d\n", packet_count));
   5.986 +        nbl_count++;
   5.987 +        if (!nbl_head)
   5.988 +        {
   5.989 +KdPrint((__DRIVER_NAME "     D\n"));
   5.990 +          nbl_head = nbl;
   5.991 +          nbl_tail = nbl;
   5.992 +        }
   5.993 +        else
   5.994 +        {
   5.995 +KdPrint((__DRIVER_NAME "     E\n"));
   5.996 +          NET_BUFFER_LIST_NEXT_NBL(nbl_tail) = nbl;
   5.997 +        }
   5.998 +        NET_BUFFER_LIST_NEXT_NBL(nbl) = NULL;
   5.999 +KdPrint((__DRIVER_NAME "     F\n"));
  5.1000 +      }
  5.1001 +KdPrint((__DRIVER_NAME "     G\n"));
  5.1002 +    }
  5.1003 +
  5.1004 +    page_buf = next_buf;
  5.1005 +  }
  5.1006 +KdPrint((__DRIVER_NAME "     H\n"));
  5.1007 +  ASSERT(!more_data_flag && !extra_info_flag);
  5.1008 +
  5.1009 +  xi->stat_rx_ok += packet_count;
  5.1010 +
  5.1011 +  if (nbl_head)
  5.1012 +  {
  5.1013 +KdPrint((__DRIVER_NAME "     I %d %p\n", nbl_count, nbl_head));
  5.1014 +KdPrint((__DRIVER_NAME "     nbl_head->Context = %p\n", nbl_head->Context));
  5.1015 +KdPrint((__DRIVER_NAME "     nbl_head->ParentNetBufferList = %p\n", nbl_head->ParentNetBufferList));
  5.1016 +KdPrint((__DRIVER_NAME "     nbl_head->NdisPoolHandle = %p\n", nbl_head->NdisPoolHandle));
  5.1017 +KdPrint((__DRIVER_NAME "     nbl_head->NblFlags = %p\n", nbl_head->NblFlags));
  5.1018 +KdPrint((__DRIVER_NAME "     nbl_head->ChildRefCount = %p\n", nbl_head->ChildRefCount));
  5.1019 +KdPrint((__DRIVER_NAME "     nbl_head->Flags = %p\n", nbl_head->Flags));
  5.1020 +KdPrint((__DRIVER_NAME "     nbl_head->Status = %p\n", nbl_head->Status));
  5.1021 +KdPrint((__DRIVER_NAME "     nbl_head->Context = %p\n", nbl_head->Context));
  5.1022 +KdPrint((__DRIVER_NAME "     NET_BUFFER_LIST_FIRST_NB(nbl_head) = %p\n", NET_BUFFER_LIST_FIRST_NB(nbl_head)));
  5.1023 +KdPrint((__DRIVER_NAME "     NET_BUFFER_FIRST_MDL(nb) = %p\n", NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB((nbl_head)))));
  5.1024 +KdPrint((__DRIVER_NAME "     NET_BUFFER_FIRST_MDL(nb)->Next = %p\n", NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB((nbl_head)))->Next));
  5.1025 +
  5.1026 +    NdisMIndicateReceiveNetBufferLists(xi->adapter_handle, nbl_head, NDIS_DEFAULT_PORT_NUMBER, nbl_count,
  5.1027 +      NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL
  5.1028 +      | NDIS_RECEIVE_FLAGS_SINGLE_ETHER_TYPE 
  5.1029 +      | NDIS_RECEIVE_FLAGS_PERFECT_FILTERED);
  5.1030 +  };
  5.1031 +KdPrint((__DRIVER_NAME "     J\n"));
  5.1032 +#if 0
  5.1033 +  /* indicate packets to NDIS */
  5.1034 +  entry = RemoveHeadList(&rx_packet_list);
  5.1035 +  InitializeListHead(&rx_header_only_packet_list);
  5.1036 +  packet_count = 0;
  5.1037 +
  5.1038 +  while (entry != &rx_packet_list) {
  5.1039 +    PNDIS_PACKET packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
  5.1040 +    NDIS_STATUS status;
  5.1041 +    ASSERT(*(shared_buffer_t **)&packet->MiniportReservedEx[0]);
  5.1042 +    status = NDIS_GET_PACKET_STATUS(packet);
  5.1043 +    if (status == NDIS_STATUS_RESOURCES)
  5.1044 +      InsertTailList(&rx_header_only_packet_list, entry);
  5.1045 +    packets[packet_count++] = packet;
  5.1046 +    InterlockedIncrement(&xi->rx_outstanding);
  5.1047 +    entry = RemoveHeadList(&rx_packet_list);
  5.1048 +    /* if we indicate a packet with NDIS_STATUS_RESOURCES  then any following packet can't be NDIS_STATUS_SUCCESS */
  5.1049 +    if (packet_count == MAXIMUM_PACKETS_PER_INDICATE || entry == &rx_packet_list
  5.1050 +        || (NDIS_GET_PACKET_STATUS(CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)])) == NDIS_STATUS_SUCCESS
  5.1051 +            && status == NDIS_STATUS_RESOURCES))
  5.1052 +    {
  5.1053 +      NdisMIndicateReceivePacket(xi->adapter_handle, packets, packet_count);
  5.1054 +      packet_count = 0;
  5.1055 +    }
  5.1056 +  }
  5.1057 +  /* now return the packets for which we indicated NDIS_STATUS_RESOURCES */
  5.1058 +  entry = RemoveHeadList(&rx_header_only_packet_list);
  5.1059 +  while (entry != &rx_header_only_packet_list) {
  5.1060 +    PNDIS_PACKET packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
  5.1061 +    entry = RemoveHeadList(&rx_header_only_packet_list);
  5.1062 +    InterlockedIncrement(&resource_packets);
  5.1063 +    XenNet_ReturnPacket(xi, packet);
  5.1064 +  }
  5.1065 +#endif
  5.1066 +  FUNCTION_EXIT();
  5.1067 +  return dont_set_event;
  5.1068 +}
  5.1069 +
  5.1070 +/*
  5.1071 +   Free all Rx buffers (on halt, for example) 
  5.1072 +   The ring must be stopped at this point.
  5.1073 +*/
  5.1074 +
  5.1075 +static VOID
  5.1076 +XenNet_PurgeRing(struct xennet_info *xi)
  5.1077 +{
  5.1078 +  int i;
  5.1079 +  for (i = 0; i < NET_RX_RING_SIZE; i++)
  5.1080 +  {
  5.1081 +    if (xi->rx_ring_pbs[i] != NULL)
  5.1082 +    {
  5.1083 +      put_pb_on_freelist(xi, xi->rx_ring_pbs[i]);
  5.1084 +      xi->rx_ring_pbs[i] = NULL;
  5.1085 +    }
  5.1086 +  }
  5.1087 +}
  5.1088 +
  5.1089 +static VOID
  5.1090 +XenNet_BufferFree(struct xennet_info *xi)
  5.1091 +{
  5.1092 +  shared_buffer_t *pb;
  5.1093 +
  5.1094 +  XenNet_PurgeRing(xi);
  5.1095 +
  5.1096 +  /* because we are shutting down this won't allocate new ones */
  5.1097 +  while ((pb = get_pb_from_freelist(xi)) != NULL)
  5.1098 +  {
  5.1099 +    xi->vectors.GntTbl_EndAccess(xi->vectors.context,
  5.1100 +        pb->gref, FALSE, (ULONG)'XNRX');
  5.1101 +    IoFreeMdl(pb->mdl);
  5.1102 +    NdisFreeMemory(pb, PAGE_SIZE, 0);
  5.1103 +    NdisFreeMemory(pb->virtual, sizeof(shared_buffer_t), 0);
  5.1104 +  }
  5.1105 +}
  5.1106 +
  5.1107 +VOID
  5.1108 +XenNet_BufferAlloc(xennet_info_t *xi)
  5.1109 +{
  5.1110 +  //NDIS_STATUS status;
  5.1111 +  int i;
  5.1112 +  
  5.1113 +  xi->rx_id_free = NET_RX_RING_SIZE;
  5.1114 +  xi->rx_outstanding = 0;
  5.1115 +
  5.1116 +  for (i = 0; i < NET_RX_RING_SIZE; i++)
  5.1117 +  {
  5.1118 +    xi->rx_ring_pbs[i] = NULL;
  5.1119 +  }
  5.1120 +}
  5.1121 +
  5.1122 +VOID
  5.1123 +XenNet_RxResumeStart(xennet_info_t *xi)
  5.1124 +{
  5.1125 +  KIRQL old_irql;
  5.1126 +
  5.1127 +  FUNCTION_ENTER();
  5.1128 +
  5.1129 +  KeAcquireSpinLock(&xi->rx_lock, &old_irql);
  5.1130 +  XenNet_PurgeRing(xi);
  5.1131 +  KeReleaseSpinLock(&xi->rx_lock, old_irql);
  5.1132 +  
  5.1133 +  FUNCTION_EXIT();
  5.1134 +}
  5.1135 +
  5.1136 +VOID
  5.1137 +XenNet_RxResumeEnd(xennet_info_t *xi)
  5.1138 +{
  5.1139 +  KIRQL old_irql;
  5.1140 +
  5.1141 +  FUNCTION_ENTER();
  5.1142 +
  5.1143 +  KeAcquireSpinLock(&xi->rx_lock, &old_irql);
  5.1144 +  //XenNet_BufferAlloc(xi);
  5.1145 +  XenNet_FillRing(xi);
  5.1146 +  KeReleaseSpinLock(&xi->rx_lock, old_irql);
  5.1147 +  
  5.1148 +  FUNCTION_EXIT();
  5.1149 +}
  5.1150 +
  5.1151 +BOOLEAN
  5.1152 +XenNet_RxInit(xennet_info_t *xi)
  5.1153 +{
  5.1154 +  NET_BUFFER_LIST_POOL_PARAMETERS nbl_pool_parameters;
  5.1155 +  NET_BUFFER_POOL_PARAMETERS nb_pool_parameters;
  5.1156 +  UNREFERENCED_PARAMETER(xi);
  5.1157 +
  5.1158 +  FUNCTION_ENTER();
  5.1159 +
  5.1160 +  xi->rx_shutting_down = FALSE;
  5.1161 +  KeInitializeSpinLock(&xi->rx_lock);
  5.1162 +  KeInitializeEvent(&xi->packet_returned_event, SynchronizationEvent, FALSE);
  5.1163 +  KeInitializeTimer(&xi->rx_timer);
  5.1164 +  xi->rxpi = NdisAllocateMemoryWithTagPriority(xi->adapter_handle, sizeof(packet_info_t) * NdisSystemProcessorCount(), XENNET_POOL_TAG, NormalPoolPriority);
  5.1165 +  if (!xi->rxpi)
  5.1166 +  {
  5.1167 +    KdPrint(("NdisAllocateMemoryWithTagPriority failed\n"));
  5.1168 +    return FALSE;
  5.1169 +  }
  5.1170 +  NdisZeroMemory(xi->rxpi, sizeof(packet_info_t) * NdisSystemProcessorCount());
  5.1171 +
  5.1172 +  stack_new(&xi->rx_pb_stack, NET_RX_RING_SIZE * 4);
  5.1173 +
  5.1174 +  XenNet_BufferAlloc(xi);
  5.1175 +  
  5.1176 +  nbl_pool_parameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
  5.1177 +  nbl_pool_parameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
  5.1178 +  nbl_pool_parameters.Header.Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
  5.1179 +  nbl_pool_parameters.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
  5.1180 +  nbl_pool_parameters.fAllocateNetBuffer = FALSE;
  5.1181 +  nbl_pool_parameters.ContextSize = 0;
  5.1182 +  nbl_pool_parameters.PoolTag = XENNET_POOL_TAG;
  5.1183 +  nbl_pool_parameters.DataSize = 0; /* NET_BUFFERS are always allocated separately */
  5.1184 +  
  5.1185 +  xi->rx_nbl_pool = NdisAllocateNetBufferListPool(xi->adapter_handle, &nbl_pool_parameters);
  5.1186 +  if (!xi->rx_nbl_pool)
  5.1187 +  {
  5.1188 +    KdPrint(("NdisAllocateNetBufferListPool failed\n"));
  5.1189 +    return FALSE;
  5.1190 +  }
  5.1191 +  //stack_new(&xi->rx_packet_stack, NET_RX_RING_SIZE * 4);
  5.1192 +
  5.1193 +  nb_pool_parameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
  5.1194 +  nb_pool_parameters.Header.Revision = NET_BUFFER_POOL_PARAMETERS_REVISION_1;
  5.1195 +  nb_pool_parameters.Header.Size = NDIS_SIZEOF_NET_BUFFER_POOL_PARAMETERS_REVISION_1;
  5.1196 +  nb_pool_parameters.PoolTag = XENNET_POOL_TAG;
  5.1197 +  nb_pool_parameters.DataSize = 0; /* the buffers come from the ring */
  5.1198 +  xi->rx_nb_pool = NdisAllocateNetBufferPool(xi->adapter_handle, &nb_pool_parameters);
  5.1199 +  if (!xi->rx_nb_pool)
  5.1200 +  {
  5.1201 +    KdPrint(("NdisAllocateNetBufferPool (rx_nb_pool) failed\n"));
  5.1202 +    return FALSE;
  5.1203 +  }
  5.1204 +
  5.1205 +  NdisInitializeNPagedLookasideList(&xi->rx_lookaside_list, NULL, NULL, 0,
  5.1206 +    MAX_ETH_HEADER_LENGTH + MAX_LOOKAHEAD_LENGTH + sizeof(shared_buffer_t), XENNET_POOL_TAG, 0);
  5.1207 +  
  5.1208 +  XenNet_FillRing(xi);
  5.1209 +
  5.1210 +  FUNCTION_EXIT();
  5.1211 +
  5.1212 +  return TRUE;
  5.1213 +}
  5.1214 +
  5.1215 +BOOLEAN
  5.1216 +XenNet_RxShutdown(xennet_info_t *xi)
  5.1217 +{
  5.1218 +  //KIRQL old_irql;
  5.1219 +  //PNDIS_PACKET packet;
  5.1220 +  UNREFERENCED_PARAMETER(xi);
  5.1221 +
  5.1222 +  FUNCTION_ENTER();
  5.1223 +
  5.1224 +#if 0
  5.1225 +  KeAcquireSpinLock(&xi->rx_lock, &old_irql);
  5.1226 +  xi->rx_shutting_down = TRUE;
  5.1227 +  KeReleaseSpinLock(&xi->rx_lock, old_irql);
  5.1228 +
  5.1229 +  if (xi->config_rx_interrupt_moderation)
  5.1230 +  {
  5.1231 +    KeCancelTimer(&xi->rx_timer);
  5.1232 +  }
  5.1233 +
  5.1234 +  KeFlushQueuedDpcs();
  5.1235 +
  5.1236 +  while (xi->rx_outstanding)
  5.1237 +  {
  5.1238 +    KdPrint((__DRIVER_NAME "     Waiting for all packets to be returned\n"));
  5.1239 +    KeWaitForSingleObject(&xi->packet_returned_event, Executive, KernelMode, FALSE, NULL);
  5.1240 +  }
  5.1241 +
  5.1242 +  //KeAcquireSpinLock(&xi->rx_lock, &old_irql);
  5.1243 +
  5.1244 +  NdisFreeMemory(xi->rxpi, sizeof(packet_info_t) * NdisSystemProcessorCount(), 0);
  5.1245 +
  5.1246 +  XenNet_BufferFree(xi);
  5.1247 +
  5.1248 +  /* this works because get_packet_from_freelist won't allocate new packets when rx_shutting_down */
  5.1249 +  while ((packet = get_packet_from_freelist(xi)) != NULL)
  5.1250 +    NdisFreePacket(packet);
  5.1251 +  //stack_delete(xi->rx_packet_stack, NULL, NULL);
  5.1252 +  NdisFreePacketPool(xi->rx_packet_pool);
  5.1253 +
  5.1254 +  NdisDeleteNPagedLookasideList(&xi->rx_lookaside_list);
  5.1255 +
  5.1256 +  stack_delete(xi->rx_pb_stack, NULL, NULL);
  5.1257 +  //KeReleaseSpinLock(&xi->rx_lock, old_irql);
  5.1258 +
  5.1259 +#endif
  5.1260 +  FUNCTION_EXIT();
  5.1261 +
  5.1262 +  return TRUE;
  5.1263 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/xennet/xennet6_tx.c	Mon May 02 00:17:33 2011 +1000
     6.3 @@ -0,0 +1,765 @@
     6.4 +/*
     6.5 +PV Net Driver for Windows Xen HVM Domains
     6.6 +Copyright (C) 2007 James Harper
     6.7 +Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
     6.8 +
     6.9 +This program is free software; you can redistribute it and/or
    6.10 +modify it under the terms of the GNU General Public License
    6.11 +as published by the Free Software Foundation; either version 2
    6.12 +of the License, or (at your option) any later version.
    6.13 +
    6.14 +This program is distributed in the hope that it will be useful,
    6.15 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.16 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    6.17 +GNU General Public License for more details.
    6.18 +
    6.19 +You should have received a copy of the GNU General Public License
    6.20 +along with this program; if not, write to the Free Software
    6.21 +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    6.22 +*/
    6.23 +
    6.24 +#include "xennet6.h"
    6.25 +
    6.26 +static USHORT
    6.27 +get_id_from_freelist(struct xennet_info *xi)
    6.28 +{
    6.29 +  ASSERT(xi->tx_id_free);
    6.30 +  xi->tx_id_free--;
    6.31 +
    6.32 +  return xi->tx_id_list[xi->tx_id_free];
    6.33 +}
    6.34 +
    6.35 +static VOID
    6.36 +put_id_on_freelist(struct xennet_info *xi, USHORT id)
    6.37 +{
    6.38 +  xi->tx_id_list[xi->tx_id_free] = id;
    6.39 +  xi->tx_id_free++;
    6.40 +}
    6.41 +
    6.42 +#define SWAP_USHORT(x) (USHORT)((((x & 0xFF) << 8)|((x >> 8) & 0xFF)))
    6.43 +
    6.44 +static __forceinline struct netif_tx_request *
    6.45 +XenNet_PutCbOnRing(struct xennet_info *xi, PVOID coalesce_buf, ULONG length, grant_ref_t gref)
    6.46 +{
    6.47 +  struct netif_tx_request *tx;
    6.48 +  tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
    6.49 +  xi->tx.req_prod_pvt++;
    6.50 +  xi->tx_ring_free--;
    6.51 +  tx->id = get_id_from_freelist(xi);
    6.52 +  ASSERT(xi->tx_shadows[tx->id].gref == INVALID_GRANT_REF);
    6.53 +  ASSERT(!xi->tx_shadows[tx->id].cb);
    6.54 +  xi->tx_shadows[tx->id].cb = coalesce_buf;
    6.55 +  tx->gref = xi->vectors.GntTbl_GrantAccess(xi->vectors.context, 0, (ULONG)(MmGetPhysicalAddress(coalesce_buf).QuadPart >> PAGE_SHIFT), FALSE, gref, (ULONG)'XNTX');
    6.56 +  xi->tx_shadows[tx->id].gref = tx->gref;
    6.57 +  tx->offset = 0;
    6.58 +  tx->size = (USHORT)length;
    6.59 +  ASSERT(tx->offset + tx->size <= PAGE_SIZE);
    6.60 +  ASSERT(tx->size);
    6.61 +  return tx;
    6.62 +}
    6.63 +  
    6.64 +/* Called at DISPATCH_LEVEL with tx_lock held */
    6.65 +/*
    6.66 + * Send one NDIS_PACKET. This may involve multiple entries on TX ring.
    6.67 + */
    6.68 +static BOOLEAN
    6.69 +XenNet_HWSendPacket(struct xennet_info *xi, PNET_BUFFER nb)
    6.70 +{
    6.71 +  struct netif_tx_request *tx0 = NULL;
    6.72 +  struct netif_tx_request *txN = NULL;
    6.73 +  struct netif_extra_info *ei = NULL;
    6.74 +  //PNDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
    6.75 +  ULONG mss = 0;
    6.76 +  uint16_t flags = NETTXF_more_data;
    6.77 +  packet_info_t pi;
    6.78 +  BOOLEAN ndis_lso = FALSE;
    6.79 +  BOOLEAN xen_gso = FALSE;
    6.80 +  ULONG remaining;
    6.81 +  ULONG parse_result;
    6.82 +  ULONG frags = 0;
    6.83 +  BOOLEAN coalesce_required = FALSE;
    6.84 +  PVOID coalesce_buf;
    6.85 +  ULONG coalesce_remaining = 0;
    6.86 +  grant_ref_t gref;
    6.87 +  ULONG tx_length = 0;
    6.88 +  
    6.89 +  FUNCTION_ENTER();
    6.90 +
    6.91 +  gref = xi->vectors.GntTbl_GetRef(xi->vectors.context, (ULONG)'XNTX');
    6.92 +  if (gref == INVALID_GRANT_REF)
    6.93 +  {
    6.94 +    KdPrint((__DRIVER_NAME "     out of grefs\n"));
    6.95 +    return FALSE;
    6.96 +  }
    6.97 +  coalesce_buf = NdisAllocateFromNPagedLookasideList(&xi->tx_lookaside_list);
    6.98 +  if (!coalesce_buf)
    6.99 +  {
   6.100 +    xi->vectors.GntTbl_PutRef(xi->vectors.context, gref, (ULONG)'XNTX');
   6.101 +    KdPrint((__DRIVER_NAME "     out of memory\n"));
   6.102 +    return FALSE;
   6.103 +  }
   6.104 +  XenNet_ClearPacketInfo(&pi);
   6.105 +  //NdisQueryPacket(packet, NULL, (PUINT)&pi.mdl_count, &pi.first_buffer, (PUINT)&pi.total_length);
   6.106 +  pi.first_mdl = pi.curr_mdl = nb->CurrentMdl;
   6.107 +  pi.first_mdl_offset = pi.curr_mdl_offset = nb->CurrentMdlOffset;
   6.108 +  pi.total_length = nb->DataLength;
   6.109 +//KdPrint((__DRIVER_NAME "     A first_mdl = %p\n", pi.first_mdl));
   6.110 +KdPrint((__DRIVER_NAME "     A total_length = %d\n", pi.total_length));
   6.111 +KdPrint((__DRIVER_NAME "     B curr_mdl_offset = %p\n", pi.curr_mdl_offset));
   6.112 +  remaining = min(pi.total_length, PAGE_SIZE);
   6.113 +KdPrint((__DRIVER_NAME "     C remaining = %d\n", remaining));
   6.114 +  while (remaining) /* this much gets put in the header */
   6.115 +  {
   6.116 +    ULONG length = XenNet_QueryData(&pi, remaining);
   6.117 +    remaining -= length;
   6.118 +KdPrint((__DRIVER_NAME "     D length = %d, remaining = %d\n", length, remaining));
   6.119 +    XenNet_EatData(&pi, length);
   6.120 +  }
   6.121 +  frags++;
   6.122 +KdPrint((__DRIVER_NAME "     Da\n"));
   6.123 +  if (pi.total_length > PAGE_SIZE) /* these are the frags we care about */
   6.124 +  {
   6.125 +    remaining = pi.total_length - PAGE_SIZE;
   6.126 +KdPrint((__DRIVER_NAME "     E remaining = %d\n", remaining));
   6.127 +    while (remaining)
   6.128 +    {
   6.129 +      ULONG length = XenNet_QueryData(&pi, PAGE_SIZE);
   6.130 +KdPrint((__DRIVER_NAME "     F length = %d\n", length));
   6.131 +      if (length != 0)
   6.132 +      {
   6.133 +        frags++;
   6.134 +        if (frags > LINUX_MAX_SG_ELEMENTS)
   6.135 +          break; /* worst case there could be hundreds of fragments - leave the loop now */
   6.136 +      }
   6.137 +KdPrint((__DRIVER_NAME "     G remaining = %d\n", remaining));
   6.138 +      remaining -= length;
   6.139 +      XenNet_EatData(&pi, length);
   6.140 +    }
   6.141 +  }
   6.142 +KdPrint((__DRIVER_NAME "     H remaining = %d, frags = %d, LINUX_MAX_SG_ELEMENTS = %d\n", remaining, frags, LINUX_MAX_SG_ELEMENTS));
   6.143 +  if (frags > LINUX_MAX_SG_ELEMENTS)
   6.144 +  {
   6.145 +    frags = LINUX_MAX_SG_ELEMENTS;
   6.146 +    coalesce_required = TRUE;
   6.147 +  }
   6.148 +
   6.149 +  /* if we have enough space on the ring then we have enough id's so no need to check for that */
   6.150 +  if (xi->tx_ring_free < frags + 1)
   6.151 +  {
   6.152 +    xi->vectors.GntTbl_PutRef(xi->vectors.context, gref, (ULONG)'XNTX');
   6.153 +    NdisFreeToNPagedLookasideList(&xi->tx_lookaside_list, coalesce_buf);
   6.154 +    KdPrint((__DRIVER_NAME "     Full on send - ring full\n"));
   6.155 +    return FALSE;
   6.156 +  }
   6.157 +  parse_result = XenNet_ParsePacketHeader(&pi, coalesce_buf, PAGE_SIZE);
   6.158 +KdPrint((__DRIVER_NAME "     I parse_result = %d\n", parse_result));
   6.159 +  remaining = pi.total_length - pi.header_length;
   6.160 +KdPrint((__DRIVER_NAME "     J total_length = %d, header_length = %d, remaining = %d\n", pi.total_length, pi.header_length, remaining));
   6.161 +
   6.162 +#if 0
   6.163 +  if (NDIS_GET_PACKET_PROTOCOL_TYPE(packet) == NDIS_PROTOCOL_ID_TCP_IP)
   6.164 +  {
   6.165 +    csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(
   6.166 +      packet, TcpIpChecksumPacketInfo);
   6.167 +    if (csum_info->Transmit.NdisPacketChecksumV4)
   6.168 +    {
   6.169 +      if (csum_info->Transmit.NdisPacketIpChecksum && !xi->setting_csum.V4Transmit.IpChecksum)
   6.170 +      {
   6.171 +        KdPrint((__DRIVER_NAME "     IpChecksum not enabled\n"));
   6.172 +        //NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_FAILURE);
   6.173 +        //return TRUE;
   6.174 +      }
   6.175 +      if (csum_info->Transmit.NdisPacketTcpChecksum)
   6.176 +      {
   6.177 +        if (xi->setting_csum.V4Transmit.TcpChecksum)
   6.178 +        {
   6.179 +          flags |= NETTXF_csum_blank | NETTXF_data_validated;
   6.180 +        }
   6.181 +        else
   6.182 +        {
   6.183 +          KdPrint((__DRIVER_NAME "     TcpChecksum not enabled\n"));
   6.184 +          //NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_FAILURE);
   6.185 +          //return TRUE;
   6.186 +        }
   6.187 +      }
   6.188 +      else if (csum_info->Transmit.NdisPacketUdpChecksum)
   6.189 +      {
   6.190 +        if (xi->setting_csum.V4Transmit.UdpChecksum)
   6.191 +        {
   6.192 +          flags |= NETTXF_csum_blank | NETTXF_data_validated;
   6.193 +        }
   6.194 +        else
   6.195 +        {
   6.196 +          KdPrint((__DRIVER_NAME "     UdpChecksum not enabled\n"));
   6.197 +          //NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_FAILURE);
   6.198 +          //return TRUE;
   6.199 +        }
   6.200 +      }
   6.201 +    }
   6.202 +    else if (csum_info->Transmit.NdisPacketChecksumV6)
   6.203 +    {
   6.204 +      KdPrint((__DRIVER_NAME "     NdisPacketChecksumV6 not supported\n"));
   6.205 +      //NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_FAILURE);
   6.206 +      //return TRUE;
   6.207 +    }
   6.208 +  }
   6.209 +  
   6.210 +  mss = PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpLargeSendPacketInfo));
   6.211 +
   6.212 +  if (mss && parse_result == PARSE_OK)
   6.213 +  {
   6.214 +    if (NDIS_GET_PACKET_PROTOCOL_TYPE(packet) != NDIS_PROTOCOL_ID_TCP_IP)
   6.215 +    {
   6.216 +      KdPrint((__DRIVER_NAME "     mss specified when packet is not NDIS_PROTOCOL_ID_TCP_IP\n"));
   6.217 +    }
   6.218 +    ndis_lso = TRUE;
   6.219 +    if (mss > xi->setting_max_offload)
   6.220 +    {
   6.221 +      KdPrint((__DRIVER_NAME "     Requested MSS (%d) larger than allowed MSS (%d)\n", mss, xi->setting_max_offload));
   6.222 +      //NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_FAILURE);
   6.223 +      //FUNCTION_EXIT();
   6.224 +      return TRUE;
   6.225 +    }
   6.226 +  }
   6.227 +
   6.228 +  if (ndis_lso)
   6.229 +  {    
   6.230 +    flags |= NETTXF_csum_blank | NETTXF_data_validated; /* these may be implied but not specified when lso is used*/
   6.231 +    if (pi.tcp_length >= mss)
   6.232 +    {
   6.233 +      flags |= NETTXF_extra_info;
   6.234 +      xen_gso = TRUE;
   6.235 +    }
   6.236 +    else
   6.237 +    {
   6.238 +      KdPrint((__DRIVER_NAME "     large send specified when tcp_length < mss\n"));
   6.239 +    }
   6.240 +  }
   6.241 +#endif
   6.242 +/*
   6.243 +* See io/netif.h. Must put (A) 1st request, then (B) optional extra_info, then
   6.244 +* (C) rest of requests on the ring. Only (A) has csum flags.
   6.245 +*/
   6.246 +
   6.247 +  /* (A) */
   6.248 +  KdPrint((__DRIVER_NAME "     AA\n"));
   6.249 +  KdPrint((__DRIVER_NAME "     AA XenNet_PutCbOnRing %d\n", min(PAGE_SIZE, remaining)));
   6.250 +  tx0 = XenNet_PutCbOnRing(xi, coalesce_buf, pi.header_length, gref);
   6.251 +  ASSERT(tx0); /* this will never happen */
   6.252 +  tx0->flags = flags;
   6.253 +  tx_length += pi.header_length;
   6.254 +
   6.255 +  /* even though we haven't reported that we are capable of it, LSO demands that we calculate the IP Header checksum */
   6.256 +  if (ndis_lso)
   6.257 +  {
   6.258 +    XenNet_SumIpHeader(coalesce_buf, pi.ip4_header_length);
   6.259 +  }
   6.260 +  txN = tx0;
   6.261 +
   6.262 +  /* (B) */
   6.263 +  KdPrint((__DRIVER_NAME "     BB\n"));
   6.264 +  if (xen_gso)
   6.265 +  {
   6.266 +    ASSERT(flags & NETTXF_extra_info);
   6.267 +    ei = (struct netif_extra_info *)RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
   6.268 +    //KdPrint((__DRIVER_NAME "     pos = %d\n", xi->tx.req_prod_pvt));
   6.269 +    xi->tx.req_prod_pvt++;
   6.270 +    xi->tx_ring_free--;
   6.271 +    ei->type = XEN_NETIF_EXTRA_TYPE_GSO;
   6.272 +    ei->flags = 0;
   6.273 +    ei->u.gso.size = (USHORT)mss;
   6.274 +    ei->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
   6.275 +    ei->u.gso.pad = 0;
   6.276 +    ei->u.gso.features = 0;
   6.277 +  }
   6.278 +
   6.279 +  ASSERT(xi->config_sg || !remaining);
   6.280 +  
   6.281 +  /* (C) - only if data is remaining */
   6.282 +  KdPrint((__DRIVER_NAME "     CC\n"));
   6.283 +  coalesce_buf = NULL;
   6.284 +  while (remaining > 0)
   6.285 +  {
   6.286 +    ULONG length;
   6.287 +    PFN_NUMBER pfn;
   6.288 +    
   6.289 +    ASSERT(pi.curr_mdl);
   6.290 +    if (coalesce_required)
   6.291 +    {
   6.292 +      PVOID va;
   6.293 +      if (!coalesce_buf)
   6.294 +      {
   6.295 +        gref = xi->vectors.GntTbl_GetRef(xi->vectors.context, (ULONG)'XNTX');
   6.296 +        if (gref == INVALID_GRANT_REF)
   6.297 +        {
   6.298 +          KdPrint((__DRIVER_NAME "     out of grefs - partial send\n"));
   6.299 +          break;
   6.300 +        }
   6.301 +        coalesce_buf = NdisAllocateFromNPagedLookasideList(&xi->tx_lookaside_list);
   6.302 +        if (!coalesce_buf)
   6.303 +        {
   6.304 +          xi->vectors.GntTbl_PutRef(xi->vectors.context, gref, (ULONG)'XNTX');
   6.305 +          KdPrint((__DRIVER_NAME "     out of memory - partial send\n"));
   6.306 +          break;
   6.307 +        }
   6.308 +        coalesce_remaining = min(PAGE_SIZE, remaining);
   6.309 +      }
   6.310 +      length = XenNet_QueryData(&pi, coalesce_remaining);
   6.311 +      va = NdisBufferVirtualAddressSafe(pi.curr_mdl, LowPagePriority);
   6.312 +      if (!va)
   6.313 +      {
   6.314 +        KdPrint((__DRIVER_NAME "     failed to map buffer va - partial send\n"));
   6.315 +        coalesce_remaining = 0;
   6.316 +        remaining -= min(PAGE_SIZE, remaining);
   6.317 +        NdisFreeToNPagedLookasideList(&xi->tx_lookaside_list, coalesce_buf);
   6.318 +      }
   6.319 +      else
   6.320 +      {
   6.321 +        memcpy((PUCHAR)coalesce_buf + min(PAGE_SIZE, remaining) - coalesce_remaining, (PUCHAR)va + pi.curr_mdl_offset, length);
   6.322 +        coalesce_remaining -= length;
   6.323 +      }
   6.324 +    }
   6.325 +    else
   6.326 +    {
   6.327 +      length = XenNet_QueryData(&pi, PAGE_SIZE);
   6.328 +    }
   6.329 +    if (!length || coalesce_remaining) /* sometimes there are zero length buffers... */
   6.330 +    {
   6.331 +      XenNet_EatData(&pi, length); /* do this so we actually move to the next buffer */
   6.332 +      continue;
   6.333 +    }
   6.334 +
   6.335 +    if (coalesce_buf)
   6.336 +    {
   6.337 +      if (remaining)
   6.338 +      {
   6.339 +        KdPrint((__DRIVER_NAME "     CC XenNet_PutCbOnRing %d\n", min(PAGE_SIZE, remaining)));
   6.340 +        txN = XenNet_PutCbOnRing(xi, coalesce_buf, min(PAGE_SIZE, remaining), gref);
   6.341 +        ASSERT(txN);
   6.342 +        coalesce_buf = NULL;
   6.343 +        remaining -= min(PAGE_SIZE, remaining);
   6.344 +        tx_length += min(PAGE_SIZE, remaining);
   6.345 +      }
   6.346 +    }
   6.347 +    else
   6.348 +    {
   6.349 +      ULONG offset;
   6.350 +      
   6.351 +      gref = xi->vectors.GntTbl_GetRef(xi->vectors.context, (ULONG)'XNTX');
   6.352 +      if (gref == INVALID_GRANT_REF)
   6.353 +      {
   6.354 +        KdPrint((__DRIVER_NAME "     out of grefs - partial send\n"));
   6.355 +        break;
   6.356 +      }
   6.357 +      txN = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
   6.358 +      xi->tx.req_prod_pvt++;
   6.359 +      xi->tx_ring_free--;
   6.360 +      txN->id = get_id_from_freelist(xi);
   6.361 +      ASSERT(!xi->tx_shadows[txN->id].cb);
   6.362 +      offset = MmGetMdlByteOffset(pi.curr_mdl) + pi.curr_mdl_offset;
   6.363 +      pfn = MmGetMdlPfnArray(pi.curr_mdl)[offset >> PAGE_SHIFT];
   6.364 +      txN->offset = (USHORT)offset & (PAGE_SIZE - 1);
   6.365 +      txN->gref = xi->vectors.GntTbl_GrantAccess(xi->vectors.context, 0, (ULONG)pfn, FALSE, gref, (ULONG)'XNTX');
   6.366 +      ASSERT(xi->tx_shadows[txN->id].gref == INVALID_GRANT_REF);
   6.367 +      xi->tx_shadows[txN->id].gref = txN->gref;
   6.368 +      //ASSERT(sg->Elements[sg_element].Length > sg_offset);
   6.369 +      txN->size = (USHORT)length;
   6.370 +      ASSERT(txN->offset + txN->size <= PAGE_SIZE);
   6.371 +      ASSERT(txN->size);
   6.372 +      ASSERT(txN->gref != INVALID_GRANT_REF);
   6.373 +      remaining -= length;
   6.374 +      tx_length += length;
   6.375 +    }
   6.376 +    tx0->size = tx0->size + txN->size;
   6.377 +    txN->flags = NETTXF_more_data;
   6.378 +    XenNet_EatData(&pi, length);
   6.379 +  }
   6.380 +  txN->flags &= ~NETTXF_more_data;
   6.381 +  ASSERT(tx0->size == pi.total_length);
   6.382 +  ASSERT(!xi->tx_shadows[txN->id].nb);
   6.383 +  xi->tx_shadows[txN->id].nb = nb;
   6.384 +
   6.385 +#if 0
   6.386 +  if (ndis_lso)
   6.387 +  {
   6.388 +    //KdPrint((__DRIVER_NAME "     TcpLargeSendPacketInfo = %d\n", pi.tcp_length));
   6.389 +    NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpLargeSendPacketInfo) = UlongToPtr(tx_length - MAX_ETH_HEADER_LENGTH - pi.ip4_header_length - pi.tcp_header_length);
   6.390 +  }
   6.391 +#endif
   6.392 +
   6.393 +  xi->stat_tx_ok++;
   6.394 +
   6.395 +  //NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS);
   6.396 +  //FUNCTION_EXIT();
   6.397 +  xi->tx_outstanding++;
   6.398 +  return TRUE;
   6.399 +}
   6.400 +
   6.401 +/* Called at DISPATCH_LEVEL with tx_lock held */
   6.402 +static VOID
   6.403 +XenNet_SendQueuedPackets(struct xennet_info *xi)
   6.404 +{
   6.405 +  PLIST_ENTRY nb_entry;
   6.406 +  PNET_BUFFER nb;
   6.407 +  int notify;
   6.408 +
   6.409 +  //FUNCTION_ENTER();
   6.410 +
   6.411 +  if (xi->device_state->suspend_resume_state_pdo != SR_STATE_RUNNING)
   6.412 +    return;
   6.413 +
   6.414 +  nb_entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
   6.415 +  /* if empty, the above returns head*, not NULL */
   6.416 +  while (nb_entry != &xi->tx_waiting_pkt_list)
   6.417 +  {
   6.418 +    nb = CONTAINING_RECORD(nb_entry, NET_BUFFER, NB_LIST_ENTRY_FIELD);
   6.419 +    KdPrint((__DRIVER_NAME "     sending %p from %p\n", nb, NB_NBL(nb)));
   6.420 +    
   6.421 +    if (!XenNet_HWSendPacket(xi, nb))
   6.422 +    {
   6.423 +      KdPrint((__DRIVER_NAME "     No room for packet\n"));
   6.424 +      InsertHeadList(&xi->tx_waiting_pkt_list, nb_entry);
   6.425 +      break;
   6.426 +    }
   6.427 +    nb_entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
   6.428 +  }
   6.429 +
   6.430 +  RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
   6.431 +  if (notify)
   6.432 +  {
   6.433 +    xi->vectors.EvtChn_Notify(xi->vectors.context, xi->event_channel);
   6.434 +  }
   6.435 +  //FUNCTION_EXIT();
   6.436 +}
   6.437 +
   6.438 +// Called at DISPATCH_LEVEL
   6.439 +VOID
   6.440 +XenNet_TxBufferGC(struct xennet_info *xi, BOOLEAN dont_set_event)
   6.441 +{
   6.442 +  RING_IDX cons, prod;
   6.443 +  LIST_ENTRY nb_head;
   6.444 +  PLIST_ENTRY nb_entry;
   6.445 +  PNET_BUFFER nb;
   6.446 +  ULONG tx_packets = 0;
   6.447 +
   6.448 +  FUNCTION_ENTER();
   6.449 +
   6.450 +  if (!xi->connected)
   6.451 +    return; /* a delayed DPC could let this come through... just do nothing */
   6.452 +  ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
   6.453 +
   6.454 +  KeAcquireSpinLockAtDpcLevel(&xi->tx_lock);
   6.455 +
   6.456 +  InitializeListHead(&nb_head);
   6.457 +  if (xi->tx_shutting_down && !xi->tx_outstanding)
   6.458 +  {
   6.459 +    /* there is a chance that our Dpc had been queued just before the shutdown... */
   6.460 +    KeSetEvent(&xi->tx_idle_event, IO_NO_INCREMENT, FALSE);
   6.461 +    KeReleaseSpinLockFromDpcLevel(&xi->tx_lock);
   6.462 +    return;
   6.463 +  }
   6.464 +
   6.465 +  do {
   6.466 +    prod = xi->tx.sring->rsp_prod;
   6.467 +    KeMemoryBarrier(); /* Ensure we see responses up to 'rsp_prod'. */
   6.468 +
   6.469 +    for (cons = xi->tx.rsp_cons; cons != prod; cons++)
   6.470 +    {
   6.471 +      struct netif_tx_response *txrsp;
   6.472 +      tx_shadow_t *shadow;
   6.473 +      
   6.474 +      txrsp = RING_GET_RESPONSE(&xi->tx, cons);
   6.475 +      
   6.476 +      xi->tx_ring_free++;
   6.477 +      
   6.478 +      if (txrsp->status == NETIF_RSP_NULL)
   6.479 +      {
   6.480 +        continue;
   6.481 +      }
   6.482 +
   6.483 +      shadow = &xi->tx_shadows[txrsp->id];
   6.484 +      if (shadow->cb)
   6.485 +      {
   6.486 +        NdisFreeToNPagedLookasideList(&xi->tx_lookaside_list, shadow->cb);
   6.487 +        shadow->cb = NULL;
   6.488 +      }
   6.489 +      
   6.490 +      if (shadow->gref != INVALID_GRANT_REF)
   6.491 +      {
   6.492 +        xi->vectors.GntTbl_EndAccess(xi->vectors.context,
   6.493 +          shadow->gref, FALSE, (ULONG)'XNTX');
   6.494 +        shadow->gref = INVALID_GRANT_REF;
   6.495 +      }
   6.496 +      
   6.497 +      if (shadow->nb)
   6.498 +      {
   6.499 +        PLIST_ENTRY nb_entry;
   6.500 +        KdPrint((__DRIVER_NAME "     nb %p complete\n"));
   6.501 +        nb = shadow->nb;
   6.502 +        nb_entry = &NB_LIST_ENTRY(nb);
   6.503 +        InsertTailList(&nb_head, nb_entry);
   6.504 +        shadow->nb = NULL;
   6.505 +      }
   6.506 +      put_id_on_freelist(xi, txrsp->id);
   6.507 +    }
   6.508 +
   6.509 +    xi->tx.rsp_cons = prod;
   6.510 +    /* resist the temptation to set the event more than +1... it breaks things */
   6.511 +    /* although I think we could set it to higher if we knew there were more outstanding packets coming soon... */
   6.512 +    if (!dont_set_event)
   6.513 +      xi->tx.sring->rsp_event = prod + 1;
   6.514 +    KeMemoryBarrier();
   6.515 +  } while (prod != xi->tx.sring->rsp_prod);
   6.516 +
   6.517 +  /* if queued packets, send them now */
   6.518 +  if (!xi->tx_shutting_down)
   6.519 +    XenNet_SendQueuedPackets(xi);
   6.520 +
   6.521 +  KeReleaseSpinLockFromDpcLevel(&xi->tx_lock);
   6.522 +
   6.523 +  /* must be done without holding any locks */
   6.524 +  nb_entry = RemoveHeadList(&nb_head);
   6.525 +  /* if empty, the above returns head*, not NULL */
   6.526 +  while (nb_entry != &nb_head)
   6.527 +  {
   6.528 +    PNET_BUFFER_LIST nbl;
   6.529 +    nb = CONTAINING_RECORD(nb_entry, NET_BUFFER, NB_LIST_ENTRY_FIELD);
   6.530 +    nbl = NB_NBL(nb);
   6.531 +    NBL_REF(nbl)--;
   6.532 +    KdPrint((__DRIVER_NAME "     nb %p from %p complete, refcount = %d\n", nb, nbl, NBL_REF(nbl)));
   6.533 +    if (!NBL_REF(nbl))
   6.534 +    {
   6.535 +      nbl->Status = NDIS_STATUS_SUCCESS;
   6.536 +      NdisMSendNetBufferListsComplete(xi->adapter_handle, nbl, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL);
   6.537 +      KdPrint((__DRIVER_NAME "     NdisMSendNetBufferListsComplete\n"));
   6.538 +    }
   6.539 +    tx_packets++;
   6.540 +    nb_entry = RemoveHeadList(&nb_head);
   6.541 +  }
   6.542 +
   6.543 +  /* must be done after we have truly given back all packets */
   6.544 +  KeAcquireSpinLockAtDpcLevel(&xi->tx_lock);
   6.545 +  xi->tx_outstanding -= tx_packets;
   6.546 +  if (!xi->tx_outstanding && xi->tx_shutting_down)
   6.547 +    KeSetEvent(&xi->tx_idle_event, IO_NO_INCREMENT, FALSE);
   6.548 +  KeReleaseSpinLockFromDpcLevel(&xi->tx_lock);
   6.549 +
   6.550 +  if (xi->device_state->suspend_resume_state_pdo == SR_STATE_SUSPENDING
   6.551 +    && xi->device_state->suspend_resume_state_fdo != SR_STATE_SUSPENDING
   6.552 +    && xi->tx_id_free == NET_TX_RING_SIZE)
   6.553 +  {
   6.554 +    KdPrint((__DRIVER_NAME "     Setting SR_STATE_SUSPENDING\n"));
   6.555 +    xi->device_state->suspend_resume_state_fdo = SR_STATE_SUSPENDING;
   6.556 +    KdPrint((__DRIVER_NAME "     Notifying event channel %d\n", xi->device_state->pdo_event_channel));
   6.557 +    xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
   6.558 +  }
   6.559 +
   6.560 +  FUNCTION_EXIT();
   6.561 +}
   6.562 +
   6.563 +// called at <= DISPATCH_LEVEL
   6.564 +VOID
   6.565 +XenNet_SendNetBufferLists(
   6.566 +  NDIS_HANDLE adapter_context,
   6.567 +  PNET_BUFFER_LIST nb_lists,
   6.568 +  NDIS_PORT_NUMBER port_number,
   6.569 +  ULONG send_flags)
   6.570 +{
   6.571 +  struct xennet_info *xi = adapter_context;
   6.572 +  PLIST_ENTRY nb_entry;
   6.573 +  KIRQL old_irql;
   6.574 +  PNET_BUFFER_LIST curr_nbl;
   6.575 +
   6.576 +  UNREFERENCED_PARAMETER(port_number);
   6.577 +  FUNCTION_ENTER();
   6.578 +
   6.579 +  if (xi->inactive)
   6.580 +  {
   6.581 +    curr_nbl = nb_lists;
   6.582 +    while(curr_nbl)
   6.583 +    {
   6.584 +      PNET_BUFFER_LIST next_nbl = NET_BUFFER_LIST_NEXT_NBL(curr_nbl);
   6.585 +      NET_BUFFER_LIST_NEXT_NBL(curr_nbl) = NULL;
   6.586 +      KdPrint((__DRIVER_NAME "     NBL %p\n", curr_nbl));
   6.587 +      curr_nbl->Status = NDIS_STATUS_FAILURE;
   6.588 +      NdisMSendNetBufferListsComplete(xi->adapter_handle, curr_nbl, (send_flags & NDIS_SEND_FLAGS_DISPATCH_LEVEL)?NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL:0);
   6.589 +      curr_nbl = next_nbl;
   6.590 +    }
   6.591 +  }
   6.592 +
   6.593 +  KeAcquireSpinLock(&xi->tx_lock, &old_irql);
   6.594 +  
   6.595 +  for (curr_nbl = nb_lists; curr_nbl; curr_nbl = NET_BUFFER_LIST_NEXT_NBL(curr_nbl))
   6.596 +  {
   6.597 +    PNET_BUFFER curr_nb;
   6.598 +    NBL_REF(curr_nbl) = 0;
   6.599 +    for (curr_nb = NET_BUFFER_LIST_FIRST_NB(curr_nbl); curr_nb; curr_nb = NET_BUFFER_NEXT_NB(curr_nb))
   6.600 +    {
   6.601 +      NB_NBL(curr_nb) = curr_nbl;
   6.602 +      nb_entry = &NB_LIST_ENTRY(curr_nb);
   6.603 +      InsertTailList(&xi->tx_waiting_pkt_list, nb_entry);
   6.604 +      NBL_REF(curr_nbl)++;
   6.605 +    }
   6.606 +  }
   6.607 +
   6.608 +  XenNet_SendQueuedPackets(xi);
   6.609 +
   6.610 +  KeReleaseSpinLock(&xi->tx_lock, old_irql);
   6.611 +  
   6.612 +  FUNCTION_EXIT();
   6.613 +}
   6.614 +
   6.615 +VOID
   6.616 +XenNet_CancelSend(NDIS_HANDLE adapter_context, PVOID cancel_id)
   6.617 +{
   6.618 +  UNREFERENCED_PARAMETER(adapter_context);
   6.619 +  UNREFERENCED_PARAMETER(cancel_id);
   6.620 +  FUNCTION_ENTER();
   6.621 +#if 0
   6.622 +  struct xennet_info *xi = MiniportAdapterContext;
   6.623 +  KIRQL old_irql;
   6.624 +  PLIST_ENTRY nb_entry;
   6.625 +  PNDIS_PACKET packet;
   6.626 +  PNDIS_PACKET head = NULL, tail = NULL;
   6.627 +  BOOLEAN result;
   6.628 +#endif
   6.629 +  FUNCTION_ENTER();
   6.630 +  
   6.631 +#if 0
   6.632 +  KeAcquireSpinLock(&xi->tx_lock, &old_irql);
   6.633 +
   6.634 +  nb_entry = xi->tx_waiting_pkt_list.Flink;
   6.635 +  while (nb_entry != &xi->tx_waiting_pkt_list)
   6.636 +  {
   6.637 +    packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
   6.638 +    entry = entry->Flink;
   6.639 +    if (NDIS_GET_PACKET_CANCEL_ID(packet) == CancelId)
   6.640 +    {
   6.641 +      KdPrint((__DRIVER_NAME "     Found packet to cancel %p\n", packet));
   6.642 +      result = RemoveEntryList((PLIST_ENTRY)&packet->MiniportReservedEx[sizeof(PVOID)]);
   6.643 +      ASSERT(result);
   6.644 +      *(PNDIS_PACKET *)&packet->MiniportReservedEx[0] = NULL;
   6.645 +      if (head)
   6.646 +        *(PNDIS_PACKET *)&tail->MiniportReservedEx[0] = packet;
   6.647 +      else
   6.648 +        head = packet;
   6.649 +      tail = packet;
   6.650 +    }
   6.651 +  }
   6.652 +
   6.653 +  KeReleaseSpinLock(&xi->tx_lock, old_irql);
   6.654 +
   6.655 +  while (head)
   6.656 +  {
   6.657 +    packet = (PNDIS_PACKET)head;
   6.658 +    head = *(PNDIS_PACKET *)&packet->MiniportReservedEx[0];
   6.659 +    KdPrint((__DRIVER_NAME "     NdisMSendComplete(%p)\n", packet));
   6.660 +    NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_REQUEST_ABORTED);
   6.661 +  }
   6.662 +#endif
   6.663 +  
   6.664 +  FUNCTION_EXIT();
   6.665 +}
   6.666 +
   6.667 +VOID
   6.668 +XenNet_TxResumeStart(xennet_info_t *xi)
   6.669 +{
   6.670 +  UNREFERENCED_PARAMETER(xi);
   6.671 +
   6.672 +  FUNCTION_ENTER();
   6.673 +  /* nothing to do here - all packets were already sent */
   6.674 +  FUNCTION_EXIT();
   6.675 +}
   6.676 +
   6.677 +VOID
   6.678 +XenNet_TxResumeEnd(xennet_info_t *xi)
   6.679 +{
   6.680 +  KIRQL old_irql;
   6.681 +
   6.682 +  FUNCTION_ENTER();
   6.683 +
   6.684 +  UNREFERENCED_PARAMETER(xi);
   6.685 +
   6.686 +  KeAcquireSpinLock(&xi->tx_lock, &old_irql);
   6.687 +  //XenNet_SendQueuedPackets(xi);
   6.688 +  KeReleaseSpinLock(&xi->tx_lock, old_irql);
   6.689 +
   6.690 +  FUNCTION_EXIT();
   6.691 +}
   6.692 +
   6.693 +BOOLEAN
   6.694 +XenNet_TxInit(xennet_info_t *xi)
   6.695 +{
   6.696 +  USHORT i;
   6.697 +  UNREFERENCED_PARAMETER(xi);
   6.698 +  
   6.699 +  KeInitializeSpinLock(&xi->tx_lock);
   6.700 +  InitializeListHead(&xi->tx_waiting_pkt_list);
   6.701 +
   6.702 +  KeInitializeEvent(&xi->tx_idle_event, SynchronizationEvent, FALSE);
   6.703 +  xi->tx_shutting_down = FALSE;
   6.704 +  xi->tx_outstanding = 0;
   6.705 +  xi->tx_ring_free = NET_TX_RING_SIZE;
   6.706 +  
   6.707 +  NdisInitializeNPagedLookasideList(&xi->tx_lookaside_list, NULL, NULL, 0,
   6.708 +    PAGE_SIZE, XENNET_POOL_TAG, 0);
   6.709 +
   6.710 +  xi->tx_id_free = 0;
   6.711 +  for (i = 0; i < NET_TX_RING_SIZE; i++)
   6.712 +  {
   6.713 +    xi->tx_shadows[i].gref = INVALID_GRANT_REF;
   6.714 +    xi->tx_shadows[i].cb = NULL;
   6.715 +    put_id_on_freelist(xi, i);
   6.716 +  }
   6.717 +
   6.718 +  return TRUE;
   6.719 +}
   6.720 +
   6.721 +/*
   6.722 +The ring is completely closed down now. We just need to empty anything left
   6.723 +on our freelists and harvest anything left on the rings.
   6.724 +*/
   6.725 +
   6.726 +BOOLEAN
   6.727 +XenNet_TxShutdown(xennet_info_t *xi)
   6.728 +{
   6.729 +  //PLIST_ENTRY entry;
   6.730 +  //PNDIS_PACKET packet;
   6.731 +  ////PMDL mdl;
   6.732 +  ////ULONG i;
   6.733 +  //KIRQL OldIrql;
   6.734 +  UNREFERENCED_PARAMETER(xi);
   6.735 +
   6.736 +  FUNCTION_ENTER();
   6.737 +
   6.738 +#if 0
   6.739 +  KeAcquireSpinLock(&xi->tx_lock, &OldIrql);
   6.740 +  xi->tx_shutting_down = TRUE;
   6.741 +  KeReleaseSpinLock(&xi->tx_lock, OldIrql);
   6.742 +
   6.743 +  while (xi->tx_outstanding)
   6.744 +  {
   6.745 +    KdPrint((__DRIVER_NAME "     Waiting for %d remaining packets to be sent\n", xi->tx_outstanding));
   6.746 +    KeWaitForSingleObject(&xi->tx_idle_event, Executive, KernelMode, FALSE, NULL);
   6.747 +  }
   6.748 +
   6.749 +#if (NTDDI_VERSION >= NTDDI_WINXP)
   6.750 +  KeFlushQueuedDpcs();
   6.751 +#endif
   6.752 +
   6.753 +  /* Free packets in tx queue */
   6.754 +  nb_entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
   6.755 +  while (nb_entry != &xi->tx_waiting_pkt_list)
   6.756 +  {
   6.757 +    packet = CONTAINING_RECORD(nb_entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
   6.758 +    NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_FAILURE);
   6.759 +    nb_entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
   6.760 +  }
   6.761 +
   6.762 +  NdisDeleteNPagedLookasideList(&xi->tx_lookaside_list);
   6.763 +#endif
   6.764 +
   6.765 +  FUNCTION_EXIT();
   6.766 +
   6.767 +  return TRUE;
   6.768 +}