From: Ben Chalmers Date: Tue, 28 May 2013 12:40:23 +0000 (+0100) Subject: [CP-4696] Git repository created for xennet X-Git-Tag: 8.1.0-rc1~60 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=4596bc734a20abcf21149e7891b070f81d337a88;p=pvdrivers%2Fwin%2Fxennet.git [CP-4696] Git repository created for xennet --- 4596bc734a20abcf21149e7891b070f81d337a88 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..00be666 --- /dev/null +++ b/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) Citrix Systems Inc. +All rights reserved. + +Redistribution and use in source and binary forms, +with or without modification, are permitted provided +that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + diff --git a/build.py b/build.py new file mode 100644 index 0000000..d457c76 --- /dev/null +++ b/build.py @@ -0,0 +1,301 @@ +#!python -u + +import os, sys +import datetime +import re +import glob +import tarfile +import subprocess + +def next_build_number(): + try: + file = open('.build_number', 'r') + build_number = file.read() + file.close() + except IOError: + build_number = '0' + + file = open('.build_number', 'w') + file.write(str(int(build_number) + 1)) + file.close() + + return build_number + + +def make_header(): + now = datetime.datetime.now() + + file = open('include\\version.h', 'w') + file.write('#define MAJOR_VERSION\t' + os.environ['MAJOR_VERSION'] + '\n') + file.write('#define MAJOR_VERSION_STR\t"' + os.environ['MAJOR_VERSION'] + '"\n') + file.write('\n') + + file.write('#define MINOR_VERSION\t' + os.environ['MINOR_VERSION'] + '\n') + file.write('#define MINOR_VERSION_STR\t"' + os.environ['MINOR_VERSION'] + '"\n') + file.write('\n') + + file.write('#define MICRO_VERSION\t' + os.environ['MICRO_VERSION'] + '\n') + file.write('#define MICRO_VERSION_STR\t"' + os.environ['MICRO_VERSION'] + '"\n') + file.write('\n') + + file.write('#define BUILD_NUMBER\t' + os.environ['BUILD_NUMBER'] + '\n') + file.write('#define BUILD_NUMBER_STR\t"' + os.environ['BUILD_NUMBER'] + '"\n') + file.write('\n') + + file.write('#define YEAR\t' + str(now.year) + '\n') + file.write('#define YEAR_STR\t"' + str(now.year) + '"\n') + + file.write('#define MONTH\t' + str(now.month) + '\n') + file.write('#define MONTH_STR\t"' + str(now.month) + '"\n') + + file.write('#define DAY\t' + str(now.day) + '\n') + file.write('#define DAY_STR\t"' + str(now.day) + '"\n') + + file.close() + + +def copy_inf(name): + src = open('src\\%s.inf' % name, 'r') + dst = open('proj\\%s.inf' % name, 'w') + + for line in src: + line = re.sub('@MAJOR_VERSION@', os.environ['MAJOR_VERSION'], line) + line = re.sub('@MINOR_VERSION@', os.environ['MINOR_VERSION'], line) + line = re.sub('@MICRO_VERSION@', os.environ['MICRO_VERSION'], line) + line = re.sub('@BUILD_NUMBER@', os.environ['BUILD_NUMBER'], line) + dst.write(line) + + dst.close() + src.close() + + +def get_expired_symbols(name, age = 30): + path = os.path.join(os.environ['SYMBOL_SERVER'], '000Admin\\history.txt') + + try: + file = open(path, 'r') + except IOError: + return [] + + threshold = datetime.datetime.utcnow() - datetime.timedelta(days = age) + + expired = [] + + for line in file: + item = line.split(',') + + if (re.match('add', item[1])): + id = item[0] + date = item[3].split('/') + time = item[4].split(':') + tag = item[5].strip('"') + + age = datetime.datetime(year = int(date[2]), + month = int(date[0]), + day = int(date[1]), + hour = int(time[0]), + minute = int(time[1]), + second = int(time[2])) + if (tag == name and age < threshold): + expired.append(id) + + elif (re.match('del', item[1])): + id = item[2].rstrip() + try: + expired.remove(id) + except ValueError: + pass + + file.close() + + return expired + + +def get_configuration(debug): + configuration = 'Windows Vista' + + if debug: + configuration += ' Debug' + else: + configuration += ' Release' + + return configuration + +def get_configuration_name(debug): + configuration = 'WindowsVista' + + if debug: + configuration += 'Debug' + else: + configuration += 'Release' + + return configuration + +def get_target_path(arch, debug): + configuration = get_configuration_name(debug) + + target = { 'x86': 'proj', 'x64': os.sep.join(['proj', 'x64']) } + target_path = os.sep.join([target[arch], configuration]) + + return target_path + + +def shell(command): + print(command) + sys.stdout.flush() + + pipe = os.popen(command, 'r', 1) + + for line in pipe: + print(line.rstrip()) + + return pipe.close() + + +class msbuild_failure(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + +def msbuild(name, arch, debug): + cwd = os.getcwd() + configuration = get_configuration(debug) + + os.environ['SOLUTION'] = name + + if arch == 'x86': + os.environ['PLATFORM'] = 'Win32' + elif arch == 'x64': + os.environ['PLATFORM'] = 'x64' + + os.environ['CONFIGURATION'] = configuration + os.environ['TARGET'] = 'Build' + + os.chdir('proj') + status = shell('msbuild.bat') + os.chdir(cwd) + + if (status != None): + raise msbuild_failure(configuration) + + +def symstore_del(name, age): + symstore_path = [os.environ['KIT'], 'Debuggers'] + if os.environ['PROCESSOR_ARCHITECTURE'] == 'x86': + symstore_path.append('x86') + else: + symstore_path.append('x64') + symstore_path.append('symstore.exe') + + symstore = os.path.join(*symstore_path) + + for id in get_expired_symbols(name, age): + command=['"' + symstore + '"'] + command.append('del') + command.append('/i') + command.append(str(id)) + command.append('/s') + command.append(os.environ['SYMBOL_SERVER']) + + shell(' '.join(command)) + +def symstore_add(name, arch, debug): + cwd = os.getcwd() + configuration = get_configuration_name(debug) + target_path = get_target_path(arch, debug) + + symstore_path = [os.environ['KIT'], 'Debuggers'] + if os.environ['PROCESSOR_ARCHITECTURE'] == 'x86': + symstore_path.append('x86') + else: + symstore_path.append('x64') + symstore_path.append('symstore.exe') + + symstore = os.path.join(*symstore_path) + + version = '.'.join([os.environ['MAJOR_VERSION'], + os.environ['MINOR_VERSION'], + os.environ['MICRO_VERSION'], + os.environ['BUILD_NUMBER']]) + + os.chdir(target_path) + command=['"' + symstore + '"'] + command.append('add') + command.append('/s') + command.append(os.environ['SYMBOL_SERVER']) + command.append('/r') + command.append('/f') + command.append('*.pdb') + command.append('/t') + command.append(name) + command.append('/v') + command.append(version) + + shell(' '.join(command)) + + os.chdir(cwd) + + +def callfnout(cmd): + print(cmd) + + sub = subprocess.Popen(cmd, stdout=subprocess.PIPE) + output = sub.communicate()[0] + ret = sub.returncode + + if ret != 0: + raise(Exception("Error %d in : %s" % (ret, cmd))) + + return output.decode('utf-8') + + +def archive(filename, files, tgz=False): + access='w' + if tgz: + access='w:gz' + tar = tarfile.open(filename, access) + for name in files : + try: + print('adding '+name) + tar.add(name) + except: + pass + tar.close() + + +if __name__ == '__main__': + debug = { 'checked': True, 'free': False } + driver = 'xennet' + + os.environ['MAJOR_VERSION'] = '7' + os.environ['MINOR_VERSION'] = '0' + os.environ['MICRO_VERSION'] = '0' + + if 'BUILD_NUMBER' not in os.environ.keys(): + os.environ['BUILD_NUMBER'] = next_build_number() + + print("BUILD_NUMBER=%s" % os.environ['BUILD_NUMBER']) + + if 'MERCURIAL_REVISION' in os.environ.keys(): + revision = open('revision', 'w') + print(os.environ['MERCURIAL_REVISION'], file=revision) + revision.close() + + make_header() + + copy_inf(driver) + + symstore_del(driver, 30) + + msbuild(driver, 'x86', debug[sys.argv[1]]) + msbuild(driver, 'x64', debug[sys.argv[1]]) + + symstore_add(driver, 'x86', debug[sys.argv[1]]) + symstore_add(driver, 'x64', debug[sys.argv[1]]) + + listfile = callfnout(['hg','manifest']) + archive(driver + '\\source.tgz', listfile.splitlines(), tgz=True) + archive(driver + '.tar', [driver,'revision']) + + diff --git a/clean.py b/clean.py new file mode 100644 index 0000000..4f77ead --- /dev/null +++ b/clean.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +import os, sys + +file = os.popen('hg status') + +for line in file: + item = line.split(' ') + if item[0] == '?': + path = ' '.join(item[1:]).rstrip() + print(path) + os.remove(path) + +file.close() diff --git a/include/ethernet.h b/include/ethernet.h new file mode 100644 index 0000000..9eb4b74 --- /dev/null +++ b/include/ethernet.h @@ -0,0 +1,135 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ETHERNET_H_ +#define _ETHERNET_H_ + +#pragma warning(push) +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union + +#pragma pack(push, 1) + +// Ethernet data structures +// +// NOTE: Fields are in network byte order + +#define ETHERNET_MTU 1500 +#define ETHERNET_MIN 60 +#define ETHERNET_MAX 1514 + +typedef struct _ETHERNET_ADDRESS { + UCHAR Byte[6]; +} ETHERNET_ADDRESS, *PETHERNET_ADDRESS; + +#define ETHERNET_ADDRESS_LENGTH (sizeof (ETHERNET_ADDRESS)) + +typedef enum _ETHERNET_ADDRESS_TYPE { + ETHERNET_ADDRESS_TYPE_INVALID = 0, + ETHERNET_ADDRESS_UNICAST, + ETHERNET_ADDRESS_MULTICAST, + ETHERNET_ADDRESS_BROADCAST, + ETHERNET_ADDRESS_TYPE_COUNT +} ETHERNET_ADDRESS_TYPE, *PETHERNET_ADDRESS_TYPE; + +#define GET_ETHERNET_ADDRESS_TYPE(_Address) \ + (((_Address)->Byte[0] & 0x01) ? \ + (((((_Address)->Byte[0] & ~0x03) == 0xFC) && \ + (((_Address)->Byte[1] ) == 0xFF) && \ + (((_Address)->Byte[2] ) == 0xFF) && \ + (((_Address)->Byte[3] ) == 0xFF) && \ + (((_Address)->Byte[4] ) == 0xFF) && \ + (((_Address)->Byte[5] ) == 0xFF) \ + ) ? \ + ETHERNET_ADDRESS_BROADCAST : \ + ETHERNET_ADDRESS_MULTICAST \ + ) : \ + ETHERNET_ADDRESS_UNICAST \ + ) + +typedef struct _ETHERNET_UNTAGGED_HEADER { + ETHERNET_ADDRESS DestinationAddress; + ETHERNET_ADDRESS SourceAddress; + USHORT TypeOrLength; + +#define ETHERTYPE_IPV4 0x0800 +#define ETHERTYPE_IPV6 0x86DD +#define ETHERTYPE_ARP 0x0806 +#define ETHERTYPE_RARP 0x0835 +#define ETHERTYPE_TPID 0x8100 +#define ETHERTYPE_LOOPBACK 0x9000 + +} ETHERNET_UNTAGGED_HEADER, *PETHERNET_UNTAGGED_HEADER; + +typedef struct _ETHERNET_TAG { + USHORT ProtocolID; // == ETHERTYPE_TPID + USHORT ControlInformation; + +#define PACK_TAG_CONTROL_INFORMATION(_ControlInformation, _UserPriority, _CanonicalFormatId, _VlanId) \ + do { \ + (_ControlInformation) = (USHORT)(_VlanId) & 0x0FFF; \ + (_ControlInformation) |= (USHORT)((_CanonicalFormatId) << 12) & 0x1000; \ + (_ControlInformation) |= (USHORT)((_UserPriority) << 13) & 0xE000; \ + } while (FALSE) + +#define UNPACK_TAG_CONTROL_INFORMATION(_ControlInformation, _UserPriority, _CanonicalFormatId, _VlanId) \ + do { \ + (_VlanId) = (_ControlInformation) & 0xFFF; \ + (_CanonicalFormatId) = ((_ControlInformation) & 0x1000) >> 12; \ + (_UserPriority) = ((_ControlInformation) & 0xE000) >> 13; \ + } while (FALSE) + +} ETHERNET_TAG, *PETHERNET_TAG; + +typedef struct _ETHERNET_TAGGED_HEADER { + ETHERNET_ADDRESS DestinationAddress; + ETHERNET_ADDRESS SourceAddress; + ETHERNET_TAG Tag; + USHORT TypeOrLength; +} ETHERNET_TAGGED_HEADER, *PETHERNET_TAGGED_HEADER; + +typedef union _ETHERNET_HEADER { + ETHERNET_UNTAGGED_HEADER Untagged; + ETHERNET_TAGGED_HEADER Tagged; +} ETHERNET_HEADER, *PETHERNET_HEADER; + +#define ETHERNET_HEADER_IS_TAGGED(_Header) \ + ((_Header)->Untagged.TypeOrLength == NTOHS(ETHERTYPE_TPID)) + +#define ETHERNET_HEADER_LENGTH(_Header) \ + ETHERNET_HEADER_IS_TAGGED(_Header) ? \ + sizeof (ETHERNET_TAGGED_HEADER) : \ + sizeof (ETHERNET_UNTAGGEDHEADER)) + +#pragma pack(pop) + +#pragma warning(pop) + +#endif // _ETHERNET_H diff --git a/include/tcpip.h b/include/tcpip.h new file mode 100644 index 0000000..7d1dade --- /dev/null +++ b/include/tcpip.h @@ -0,0 +1,262 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ethernet.h" + +#ifndef _TCPIP_H +#define _TCPIP_H + +#pragma warning(push) +#pragma warning(disable:4214) // nonstandard extension used : bit field types other than int +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union + +#define NTOHS(_Value) _byteswap_ushort(_Value) +#define HTONS(_Value) _byteswap_ushort(_Value) +#define NTOHL(_Value) _byteswap_ulong(_Value) +#define HTONL(_Value) _byteswap_ulong(_Value) + +#pragma pack(push, 1) + +// TCP/IP data structures +// +// NOTE: Fields are in network byte order + +// IPv4 + +typedef struct _IPV4_ADDRESS { + union { + ULONG Dword[1]; + UCHAR Byte[4]; + }; +} IPV4_ADDRESS, *PIPV4_ADDRESS; + +#define IPV4_ADDRESS_LENGTH (sizeof (IPV4_ADDRESS)) + +typedef struct _IPV4_HEADER { + UCHAR HeaderLength:4; + UCHAR Version:4; + UCHAR TypeOfService; + USHORT PacketLength; + USHORT PacketID; + USHORT FragmentOffsetAndFlags; + +#define IPV4_FRAGMENT_OFFSET(_FragmentOffsetAndFlags) \ + ((_FragmentOffsetAndFlags) & 0x1fff) +#define IPV4_DONT_FRAGMENT(_FragmentOffsetAndFlags) \ + ((_FragmentOffsetAndFlags) & 0x4000) +#define IPV4_MORE_FRAGMENTS(_FragmentOffsetAndFlags) \ + ((_FragmentOffsetAndFlags) & 0x2000) +#define IPV4_IS_A_FRAGMENT(_FragmentOffsetAndFlags) \ + ((_FragmentOffsetAndFlags) & 0x3fff) + + UCHAR TimeToLive; + UCHAR Protocol; + USHORT Checksum; + IPV4_ADDRESS SourceAddress; + IPV4_ADDRESS DestinationAddress; +} IPV4_HEADER, *PIPV4_HEADER; + +#define IPV4_HEADER_LENGTH(_Header) \ + (((ULONG)((_Header)->HeaderLength)) << 2) + +#define MAXIMUM_IPV4_HEADER_LENGTH \ + (0xF << 2) + +// IPv6 + +typedef struct _IPV6_ADDRESS { + union { + ULONG Dword[4]; + UCHAR Byte[16]; + }; +} IPV6_ADDRESS, *PIPV6_ADDRESS; + +#define IPV6_ADDRESS_LENGTH (sizeof (IPV6_ADDRESS)) + +typedef struct _IPV6_HEADER { + union { + struct { + UCHAR __Pad:4; + UCHAR Version:4; + }; + ULONG VCF; + }; + USHORT PayloadLength; + UCHAR NextHeader; + UCHAR HopLimit; + IPV6_ADDRESS SourceAddress; + IPV6_ADDRESS DestinationAddress; +} IPV6_HEADER, *PIPV6_HEADER; + +#define IPV6_HEADER_LENGTH(_Header) \ + (ULONG)(sizeof (IPV6_HEADER)) + +// IP + +typedef union _IP_ADDRESS { + IPV4_ADDRESS Version4; + IPV6_ADDRESS Version6; +} IP_ADDRESS, *PIP_ADDRESS; + +typedef union _IP_HEADER { + struct { + UCHAR __Pad:4; + UCHAR Version:4; + }; + IPV4_HEADER Version4; + IPV6_HEADER Version6; +} IP_HEADER, *PIP_HEADER; + +#define IP_HEADER_LENGTH(_Header) \ + (((_Header)->Version == 4) ? \ + IPV4_HEADER_LENGTH(&(_Header)->Version4) : \ + IPV6_HEADER_LENGTH(&(_Header)->Version6)) + +#define IPPROTO_HOP_OPTIONS 0 +#define IPPROTO_DST_OPTIONS 60 +#define IPPROTO_ROUTING 43 + +// Options + +typedef struct _IPV6_OPTION_HEADER { + UCHAR NextHeader; + UCHAR PayloadLength; +} IPV6_OPTION_HEADER, *PIPV6_OPTION_HEADER; + +#define IPV6_OPTION_HEADER_LENGTH(_Header) \ + (ULONG)(sizeof (IPV6_OPTION_HEADER) + (_Header)->PayloadLength) + +#define IPPROTO_TCP 6 + +// TCP + +typedef struct _TCP_HEADER { + USHORT SourcePort; + USHORT DestinationPort; + ULONG Seq; + ULONG Ack; + UCHAR Reserved:4; + UCHAR HeaderLength:4; + UCHAR Flags; + +#define TCP_FIN 0x01 +#define TCP_SYN 0x02 +#define TCP_RST 0x04 +#define TCP_PSH 0x08 +#define TCP_ACK 0x10 +#define TCP_URG 0x20 +#define TCP_ECE 0x40 +#define TCP_CWR 0x80 + + USHORT Window; + USHORT Checksum; + USHORT UrgentPointer; +} TCP_HEADER, *PTCP_HEADER; + +#define TCP_HEADER_LENGTH(_Header) \ + (((ULONG)((_Header)->HeaderLength)) << 2) + +#define MAXIMUM_TCP_HEADER_LENGTH \ + (0xF << 2) + +#define TCPOPT_NOP 1 +#define TCPOPT_TIMESTAMP 8 +#define TCPOLEN_TIMESTAMP 10 + +#define IPPROTO_UDP 17 + +// UDP + +typedef struct _UDP_HEADER { + USHORT SourcePort; + USHORT DestinationPort; + USHORT PacketLength; + USHORT Checksum; +} UDP_HEADER, *PUDP_HEADER; + +#define UDP_HEADER_LENGTH(_Header) \ + (ULONG)(sizeof (UDP_HEADER)) + +#define IPPROTO_NONE 59 + +// Checksum + +typedef struct _IPV4_PSEUDO_HEADER { + IPV4_ADDRESS SourceAddress; + IPV4_ADDRESS DestinationAddress; + UCHAR Zero; + UCHAR Protocol; // TCP or UDP + USHORT Length; // Including TCP/UDP header +} IPV4_PSEUDO_HEADER, *PIPV4_PSEUDO_HEADER; + +typedef struct _IPV6_PSEUDO_HEADER { + IPV6_ADDRESS SourceAddress; + IPV6_ADDRESS DestinationAddress; + USHORT Length; // Including TCP/UDP header + UCHAR Zero[3]; + UCHAR NextHeader; // TCP or UDP +} IPV6_PSEUDO_HEADER, *PIPV6_PSEUDO_HEADER; + +typedef union _PSEUDO_HEADER { + IPV4_PSEUDO_HEADER Version4; + IPV6_PSEUDO_HEADER Version6; +} PSEUDO_HEADER, *PPSEUDO_HEADER; + +// ARP + +typedef struct _ARP_HEADER { + USHORT HardwareType; + +#define HARDWARE_ETHER 1 + + USHORT ProtocolType; + +#define PROTOCOL_IPV4 ETHERTYPE_IPV4 + + UCHAR HardwareAddressLength; + UCHAR ProtocolAddressLength; + USHORT Operation; + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 +#define RARP_REQUEST 3 +#define RARP_REPLY 4 + +} ARP_HEADER, *PARP_HEADER; + +#define ARP_HEADER_LENGTH(_Header) \ + (ULONG)(sizeof (ARP_HEADER)) + +#pragma pack(pop) + +#pragma warning(pop) + +#endif //_TCPIP_H diff --git a/include/util.h b/include/util.h new file mode 100644 index 0000000..9b338b6 --- /dev/null +++ b/include/util.h @@ -0,0 +1,113 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _UTIL_H +#define _UTIL_H + +#include + +#define P2ROUNDUP(_x, _a) \ + (-(-(_x) & -(_a))) + +static FORCEINLINE LONG +__ffs( + IN unsigned long long mask + ) +{ + unsigned char *array = (unsigned char *)&mask; + unsigned int byte; + unsigned int bit; + unsigned char val; + + val = 0; + + byte = 0; + while (byte < 8) { + val = array[byte]; + + if (val != 0) + break; + + byte++; + } + if (byte == 8) + return -1; + + bit = 0; + while (bit < 8) { + if (val & 0x01) + break; + + val >>= 1; + bit++; + } + + return (byte * 8) + bit; +} + +#define __ffu(_mask) \ + __ffs(~(_mask)) + +static FORCEINLINE LONG +__InterlockedAdd( + IN LONG *Value, + IN LONG Delta + ) +{ + LONG New; + LONG Old; + + do { + Old = *Value; + New = Old + Delta; + } while (InterlockedCompareExchange(Value, New, Old) != Old); + + return New; +} + +static FORCEINLINE LONG +__InterlockedSubtract( + IN LONG *Value, + IN LONG Delta + ) +{ + LONG New; + LONG Old; + + do { + Old = *Value; + New = Old - Delta; + } while (InterlockedCompareExchange(Value, New, Old) != Old); + + return New; +} + +#endif // _UTIL_H diff --git a/include/vif_interface.h b/include/vif_interface.h new file mode 100644 index 0000000..ae5d6b4 --- /dev/null +++ b/include/vif_interface.h @@ -0,0 +1,418 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _XENVIF_VIF_INTERFACE_H +#define _XENVIF_VIF_INTERFACE_H + +#include +#include + +#define MAX_SKB_FRAGS ((65536/PAGE_SIZE) + 2) + +typedef UCHAR XENVIF_PACKET_STATUS, *PXENVIF_PACKET_STATUS; + +#define PACKET_STATUS_INVALID 0 +#define PACKET_PENDING 1 +#define PACKET_OK 2 +#define PACKET_DROPPED 3 +#define PACKET_ERROR 4 + +typedef struct _XENVIF_PACKET_HEADER { + ULONG Offset; + ULONG Length; +} XENVIF_PACKET_HEADER, *PXENVIF_PACKET_HEADER; + +typedef struct _XENVIF_PACKET_INFO { + XENVIF_PACKET_HEADER EthernetHeader; + XENVIF_PACKET_HEADER LLCSnapHeader; + XENVIF_PACKET_HEADER IpHeader; + XENVIF_PACKET_HEADER IpOptions; + XENVIF_PACKET_HEADER TcpHeader; + XENVIF_PACKET_HEADER TcpOptions; + XENVIF_PACKET_HEADER UdpHeader; + ULONG Length; +} XENVIF_PACKET_INFO, *PXENVIF_PACKET_INFO; + +#pragma warning(push) +#pragma warning(disable:4214) // nonstandard extension used : bit field types other than int +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union + +typedef struct _XENVIF_CHECKSUM_FLAGS { + struct { + ULONG IpChecksumSucceeded:1; + ULONG IpChecksumFailed:1; + ULONG IpChecksumPresent:1; + ULONG TcpChecksumSucceeded:1; + ULONG TcpChecksumFailed:1; + ULONG TcpChecksumPresent:1; + ULONG UdpChecksumSucceeded:1; + ULONG UdpChecksumFailed:1; + ULONG UdpChecksumPresent:1; + ULONG Reserved:23; + }; +} XENVIF_CHECKSUM_FLAGS, *PXENVIF_CHECKSUM_FLAGS; + +#pragma warning(pop) + +typedef struct _XENVIF_RECEIVER_PACKET { + LIST_ENTRY ListEntry; + ULONG Offset; + ULONG Length; + XENVIF_PACKET_INFO Info; + XENVIF_CHECKSUM_FLAGS Flags; + USHORT TagControlInformation; + USHORT MaximumSegmentSize; + PVOID Cookie; + MDL Mdl; + PFN_NUMBER __Pfn; +} XENVIF_RECEIVER_PACKET, *PXENVIF_RECEIVER_PACKET; + +typedef struct _XENVIF_RECEIVER_PACKET_STATISTICS { + ULONGLONG Drop; + ULONGLONG BackendError; + ULONGLONG FrontendError; + ULONGLONG Unicast; + ULONGLONG UnicastBytes; + ULONGLONG Multicast; + ULONGLONG MulticastBytes; + ULONGLONG Broadcast; + ULONGLONG BroadcastBytes; +} XENVIF_RECEIVER_PACKET_STATISTICS, *PXENVIF_RECEIVER_PACKET_STATISTICS; + +#pragma warning(push) +#pragma warning(disable:4214) // nonstandard extension used : bit field types other than int +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union + +typedef struct _XENVIF_OFFLOAD_OPTIONS { + union { + struct { + USHORT OffloadTagManipulation:1; + USHORT OffloadIpVersion4LargePacket:1; + USHORT OffloadIpVersion4HeaderChecksum:1; + USHORT OffloadIpVersion4TcpChecksum:1; + USHORT OffloadIpVersion4UdpChecksum:1; + USHORT OffloadIpVersion6LargePacket:1; + USHORT OffloadIpVersion6TcpChecksum:1; + USHORT OffloadIpVersion6UdpChecksum:1; + USHORT NeedChecksumValue:1; + USHORT NeedLargePacketSplit:1; + USHORT Reserved:6; + }; + + USHORT Value; + }; +} XENVIF_OFFLOAD_OPTIONS, *PXENVIF_OFFLOAD_OPTIONS; + +#pragma warning(pop) + +typedef struct _XENVIF_TRANSMITTER_PACKET XENVIF_TRANSMITTER_PACKET, *PXENVIF_TRANSMITTER_PACKET; + +// To fit into the reserved space in NDIS_PACKET and NET_BUFFER structures the XENVIF_TRANSMITTER_PACKET +// structure must be at most the size of 3 pointer types. + +#pragma pack(push, 1) +typedef struct _XENVIF_SEND_INFO { + XENVIF_OFFLOAD_OPTIONS OffloadOptions; + USHORT MaximumSegmentSize; // Only used if OffloadOptions.OffloadIpVersion[4|6}LargePacket is set + USHORT TagControlInformation; // Only used if OffloadOptions.OffloadTagManipulation is set +} XENVIF_SEND_INFO, *PXENVIF_SEND_INFO; + +typedef struct _XENVIF_COMPLETION_INFO { + UCHAR Type; + XENVIF_PACKET_STATUS Status; + USHORT PacketLength; + USHORT PayloadLength; +} XENVIF_COMPLETION_INFO, *PXENVIF_COMPLETION_INFO; + +#pragma warning(push) +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union + +struct _XENVIF_TRANSMITTER_PACKET { + PXENVIF_TRANSMITTER_PACKET Next; + union { + XENVIF_SEND_INFO Send; + XENVIF_COMPLETION_INFO Completion; + }; +}; + +#pragma warning(pop) + +#pragma pack(pop) + +C_ASSERT(sizeof (XENVIF_TRANSMITTER_PACKET) <= (3 * sizeof (PVOID))); + +// Because we're so tight on space in the XENVIF_TRANSMITTER_PACKET structure, certain packet metadata +// needs to be accessed via magic offsets +typedef struct _XENVIF_TRANSMITTER_PACKET_METADATA { + LONG_PTR OffsetOffset; + LONG_PTR LengthOffset; + LONG_PTR MdlOffset; +} XENVIF_TRANSMITTER_PACKET_METADATA, *PXENVIF_TRANSMITTER_PACKET_METADATA; + +typedef struct _XENVIF_TRANSMITTER_PACKET_STATISTICS { + ULONG Drop; + ULONG BackendError; + ULONG FrontendError; + ULONG Unicast; + ULONG UnicastBytes; + ULONG Multicast; + ULONG MulticastBytes; + ULONG Broadcast; + ULONG BroadcastBytes; +} XENVIF_TRANSMITTER_PACKET_STATISTICS, *PXENVIF_TRANSMITTER_PACKET_STATISTICS; + +typedef struct _XENVIF_PACKET_STATISTICS { + XENVIF_RECEIVER_PACKET_STATISTICS Receiver; + XENVIF_TRANSMITTER_PACKET_STATISTICS Transmitter; +} XENVIF_PACKET_STATISTICS, *PXENVIF_PACKET_STATISTICS; + +#define MAXIMUM_MULTICAST_ADDRESS_COUNT 32 // Minimum number to pass WHQL + +typedef enum _XENVIF_MAC_FILTER_LEVEL { + MAC_FILTER_NONE = 0, + MAC_FILTER_MATCHING = 1, + MAC_FILTER_ALL = 2 +} XENVIF_MAC_FILTER_LEVEL, *PXENVIF_MAC_FILTER_LEVEL; + +typedef struct _XENVIF_MEDIA_STATE { + NET_IF_MEDIA_CONNECT_STATE MediaConnectState; + ULONG64 LinkSpeed; + NET_IF_MEDIA_DUPLEX_STATE MediaDuplexState; +} XENVIF_MEDIA_STATE, *PXENVIF_MEDIA_STATE; + +typedef enum XENVIF_CALLBACK_TYPE { + XENVIF_CALLBACK_TYPE_INVALID = 0, + XENVIF_CALLBACK_COMPLETE_PACKETS, + XENVIF_CALLBACK_RECEIVE_PACKETS, + XENVIF_CALLBACK_MEDIA_STATE_CHANGE +} XENVIF_CALLBACK_TYPE, *PXENVIF_CALLBACK_TYPE; + +#define DEFINE_VIF_OPERATIONS \ + VIF_OPERATION(VOID, \ + Acquire, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + Release, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context \ + ) \ + ) \ + VIF_OPERATION(NTSTATUS, \ + Enable, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + IN VOID (*Function)(PVOID, XENVIF_CALLBACK_TYPE, ...), \ + IN PVOID Argument OPTIONAL \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + Disable, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + QueryPacketStatistics, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + OUT PXENVIF_PACKET_STATISTICS Statistics \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + UpdatePacketMetadata, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + IN PXENVIF_TRANSMITTER_PACKET_METADATA Metadata \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + ReturnPacket, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + IN PXENVIF_RECEIVER_PACKET Packet \ + ) \ + ) \ + VIF_OPERATION(NTSTATUS, \ + QueuePackets, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + IN PXENVIF_TRANSMITTER_PACKET HeadPacket \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + QueryOffloadOptions, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + OUT PXENVIF_OFFLOAD_OPTIONS Options \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + UpdateOffloadOptions, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + IN XENVIF_OFFLOAD_OPTIONS Options \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + QueryLargePacketSize, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + IN UCHAR Version, \ + OUT PULONG Size \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + QueryMediaState, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + OUT PNET_IF_MEDIA_CONNECT_STATE MediaConnectState OPTIONAL, \ + OUT PULONG64 LinkSpeed OPTIONAL, \ + OUT PNET_IF_MEDIA_DUPLEX_STATE MediaDuplexState OPTIONAL \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + QueryMaximumFrameSize, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + OUT PULONG Size \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + QueryPermanentAddress, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + OUT PETHERNET_ADDRESS Address \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + QueryCurrentAddress, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + OUT PETHERNET_ADDRESS Address \ + ) \ + ) \ + VIF_OPERATION(NTSTATUS, \ + UpdateCurrentAddress, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + IN PETHERNET_ADDRESS Address \ + ) \ + ) \ + VIF_OPERATION(NTSTATUS, \ + QueryMulticastAddresses, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + OUT PETHERNET_ADDRESS Address OPTIONAL, \ + OUT PULONG Count \ + ) \ + ) \ + VIF_OPERATION(NTSTATUS, \ + UpdateMulticastAddresses, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + IN PETHERNET_ADDRESS Address, \ + IN ULONG Count \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + QueryFilterLevel, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + IN ETHERNET_ADDRESS_TYPE Type, \ + OUT PXENVIF_MAC_FILTER_LEVEL Level \ + ) \ + ) \ + VIF_OPERATION(NTSTATUS, \ + UpdateFilterLevel, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + IN ETHERNET_ADDRESS_TYPE Type, \ + IN XENVIF_MAC_FILTER_LEVEL Level \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + QueryReceiverRingSize, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + OUT PULONG Size \ + ) \ + ) \ + VIF_OPERATION(VOID, \ + QueryTransmitterRingSize, \ + ( \ + IN PXENVIF_VIF_CONTEXT Context, \ + OUT PULONG Size \ + ) \ + ) + +typedef struct _XENVIF_VIF_CONTEXT XENVIF_VIF_CONTEXT, *PXENVIF_VIF_CONTEXT; + +#define VIF_OPERATION(_Type, _Name, _Arguments) \ + _Type (*VIF_ ## _Name) _Arguments; + +typedef struct _XENVIF_VIF_OPERATIONS { + DEFINE_VIF_OPERATIONS +} XENVIF_VIF_OPERATIONS, *PXENVIF_VIF_OPERATIONS; + +#undef VIF_OPERATION + +typedef struct _XENVIF_VIF_INTERFACE XENVIF_VIF_INTERFACE, *PXENVIF_VIF_INTERFACE; + +// {BAA55367-D5CD-4fab-8A2D-BB40476795C3} +DEFINE_GUID(GUID_VIF_INTERFACE, + 0xbaa55367, + 0xd5cd, + 0x4fab, + 0x8a, + 0x2d, + 0xbb, + 0x40, + 0x47, + 0x67, + 0x95, + 0xc3); + +#define VIF_INTERFACE_VERSION 12 + +#define VIF_OPERATIONS(_Interface) \ + (PXENVIF_VIF_OPERATIONS *)((ULONG_PTR)(_Interface)) + +#define VIF_CONTEXT(_Interface) \ + (PXENVIF_VIF_CONTEXT *)((ULONG_PTR)(_Interface) + sizeof (PVOID)) + +#define VIF(_Operation, _Interface, ...) \ + (*VIF_OPERATIONS(_Interface))->VIF_ ## _Operation((*VIF_CONTEXT(_Interface)), __VA_ARGS__) + +#endif // _XENVIF_INTERFACE_H + diff --git a/kdfiles.py b/kdfiles.py new file mode 100644 index 0000000..7aaa586 --- /dev/null +++ b/kdfiles.py @@ -0,0 +1,26 @@ +#!python -u + +import os, sys +import subprocess +import glob +from pprint import pprint + +def regenerate_kdfiles(filename, arch, pkg, source): + cwd = os.getcwd() + file = open(filename, 'w') + os.chdir(pkg + '/' + arch) + drivers = glob.glob('*.sys') + pprint(drivers) + for driver in drivers: + file.write("map\n") + file.write('\SystemRoot\System32\drivers\\' + driver + '\n') + file.write(source + '\\' + pkg + '\\' + arch + '\\' + driver + '\n') + file.write('\n') + os.chdir(cwd) + file.close() + +if __name__ == '__main__': + pkg = 'xennet' + source = os.getcwd() + regenerate_kdfiles('kdfiles32.txt', 'x86', pkg, source) + regenerate_kdfiles('kdfiles64.txt', 'x64', pkg, source) diff --git a/proj/msbuild.bat b/proj/msbuild.bat new file mode 100644 index 0000000..0d3f6cb --- /dev/null +++ b/proj/msbuild.bat @@ -0,0 +1,7 @@ +call "%VS%\VC\vcvarsall.bat" x86 +msbuild.exe /m:4 /p:Configuration="%CONFIGURATION%" /p:Platform="%PLATFORM%" /t:"%TARGET%" /p:SignMode="ProductionSign" %SOLUTION%.sln +if errorlevel 1 goto error +exit 0 + +:error +exit 1 diff --git a/proj/package/package.vcxproj b/proj/package/package.vcxproj new file mode 100644 index 0000000..faddfee --- /dev/null +++ b/proj/package/package.vcxproj @@ -0,0 +1,161 @@ + + + + + Windows Developer Preview Debug + Win32 + + + Windows Developer Preview Release + Win32 + + + Windows 7 Debug + Win32 + + + Windows 7 Release + Win32 + + + Windows Vista Debug + Win32 + + + Windows Vista Release + Win32 + + + Windows Developer Preview Debug + x64 + + + Windows Developer Preview Release + x64 + + + Windows 7 Debug + x64 + + + Windows 7 Release + x64 + + + Windows Vista Debug + x64 + + + Windows Vista Release + x64 + + + + {445FD18F-97E3-4E5D-825F-151026242C05} + v4.5 + 11.0 + + + WindowsKernelModeDriver8.0 + Utility + Package + Windows Developer Preview Debug + true + + + + Windows8 + true + + + Windows8 + false + + + Windows7 + true + + + Windows7 + false + + + Vista + true + + + Vista + false + + + Windows8 + true + + + Windows8 + false + + + Windows7 + true + + + Windows7 + false + + + Vista + true + + + Vista + false + + + + + + + + + + true + Vista_$(DDKPlatform);7_$(DDKPlatform);Server2008_$(DDKPlatform);Server2008R2_$(DDKPlatform) + Vista_$(DDKPlatform);7_$(DDKPlatform);Server2008_$(DDKPlatform) + + + DbgengKernelDebugger + False + False + None + + + + + + %PathToInf% + False + False + True + + 133563 + ..\..\xennet\$(DDKPlatform) + + + + {97D9942B-5EA3-488C-B512-C96E5D077F8E} + + + + + {3EDD837A-C1BE-47D4-9603-16B61353670B} + + + + + + + + + + \ No newline at end of file diff --git a/proj/package/package.vcxproj.user b/proj/package/package.vcxproj.user new file mode 100644 index 0000000..7dea6a2 --- /dev/null +++ b/proj/package/package.vcxproj.user @@ -0,0 +1,8 @@ + + + + ProductionSign + CN="Citrix Systems, Inc.", OU=Digital ID Class 3 - Microsoft Software Validation v2, O="Citrix Systems, Inc.", L=Santa Clara, S=California, C=US | 9505C081954CC0A3E8B904458ACACD72EABD98B5 + http://timestamp.verisign.com/scripts/timstamp.dll + + \ No newline at end of file diff --git a/proj/xennet.sln b/proj/xennet.sln new file mode 100644 index 0000000..93bb6df --- /dev/null +++ b/proj/xennet.sln @@ -0,0 +1,140 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 11 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xennet", "xennet\xennet.vcxproj", "{97D9942B-5EA3-488C-B512-C96E5D077F8E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xennet_coinst", "xennet_coinst\xennet_coinst.vcxproj", "{3EDD837A-C1BE-47D4-9603-16B61353670B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "package\package.vcxproj", "{445FD18F-97E3-4E5D-825F-151026242C05}" + ProjectSection(ProjectDependencies) = postProject + {3EDD837A-C1BE-47D4-9603-16B61353670B} = {3EDD837A-C1BE-47D4-9603-16B61353670B} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Windows 7 Debug|Win32 = Windows 7 Debug|Win32 + Windows 7 Debug|x64 = Windows 7 Debug|x64 + Windows 7 Release|Win32 = Windows 7 Release|Win32 + Windows 7 Release|x64 = Windows 7 Release|x64 + Windows Developer Preview Debug|Win32 = Windows Developer Preview Debug|Win32 + Windows Developer Preview Debug|x64 = Windows Developer Preview Debug|x64 + Windows Developer Preview Release|Win32 = Windows Developer Preview Release|Win32 + Windows Developer Preview Release|x64 = Windows Developer Preview Release|x64 + Windows Vista Debug|Win32 = Windows Vista Debug|Win32 + Windows Vista Debug|x64 = Windows Vista Debug|x64 + Windows Vista Release|Win32 = Windows Vista Release|Win32 + Windows Vista Release|x64 = Windows Vista Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Debug|Win32.ActiveCfg = Windows 7 Debug|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Debug|Win32.Build.0 = Windows 7 Debug|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Debug|Win32.Deploy.0 = Windows 7 Debug|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Debug|x64.ActiveCfg = Windows 7 Debug|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Debug|x64.Build.0 = Windows 7 Debug|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Debug|x64.Deploy.0 = Windows 7 Debug|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Release|Win32.ActiveCfg = Windows 7 Release|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Release|Win32.Build.0 = Windows 7 Release|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Release|Win32.Deploy.0 = Windows 7 Release|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Release|x64.ActiveCfg = Windows 7 Release|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Release|x64.Build.0 = Windows 7 Release|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows 7 Release|x64.Deploy.0 = Windows 7 Release|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Debug|Win32.ActiveCfg = Windows Developer Preview Debug|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Debug|Win32.Build.0 = Windows Developer Preview Debug|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Debug|Win32.Deploy.0 = Windows Developer Preview Debug|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Debug|x64.ActiveCfg = Windows Developer Preview Debug|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Debug|x64.Build.0 = Windows Developer Preview Debug|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Debug|x64.Deploy.0 = Windows Developer Preview Debug|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Release|Win32.ActiveCfg = Windows Developer Preview Release|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Release|Win32.Build.0 = Windows Developer Preview Release|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Release|Win32.Deploy.0 = Windows Developer Preview Release|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Release|x64.ActiveCfg = Windows Developer Preview Release|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Release|x64.Build.0 = Windows Developer Preview Release|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Developer Preview Release|x64.Deploy.0 = Windows Developer Preview Release|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Debug|Win32.ActiveCfg = Windows Vista Debug|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Debug|Win32.Build.0 = Windows Vista Debug|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Debug|Win32.Deploy.0 = Windows Vista Debug|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Debug|x64.ActiveCfg = Windows Vista Debug|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Debug|x64.Build.0 = Windows Vista Debug|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Debug|x64.Deploy.0 = Windows Vista Debug|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Release|Win32.ActiveCfg = Windows Vista Release|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Release|Win32.Build.0 = Windows Vista Release|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Release|Win32.Deploy.0 = Windows Vista Release|Win32 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Release|x64.ActiveCfg = Windows Vista Release|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Release|x64.Build.0 = Windows Vista Release|x64 + {3EDD837A-C1BE-47D4-9603-16B61353670B}.Windows Vista Release|x64.Deploy.0 = Windows Vista Release|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Debug|Win32.ActiveCfg = Windows 7 Debug|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Debug|Win32.Build.0 = Windows 7 Debug|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Debug|Win32.Deploy.0 = Windows 7 Debug|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Debug|x64.ActiveCfg = Windows 7 Debug|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Debug|x64.Build.0 = Windows 7 Debug|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Debug|x64.Deploy.0 = Windows 7 Debug|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Release|Win32.ActiveCfg = Windows 7 Release|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Release|Win32.Build.0 = Windows 7 Release|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Release|Win32.Deploy.0 = Windows 7 Release|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Release|x64.ActiveCfg = Windows 7 Release|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Release|x64.Build.0 = Windows 7 Release|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows 7 Release|x64.Deploy.0 = Windows 7 Release|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Debug|Win32.ActiveCfg = Windows Developer Preview Debug|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Debug|Win32.Build.0 = Windows Developer Preview Debug|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Debug|Win32.Deploy.0 = Windows Developer Preview Debug|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Debug|x64.ActiveCfg = Windows Developer Preview Debug|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Debug|x64.Build.0 = Windows Developer Preview Debug|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Debug|x64.Deploy.0 = Windows Developer Preview Debug|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Release|Win32.ActiveCfg = Windows Developer Preview Release|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Release|Win32.Build.0 = Windows Developer Preview Release|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Release|Win32.Deploy.0 = Windows Developer Preview Release|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Release|x64.ActiveCfg = Windows Developer Preview Release|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Release|x64.Build.0 = Windows Developer Preview Release|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Developer Preview Release|x64.Deploy.0 = Windows Developer Preview Release|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Debug|Win32.ActiveCfg = Windows Vista Debug|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Debug|Win32.Build.0 = Windows Vista Debug|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Debug|Win32.Deploy.0 = Windows Vista Debug|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Debug|x64.ActiveCfg = Windows Vista Debug|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Debug|x64.Build.0 = Windows Vista Debug|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Debug|x64.Deploy.0 = Windows Vista Debug|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Release|Win32.ActiveCfg = Windows Vista Release|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Release|Win32.Build.0 = Windows Vista Release|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Release|Win32.Deploy.0 = Windows Vista Release|Win32 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Release|x64.ActiveCfg = Windows Vista Release|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Release|x64.Build.0 = Windows Vista Release|x64 + {445FD18F-97E3-4E5D-825F-151026242C05}.Windows Vista Release|x64.Deploy.0 = Windows Vista Release|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Debug|Win32.ActiveCfg = Windows 7 Debug|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Debug|Win32.Build.0 = Windows 7 Debug|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Debug|Win32.Deploy.0 = Windows 7 Debug|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Debug|x64.ActiveCfg = Windows 7 Debug|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Debug|x64.Build.0 = Windows 7 Debug|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Debug|x64.Deploy.0 = Windows 7 Debug|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Release|Win32.ActiveCfg = Windows 7 Release|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Release|Win32.Build.0 = Windows 7 Release|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Release|Win32.Deploy.0 = Windows 7 Release|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Release|x64.ActiveCfg = Windows 7 Release|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Release|x64.Build.0 = Windows 7 Release|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows 7 Release|x64.Deploy.0 = Windows 7 Release|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Debug|Win32.ActiveCfg = Windows Developer Preview Debug|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Debug|Win32.Build.0 = Windows Developer Preview Debug|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Debug|Win32.Deploy.0 = Windows Developer Preview Debug|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Debug|x64.ActiveCfg = Windows Developer Preview Debug|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Debug|x64.Build.0 = Windows Developer Preview Debug|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Debug|x64.Deploy.0 = Windows Developer Preview Debug|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Release|Win32.ActiveCfg = Windows Developer Preview Release|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Release|Win32.Build.0 = Windows Developer Preview Release|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Release|Win32.Deploy.0 = Windows Developer Preview Release|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Release|x64.ActiveCfg = Windows Developer Preview Release|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Release|x64.Build.0 = Windows Developer Preview Release|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Developer Preview Release|x64.Deploy.0 = Windows Developer Preview Release|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Debug|Win32.ActiveCfg = Windows Vista Debug|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Debug|Win32.Build.0 = Windows Vista Debug|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Debug|Win32.Deploy.0 = Windows Vista Debug|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Debug|x64.ActiveCfg = Windows Vista Debug|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Debug|x64.Build.0 = Windows Vista Debug|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Debug|x64.Deploy.0 = Windows Vista Debug|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Release|Win32.ActiveCfg = Windows Vista Release|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Release|Win32.Build.0 = Windows Vista Release|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Release|Win32.Deploy.0 = Windows Vista Release|Win32 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Release|x64.ActiveCfg = Windows Vista Release|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Release|x64.Build.0 = Windows Vista Release|x64 + {97D9942B-5EA3-488C-B512-C96E5D077F8E}.Windows Vista Release|x64.Deploy.0 = Windows Vista Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/proj/xennet/xennet.vcxproj b/proj/xennet/xennet.vcxproj new file mode 100644 index 0000000..925df09 --- /dev/null +++ b/proj/xennet/xennet.vcxproj @@ -0,0 +1,190 @@ + + + + + Windows Developer Preview Debug + Win32 + + + Windows Developer Preview Release + Win32 + + + Windows 7 Debug + Win32 + + + Windows 7 Release + Win32 + + + Windows Vista Debug + Win32 + + + Windows Vista Release + Win32 + + + Windows Developer Preview Debug + x64 + + + Windows Developer Preview Release + x64 + + + Windows 7 Debug + x64 + + + Windows 7 Release + x64 + + + Windows Vista Debug + x64 + + + Windows Vista Release + x64 + + + + {97D9942B-5EA3-488C-B512-C96E5D077F8E} + v4.5 + 11.0 + xennet + + + WindowsKernelModeDriver8.0 + Driver + WDM + Windows Developer Preview Debug + + + + Windows8 + true + + + Windows8 + false + + + Windows7 + true + + + Windows7 + false + + + Vista + true + + + Vista + false + + + Windows8 + true + + + Windows8 + false + + + Windows7 + true + + + Windows7 + false + + + Vista + true + + + Vista + false + + + + + + + + $(IncludePath) + true + false + + + + $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + __i386__;__MODULE__="XENNET";NDIS_MINIPORT_DRIVER;NDIS60_MINIPORT=1;POOL_NX_OPTIN=1;%(PreprocessorDefinitions) + EnableAllWarnings + 4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings) + true + true + + + false + $(DDK_LIB_PATH)\ndis.lib;%(AdditionalDependencies) + + + $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + + + true + x86 + true + $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION).$(BUILD_NUMBER) + true + + + + + $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + __x86_64__;__MODULE__="XENNET";NDIS_MINIPORT_DRIVER;NDIS60_MINIPORT=1;POOL_NX_OPTIN=1;%(PreprocessorDefinitions) + EnableAllWarnings + 4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings) + true + true + + + $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + + + $(DDK_LIB_PATH)\ndis.lib;%(AdditionalDependencies) + + + true + amd64 + true + $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION).$(BUILD_NUMBER) + true + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/proj/xennet/xennet.vcxproj.user b/proj/xennet/xennet.vcxproj.user new file mode 100644 index 0000000..7dea6a2 --- /dev/null +++ b/proj/xennet/xennet.vcxproj.user @@ -0,0 +1,8 @@ + + + + ProductionSign + CN="Citrix Systems, Inc.", OU=Digital ID Class 3 - Microsoft Software Validation v2, O="Citrix Systems, Inc.", L=Santa Clara, S=California, C=US | 9505C081954CC0A3E8B904458ACACD72EABD98B5 + http://timestamp.verisign.com/scripts/timstamp.dll + + \ No newline at end of file diff --git a/proj/xennet_coinst/xennet_coinst.vcxproj b/proj/xennet_coinst/xennet_coinst.vcxproj new file mode 100644 index 0000000..a98e707 --- /dev/null +++ b/proj/xennet_coinst/xennet_coinst.vcxproj @@ -0,0 +1,177 @@ + + + + + Windows Developer Preview Debug + Win32 + + + Windows Developer Preview Release + Win32 + + + Windows 7 Debug + Win32 + + + Windows 7 Release + Win32 + + + Windows Vista Debug + Win32 + + + Windows Vista Release + Win32 + + + Windows Developer Preview Debug + x64 + + + Windows Developer Preview Release + x64 + + + Windows 7 Debug + x64 + + + Windows 7 Release + x64 + + + Windows Vista Debug + x64 + + + Windows Vista Release + x64 + + + + {3EDD837A-C1BE-47D4-9603-16B61353670B} + v4.5 + 11.0 + xennet_coinst + + + WindowsApplicationForDrivers8.0 + DynamicLibrary + WDM + Windows Developer Preview Debug + + + + Windows8 + true + + + Windows8 + false + + + Windows7 + true + + + Windows7 + false + + + Vista + true + + + Vista + false + + + Windows8 + true + + + Windows8 + false + + + Windows7 + true + + + Windows7 + false + + + Vista + true + + + Vista + false + + + + + + + + DbgengKernelDebugger + + + $(IncludePath) + true + false + + + + $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + __i386__;__MODULE__="XENNET_COINST";%(PreprocessorDefinitions) + EnableAllWarnings + 4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings) + true + true + MultiThreadedDebug + MultiThreaded + + + ../../src/coinst/xennet_coinst.def + setupapi.lib;%(AdditionalDependencies) + + + $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + + + + + $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + __x86_64__;__MODULE__="XENNET_COINST";%(PreprocessorDefinitions) + EnableAllWarnings + 4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings) + true + true + MultiThreadedDebug + MultiThreaded + + + ../../src/coinst/xennet_coinst.def + setupapi.lib;%(AdditionalDependencies) + + + $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/proj/xennet_coinst/xennet_coinst.vcxproj.user b/proj/xennet_coinst/xennet_coinst.vcxproj.user new file mode 100644 index 0000000..7dea6a2 --- /dev/null +++ b/proj/xennet_coinst/xennet_coinst.vcxproj.user @@ -0,0 +1,8 @@ + + + + ProductionSign + CN="Citrix Systems, Inc.", OU=Digital ID Class 3 - Microsoft Software Validation v2, O="Citrix Systems, Inc.", L=Santa Clara, S=California, C=US | 9505C081954CC0A3E8B904458ACACD72EABD98B5 + http://timestamp.verisign.com/scripts/timstamp.dll + + \ No newline at end of file diff --git a/src/coinst/coinst.c b/src/coinst/coinst.c new file mode 100644 index 0000000..62b4709 --- /dev/null +++ b/src/coinst/coinst.c @@ -0,0 +1,2817 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define INITGUID + +#include +#include +#include +#include +#include +#include +#include + +#include + +__user_code; + +#define MAXIMUM_BUFFER_SIZE 1024 + +#define ENUM_KEY "SYSTEM\\CurrentControlSet\\Enum" + +#define CLASS_KEY "SYSTEM\\CurrentControlSet\\Control\\Class" + +#define SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services" + +#define NSI_KEY "SYSTEM\\CurrentControlSet\\Control\\Nsi" + +#define PARAMETERS_KEY(_Driver) \ + SERVICES_KEY ## "\\" ## #_Driver ## "\\Parameters" + +#define ALIASES_KEY(_Driver) \ + SERVICES_KEY ## "\\" ## #_Driver ## "\\Aliases" + +#define STATUS_KEY(_Driver) \ + SERVICES_KEY ## "\\" ## #_Driver ## "\\Status" + +#define SOFTWARE_KEY "SOFTWARE\\Citrix" + +#define NET_SETTINGS_KEY \ + SOFTWARE_KEY ## "\\" ## "XenToolsNetSettings\\XEN\\VIF" + +static VOID +#pragma prefast(suppress:6262) // Function uses '1036' bytes of stack: exceeds /analyze:stacksize'1024' +__Log( + IN const CHAR *Format, + IN ... + ) +{ + TCHAR Buffer[MAXIMUM_BUFFER_SIZE]; + va_list Arguments; + size_t Length; + SP_LOG_TOKEN LogToken; + DWORD Category; + DWORD Flags; + HRESULT Result; + + va_start(Arguments, Format); + Result = StringCchVPrintf(Buffer, MAXIMUM_BUFFER_SIZE, Format, Arguments); + va_end(Arguments); + + if (Result != S_OK && Result != STRSAFE_E_INSUFFICIENT_BUFFER) + return; + + Result = StringCchLength(Buffer, MAXIMUM_BUFFER_SIZE, &Length); + if (Result != S_OK) + return; + + LogToken = SetupGetThreadLogToken(); + Category = TXTLOG_VENDOR; + Flags = TXTLOG_DETAILS; + + SetupWriteTextLog(LogToken, Category, Flags, Buffer); + + __analysis_assume(Length < MAXIMUM_BUFFER_SIZE); + __analysis_assume(Length >= 2); + Length = __min(MAXIMUM_BUFFER_SIZE - 1, Length + 2); + Buffer[Length] = '\0'; + Buffer[Length - 1] = '\n'; + Buffer[Length - 2] = '\r'; + + OutputDebugString(Buffer); +} + +#define Log(_Format, ...) \ + __Log(__MODULE__ "|" __FUNCTION__ ": " _Format, __VA_ARGS__) + +static PTCHAR +GetErrorMessage( + IN DWORD Error + ) +{ + PTCHAR Message; + ULONG Index; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + Error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&Message, + 0, + NULL); + + for (Index = 0; Message[Index] != '\0'; Index++) { + if (Message[Index] == '\r' || Message[Index] == '\n') { + Message[Index] = '\0'; + break; + } + } + + return Message; +} + +static const CHAR * +FunctionName( + IN DI_FUNCTION Function + ) +{ +#define _NAME(_Function) \ + case DIF_ ## _Function: \ + return #_Function; + + switch (Function) { + _NAME(INSTALLDEVICE); + _NAME(REMOVE); + _NAME(SELECTDEVICE); + _NAME(ASSIGNRESOURCES); + _NAME(PROPERTIES); + _NAME(FIRSTTIMESETUP); + _NAME(FOUNDDEVICE); + _NAME(SELECTCLASSDRIVERS); + _NAME(VALIDATECLASSDRIVERS); + _NAME(INSTALLCLASSDRIVERS); + _NAME(CALCDISKSPACE); + _NAME(DESTROYPRIVATEDATA); + _NAME(VALIDATEDRIVER); + _NAME(MOVEDEVICE); + _NAME(DETECT); + _NAME(INSTALLWIZARD); + _NAME(DESTROYWIZARDDATA); + _NAME(PROPERTYCHANGE); + _NAME(ENABLECLASS); + _NAME(DETECTVERIFY); + _NAME(INSTALLDEVICEFILES); + _NAME(ALLOW_INSTALL); + _NAME(SELECTBESTCOMPATDRV); + _NAME(REGISTERDEVICE); + _NAME(NEWDEVICEWIZARD_PRESELECT); + _NAME(NEWDEVICEWIZARD_SELECT); + _NAME(NEWDEVICEWIZARD_PREANALYZE); + _NAME(NEWDEVICEWIZARD_POSTANALYZE); + _NAME(NEWDEVICEWIZARD_FINISHINSTALL); + _NAME(INSTALLINTERFACES); + _NAME(DETECTCANCEL); + _NAME(REGISTER_COINSTALLERS); + _NAME(ADDPROPERTYPAGE_ADVANCED); + _NAME(ADDPROPERTYPAGE_BASIC); + _NAME(TROUBLESHOOTER); + _NAME(POWERMESSAGEWAKE); + default: + break; + } + + return "UNKNOWN"; + +#undef _NAME +} + +#define MAXIMUM_DEVICE_NAME_LENGTH 32 +#define MAXIMUM_ALIAS_LENGTH 128 + +typedef struct _EMULATED_DEVICE { + TCHAR Device[MAXIMUM_DEVICE_NAME_LENGTH]; + TCHAR Alias[MAXIMUM_ALIAS_LENGTH]; +} EMULATED_DEVICE, *PEMULATED_DEVICE; + +static PEMULATED_DEVICE +GetEmulatedDeviceTable( + VOID + ) +{ + HKEY Key; + HRESULT Error; + DWORD Values; + DWORD Index; + PEMULATED_DEVICE Table; + + Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + ALIASES_KEY(XENFILT) "\\VIF", + 0, + KEY_READ, + &Key); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail1; + } + + Error = RegQueryInfoKey(Key, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &Values, + NULL, + NULL, + NULL, + NULL); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail2; + } + + Table = malloc(sizeof (EMULATED_DEVICE) * (Values + 1)); + if (Table == NULL) + goto fail3; + + memset(Table, 0, sizeof (EMULATED_DEVICE) * (Values + 1)); + + for (Index = 0; Index < Values; Index++) { + PEMULATED_DEVICE Entry = &Table[Index]; + ULONG DeviceNameLength; + ULONG AliasLength; + ULONG Type; + + DeviceNameLength = MAXIMUM_DEVICE_NAME_LENGTH * sizeof (TCHAR); + AliasLength = MAXIMUM_ALIAS_LENGTH * sizeof (TCHAR); + + Error = RegEnumValue(Key, + Index, + (LPTSTR)Entry->Device, + &DeviceNameLength, + NULL, + &Type, + (LPBYTE)Entry->Alias, + &AliasLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail4; + } + + if (Type != REG_SZ) { + SetLastError(ERROR_BAD_FORMAT); + goto fail5; + } + } + + RegCloseKey(Key); + + return Table; + +fail5: + Log("fail5"); + +fail4: + Log("fail4"); + + free(Table); + +fail3: + Log("fail3"); + +fail2: + Log("fail2"); + + RegCloseKey(Key); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return NULL; +} + +static DECLSPEC_NOINLINE HRESULT +OpenSoftwareKey( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + OUT PHKEY SoftwareKey + ) +{ + HKEY Key; + HRESULT Error; + + Key = SetupDiOpenDevRegKey(DeviceInfoSet, + DeviceInfoData, + DICS_FLAG_GLOBAL, + 0, + DIREG_DRV, + KEY_READ); + if (Key == INVALID_HANDLE_VALUE) { + SetLastError(ERROR_PATH_NOT_FOUND); + goto fail1; + } + + *SoftwareKey = Key; + + return ERROR_SUCCESS; + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return Error; +} + +// {4d36e972-e325-11ce-bfc1-08002be10318} +DEFINE_GUID(GUID_NET_DEVICE, + 0x4d36e972, + 0xe325, + 0x11ce, + 0xbf, + 0xc1, + 0x08, + 0x00, + 0x2b, + 0xe1, + 0x03, + 0x18 + ); + +static HRESULT +OpenAliasHardwareKey( + IN PTCHAR AliasDeviceID, + IN PTCHAR AliasInstanceID, + OUT PHKEY HardwareKey + ) +{ + DWORD PathLength; + PTCHAR Path; + HRESULT Result; + HKEY Key; + HRESULT Error; + DWORD SubKeys; + DWORD MaxSubKeyLength; + PTCHAR Name; + DWORD Index; + HKEY SubKey; + + Log("====> (%s) (%s)", AliasDeviceID, AliasInstanceID); + + PathLength = (DWORD)(strlen(ENUM_KEY) + + 1 + + strlen(AliasDeviceID) + + 1) * sizeof (TCHAR); + + Path = malloc(PathLength); + if (Path == NULL) + goto fail1; + + Result = StringCbPrintf(Path, + PathLength, + "%s\\%s", + ENUM_KEY, + AliasDeviceID); + if (!SUCCEEDED(Result)) { + SetLastError(ERROR_BUFFER_OVERFLOW); + goto fail2; + } + + Log("%s", Path); + + Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + Path, + 0, + KEY_READ, + &Key); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail3; + } + + Error = RegQueryInfoKey(Key, + NULL, + NULL, + NULL, + &SubKeys, + &MaxSubKeyLength, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail4; + } + + Name = malloc(MaxSubKeyLength + sizeof (TCHAR)); + if (Name == NULL) + goto fail5; + + for (Index = 0; Index < SubKeys; Index++) { + DWORD NameLength; + PTCHAR InstanceID; + + NameLength = MaxSubKeyLength + sizeof (TCHAR); + memset(Name, 0, NameLength); + + Error = RegEnumKeyEx(Key, + Index, + (LPTSTR)Name, + &NameLength, + NULL, + NULL, + NULL, + NULL); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail6; + } + + Log("%s", Name); + + Error = RegOpenKeyEx(Key, + Name, + 0, + KEY_READ, + &SubKey); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail7; + } + + InstanceID = strrchr(Name, '&'); + InstanceID++; + + if (_stricmp(AliasInstanceID, InstanceID) == 0) + goto done; + + RegCloseKey(SubKey); + } + + Error = ERROR_FILE_NOT_FOUND; + goto fail8; + +done: + free(Name); + + RegCloseKey(Key); + + free(Path); + + *HardwareKey = SubKey; + + Log("<===="); + + return ERROR_SUCCESS; + +fail8: + Log("fail8"); + +fail7: + Log("fail7"); + +fail6: + Log("fail6"); + + free(Name); + +fail5: + Log("fail5"); + +fail4: + Log("fail4"); + + RegCloseKey(Key); + +fail3: + Log("fail3"); + +fail2: + Log("fail2"); + + free(Path); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return Error; +} + +static HRESULT +OpenAliasSoftwareKey( + IN PTCHAR Alias, + OUT PHKEY SoftwareKey + ) +{ + DWORD BufferLength; + PTCHAR Buffer; + PTCHAR AliasDeviceID; + PTCHAR AliasInstanceID; + HRESULT Error; + HKEY HardwareKey; + DWORD MaxValueLength; + DWORD DriverLength; + PTCHAR Driver; + DWORD Type; + DWORD PathLength; + PTCHAR Path; + HRESULT Result; + HKEY Key; + + Log("====>"); + + BufferLength = (DWORD)(strlen(Alias) + + 1) * sizeof (TCHAR); + + Buffer = malloc(BufferLength); + if (Buffer == NULL) + goto fail1; + + memset(Buffer, 0, BufferLength); + + memcpy(Buffer, Alias, strlen(Alias)); + + AliasDeviceID = Buffer; + + AliasInstanceID = strchr(Buffer, '#'); + *AliasInstanceID++ = '\0'; + + Error = OpenAliasHardwareKey(AliasDeviceID, + AliasInstanceID, + &HardwareKey); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail2; + } + + Error = RegQueryInfoKey(HardwareKey, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &MaxValueLength, + NULL, + NULL); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail3; + } + + DriverLength = MaxValueLength + sizeof (TCHAR); + + Driver = malloc(DriverLength); + if (Driver == NULL) + goto fail4; + + memset(Driver, 0, DriverLength); + + Error = RegQueryValueEx(HardwareKey, + "Driver", + NULL, + &Type, + (LPBYTE)Driver, + &DriverLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail5; + } + + if (Type != REG_SZ) { + SetLastError(ERROR_BAD_FORMAT); + goto fail6; + } + + Log("%s", Driver); + + PathLength = (ULONG)(strlen(CLASS_KEY) + + 1 + + strlen(Driver) + + 1) * sizeof (TCHAR); + + Path = malloc(PathLength); + if (Path == NULL) + goto fail7; + + Result = StringCbPrintf(Path, + PathLength, + "%s\\%s", + CLASS_KEY, + Driver); + if (!SUCCEEDED(Result)) { + SetLastError(ERROR_BUFFER_OVERFLOW); + goto fail8; + } + + Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + Path, + 0, + KEY_READ, + &Key); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail9; + } + + free(Path); + + free(Driver); + + RegCloseKey(HardwareKey); + + free(Buffer); + + *SoftwareKey = Key; + + Log("<===="); + + return ERROR_SUCCESS; + +fail9: + Log("fail9"); + +fail8: + Log("fail8"); + + free(Path); + +fail7: + Log("fail7"); + +fail6: + Log("fail6"); + +fail5: + Log("fail5"); + + free(Driver); + +fail4: + Log("fail4"); + +fail3: + Log("fail3"); + + RegCloseKey(HardwareKey); + +fail2: + Log("fail2"); + + free(Buffer); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return Error; +} + +static PTCHAR +GetInterface( + IN HKEY Key + ) +{ + HRESULT Error; + HKEY SubKey; + DWORD MaxValueLength; + DWORD RootDeviceLength; + PTCHAR RootDevice; + DWORD Type; + + Error = RegOpenKeyEx(Key, + "Linkage", + 0, + KEY_READ, + &SubKey); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail1; + } + + Error = RegQueryInfoKey(SubKey, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &MaxValueLength, + NULL, + NULL); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail2; + } + + RootDeviceLength = MaxValueLength + sizeof (TCHAR); + + RootDevice = malloc(RootDeviceLength); + if (RootDevice == NULL) + goto fail2; + + memset(RootDevice, 0, RootDeviceLength); + + Error = RegQueryValueEx(SubKey, + "RootDevice", + NULL, + &Type, + (LPBYTE)RootDevice, + &RootDeviceLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail3; + } + + if (Type != REG_MULTI_SZ) { + SetLastError(ERROR_BAD_FORMAT); + goto fail4; + } + + RegCloseKey(SubKey); + + return RootDevice; + +fail4: + Log("fail4"); + +fail3: + Log("fail3"); + + free(RootDevice); + +fail2: + Log("fail2"); + + RegCloseKey(SubKey); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return NULL; +} + +static BOOLEAN +CopyValues( + IN PTCHAR TargetPath, + IN PTCHAR SourcePath + ) +{ + HKEY TargetKey; + HKEY SourceKey; + HRESULT Error; + DWORD Values; + DWORD MaxNameLength; + PTCHAR Name; + DWORD MaxValueLength; + LPBYTE Value; + DWORD Index; + + Log("TARGET: %s", TargetPath); + Log("SOURCE: %s", SourcePath); + + Error = RegCreateKeyEx(HKEY_LOCAL_MACHINE, + TargetPath, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + NULL, + &TargetKey, + NULL); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail1; + } + + Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + SourcePath, + 0, + KEY_ALL_ACCESS, + &SourceKey); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail2; + } + + Error = RegQueryInfoKey(SourceKey, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &Values, + &MaxNameLength, + &MaxValueLength, + NULL, + NULL); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail3; + } + + if (Values == 0) + goto done; + + MaxNameLength += sizeof (TCHAR); + + Name = malloc(MaxNameLength); + if (Name == NULL) + goto fail4; + + Value = malloc(MaxValueLength); + if (Value == NULL) + goto fail5; + + for (Index = 0; Index < Values; Index++) { + DWORD NameLength; + DWORD ValueLength; + DWORD Type; + + NameLength = MaxNameLength; + memset(Name, 0, NameLength); + + ValueLength = MaxValueLength; + memset(Value, 0, ValueLength); + + Error = RegEnumValue(SourceKey, + Index, + (LPTSTR)Name, + &NameLength, + NULL, + &Type, + Value, + &ValueLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail6; + } + + Error = RegSetValueEx(TargetKey, + Name, + 0, + Type, + Value, + ValueLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail7; + } + + Log("COPIED %s", Name); + } + + free(Value); + free(Name); + + RegCloseKey(SourceKey); + RegCloseKey(TargetKey); + +done: + return TRUE; + +fail7: + Log("fail7"); + +fail6: + Log("fail6"); + + free(Value); + +fail5: + Log("fail5"); + + free(Name); + +fail4: + Log("fail4"); + +fail3: + Log("fail3"); + + RegCloseKey(SourceKey); + +fail2: + Log("fail2"); + + RegCloseKey(TargetKey); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static BOOLEAN +CopyParameters( + IN PTCHAR TargetPrefix, + IN PTCHAR TargetNode, + IN PTCHAR SourcePrefix, + IN PTCHAR SourceNode + ) +{ + DWORD Length; + PTCHAR SourcePath; + PTCHAR TargetPath; + HRESULT Result; + HRESULT Error; + BOOLEAN Success; + + Length = (DWORD)((strlen(TargetPrefix) + + strlen(TargetNode) + + 1) * sizeof (TCHAR)); + + TargetPath = malloc(Length); + if (TargetPath == NULL) + goto fail1; + + Result = StringCbPrintf(TargetPath, + Length, + "%s%s", + TargetPrefix, + TargetNode); + if (!SUCCEEDED(Result)) { + SetLastError(ERROR_BUFFER_OVERFLOW); + goto fail2; + } + + Length = (DWORD)((strlen(SourcePrefix) + + strlen(SourceNode) + + 1) * sizeof (TCHAR)); + + SourcePath = malloc(Length); + if (SourcePath == NULL) + goto fail3; + + Result = StringCbPrintf(SourcePath, + Length, + "%s%s", + SourcePrefix, + SourceNode); + if (!SUCCEEDED(Result)) { + SetLastError(ERROR_BUFFER_OVERFLOW); + goto fail4; + } + + Success = CopyValues(TargetPath, SourcePath); + + free(SourcePath); + free(TargetPath); + + return Success; + +fail4: + Log("fail4"); + + free(SourcePath); + +fail3: + Log("fail3"); + +fail2: + Log("fail2"); + + free(TargetPath); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static BOOLEAN +CopyIpVersion6Addresses( + IN PTCHAR TargetPath, + IN PTCHAR TargetPrefix, + IN PTCHAR SourcePath, + IN PTCHAR SourcePrefix + ) +{ + HKEY TargetKey; + HKEY SourceKey; + HRESULT Error; + DWORD Values; + DWORD MaxNameLength; + PTCHAR Name; + DWORD MaxValueLength; + LPBYTE Value; + DWORD Index; + + Log("TARGET: %s", TargetPath); + Log("SOURCE: %s", SourcePath); + + Error = RegCreateKeyEx(HKEY_LOCAL_MACHINE, + TargetPath, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + NULL, + &TargetKey, + NULL); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail1; + } + + Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + SourcePath, + 0, + KEY_ALL_ACCESS, + &SourceKey); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail2; + } + + Error = RegQueryInfoKey(SourceKey, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &Values, + &MaxNameLength, + &MaxValueLength, + NULL, + NULL); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail3; + } + + if (Values == 0) + goto done; + + MaxNameLength += sizeof (TCHAR); + + Name = malloc(MaxNameLength); + if (Name == NULL) + goto fail4; + + Value = malloc(MaxValueLength); + if (Value == NULL) + goto fail5; + + for (Index = 0; Index < Values; Index++) { + DWORD NameLength; + DWORD ValueLength; + DWORD Type; + + NameLength = MaxNameLength; + memset(Name, 0, NameLength); + + ValueLength = MaxValueLength; + memset(Value, 0, ValueLength); + + Error = RegEnumValue(SourceKey, + Index, + (LPTSTR)Name, + &NameLength, + NULL, + &Type, + Value, + &ValueLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail6; + } + + if (strncmp(Name, SourcePrefix, sizeof (ULONG64) * 2) != 0) + continue; + + Log("READ: %s", Name); + + memcpy(Name, TargetPrefix, sizeof (ULONG64) * 2); + + Log("WRITE: %s", Name); + + Error = RegSetValueEx(TargetKey, + Name, + 0, + Type, + Value, + ValueLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail7; + } + } + + free(Value); + free(Name); + + RegCloseKey(SourceKey); + RegCloseKey(TargetKey); + +done: + + return TRUE; + +fail7: + Log("fail7"); + +fail6: + Log("fail6"); + + free(Value); + +fail5: + Log("fail5"); + + free(Name); + +fail4: + Log("fail4"); + +fail3: + Log("fail3"); + + RegCloseKey(SourceKey); + +fail2: + Log("fail2"); + + RegCloseKey(TargetKey); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static PTCHAR +GetNetLuid( + IN HKEY Key + ) +{ + HRESULT Error; + DWORD MaxValueLength; + DWORD ValueLength; + LPDWORD Value; + DWORD Type; + NET_LUID NetLuid; + DWORD BufferLength; + PTCHAR Buffer; + HRESULT Result; + + memset(&NetLuid, 0, sizeof (NetLuid)); + + Error = RegQueryInfoKey(Key, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &MaxValueLength, + NULL, + NULL); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail1; + } + + ValueLength = MaxValueLength; + + Value = malloc(ValueLength); + if (Value == NULL) + goto fail2; + + memset(Value, 0, ValueLength); + + Error = RegQueryValueEx(Key, + "NetLuidIndex", + NULL, + &Type, + (LPBYTE)Value, + &ValueLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail3; + } + + if (Type != REG_DWORD) { + SetLastError(ERROR_BAD_FORMAT); + goto fail4; + } + + NetLuid.Info.NetLuidIndex = *Value; + + Error = RegQueryValueEx(Key, + "*IfType", + NULL, + &Type, + (LPBYTE)Value, + &ValueLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail5; + } + + if (Type != REG_DWORD) { + SetLastError(ERROR_BAD_FORMAT); + goto fail6; + } + + NetLuid.Info.IfType = *Value; + + BufferLength = ((sizeof (ULONG64) * 2) + 1) * sizeof (TCHAR); + + Buffer = malloc(BufferLength); + if (Buffer == NULL) + goto fail7; + + Result = StringCbPrintf(Buffer, + BufferLength, + "%016llx", + _byteswap_uint64(NetLuid.Value)); + if (!SUCCEEDED(Result)) { + SetLastError(ERROR_BUFFER_OVERFLOW); + goto fail8; + } + + free(Value); + + return Buffer; + +fail8: + Log("fail8"); + + free(Buffer); + +fail7: + Log("fail7"); + +fail6: + Log("fail6"); + +fail5: + Log("fail5"); + +fail4: + Log("fail4"); + +fail3: + Log("fail3"); + + free(Value); + +fail2: + Log("fail2"); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return NULL; +} + +static BOOLEAN +MigrateSettings( + IN HKEY SourceKey, + IN HKEY TargetKey + ) +{ + PTCHAR SourcePrefix; + PTCHAR TargetPrefix; + BOOLEAN Success; + HRESULT Error; + + Log("====>"); + + Success = TRUE; + + SourcePrefix = GetInterface(SourceKey); + + if (SourcePrefix == NULL) + goto fail1; + + TargetPrefix = GetInterface(TargetKey); + + if (TargetPrefix == NULL) + goto fail2; + + Success &= CopyParameters(PARAMETERS_KEY(NetBT) "\\Interfaces\\Tcpip_", TargetPrefix, + PARAMETERS_KEY(NetBT) "\\Interfaces\\Tcpip_", SourcePrefix); + Success &= CopyParameters(PARAMETERS_KEY(Tcpip) "\\Interfaces\\", TargetPrefix, + PARAMETERS_KEY(Tcpip) "\\Interfaces\\", SourcePrefix); + Success &= CopyParameters(PARAMETERS_KEY(Tcpip6) "\\Interfaces\\", TargetPrefix, + PARAMETERS_KEY(Tcpip6) "\\Interfaces\\", SourcePrefix); + + free(TargetPrefix); + free(SourcePrefix); + + SourcePrefix = GetNetLuid(SourceKey); + + if (SourcePrefix == NULL) + goto fail3; + + TargetPrefix = GetNetLuid(TargetKey); + + if (TargetPrefix == NULL) + goto fail4; + + Success &= CopyIpVersion6Addresses(NSI_KEY "\\{eb004a01-9b1a-11d4-9123-0050047759bc}\\10\\", TargetPrefix, + NSI_KEY "\\{eb004a01-9b1a-11d4-9123-0050047759bc}\\10\\", SourcePrefix); + + free(TargetPrefix); + free(SourcePrefix); + + Log("<===="); + + return Success; + +fail4: + Log("fail4"); + + free(SourcePrefix); + goto fail1; + +fail3: + Log("fail3"); + +fail2: + Log("fail2"); + + free(SourcePrefix); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static FORCEINLINE BOOLEAN +__MigrateFromEmulated( + IN PTCHAR Location, + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData + ) +{ + PEMULATED_DEVICE Table; + DWORD Index; + BOOLEAN Success; + HRESULT Error; + HKEY SourceKey; + HKEY TargetKey; + + Log("====>"); + + Table = GetEmulatedDeviceTable(); + if (Table == NULL) + goto fail1; + + Success = FALSE; + + for (Index = 0; strlen(Table[Index].Alias) != 0; Index++) { + if (_stricmp(Location, Table[Index].Device) == 0) { + Error = OpenAliasSoftwareKey(Table[Index].Alias, + &SourceKey); + if (Error != ERROR_SUCCESS) + goto fail2; + + Error = OpenSoftwareKey(DeviceInfoSet, + DeviceInfoData, + &TargetKey); + if (Error != ERROR_SUCCESS) + goto fail3; + + Success = MigrateSettings(SourceKey, TargetKey); + + RegCloseKey(TargetKey); + RegCloseKey(SourceKey); + + break; + } + } + + free(Table); + + Log("<===="); + + return Success; + +fail3: + RegCloseKey(SourceKey); + +fail2: +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static FORCEINLINE BOOLEAN +__MigrateToEmulated( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PTCHAR Location + ) +{ + PEMULATED_DEVICE Table; + DWORD Index; + BOOLEAN Success; + HRESULT Error; + HKEY SourceKey; + HKEY TargetKey; + + Log("====>"); + + Table = GetEmulatedDeviceTable(); + if (Table == NULL) + goto fail1; + + Success = FALSE; + + for (Index = 0; strlen(Table[Index].Alias) != 0; Index++) { + if (_stricmp(Location, Table[Index].Device) == 0) { + Error = OpenSoftwareKey(DeviceInfoSet, + DeviceInfoData, + &SourceKey); + if (Error != ERROR_SUCCESS) + goto fail3; + + Error = OpenAliasSoftwareKey(Table[Index].Alias, + &TargetKey); + if (Error != ERROR_SUCCESS) + goto fail2; + + Success = MigrateSettings(SourceKey, TargetKey); + break; + } + } + + free(Table); + + Log("<===="); + + return Success; + +fail3: + RegCloseKey(SourceKey); + +fail2: +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static FORCEINLINE BOOLEAN +__MigrateFromPV( + IN PTCHAR Location, + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData + ) +{ + HKEY TargetKey; + PTCHAR TargetPrefix; + DWORD Length; + PTCHAR SourcePrefix; + BOOLEAN Success; + HRESULT Result; + HRESULT Error; + + Log("====>"); + + Success = TRUE; + + Length = (DWORD)((strlen(NET_SETTINGS_KEY) + + strlen("\\") + + strlen(Location) + + strlen("\\") + + 1) * sizeof (TCHAR)); + + SourcePrefix = malloc(Length); + if (SourcePrefix == NULL) + goto fail1; + + Result = StringCbPrintf(SourcePrefix, + Length, + "%s\\%s\\", + NET_SETTINGS_KEY, + Location); + if (!SUCCEEDED(Result)) { + SetLastError(ERROR_BUFFER_OVERFLOW); + goto fail2; + } + + Error = OpenSoftwareKey(DeviceInfoSet, + DeviceInfoData, + &TargetKey); + if (Error != ERROR_SUCCESS) + goto fail3; + + TargetPrefix = GetInterface(TargetKey); + + if (TargetPrefix == NULL) + goto fail4; + + Success &= CopyParameters(PARAMETERS_KEY(NetBT) "\\Interfaces\\Tcpip_", TargetPrefix, + SourcePrefix, "nbt"); + Success &= CopyParameters(PARAMETERS_KEY(Tcpip) "\\Interfaces\\", TargetPrefix, + SourcePrefix, "tcpip"); + Success &= CopyParameters(PARAMETERS_KEY(Tcpip6) "\\Interfaces\\", TargetPrefix, + SourcePrefix, "tcpip6"); + + free(TargetPrefix); + + TargetPrefix = GetNetLuid(TargetKey); + + if (TargetPrefix == NULL) + goto fail5; + + Success &= CopyIpVersion6Addresses(NSI_KEY "\\{eb004a01-9b1a-11d4-9123-0050047759bc}\\10\\", TargetPrefix, + SourcePrefix, "IPv6_Address____"); + + free(TargetPrefix); + + RegCloseKey(TargetKey); + free(SourcePrefix); + + Log("<===="); + + return Success; + +fail5: + Log("fail5"); + +fail4: + Log("fail4"); + + RegCloseKey(TargetKey); + +fail3: + Log("fail3"); + +fail2: + Log("fail"); + + free(SourcePrefix); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static FORCEINLINE BOOLEAN +__MigrateToPV( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PTCHAR Location + ) +{ + PTCHAR TargetPrefix; + DWORD Length; + HKEY SourceKey; + PTCHAR SourcePrefix; + BOOLEAN Success; + HRESULT Result; + HRESULT Error; + + Log("====>"); + + Success = TRUE; + + Length = (DWORD)((strlen(NET_SETTINGS_KEY) + + strlen("\\") + + strlen(Location) + + strlen("\\") + + 1) * sizeof (TCHAR)); + + TargetPrefix = malloc(Length); + if (TargetPrefix == NULL) + goto fail1; + + Result = StringCbPrintf(TargetPrefix, + Length, + "%s\\%s\\", + NET_SETTINGS_KEY, + Location); + if (!SUCCEEDED(Result)) { + SetLastError(ERROR_BUFFER_OVERFLOW); + goto fail2; + } + + Error = OpenSoftwareKey(DeviceInfoSet, + DeviceInfoData, + &SourceKey); + if (Error != ERROR_SUCCESS) + goto fail3; + + SourcePrefix = GetInterface(SourceKey); + + if (SourcePrefix == NULL) + goto fail4; + + Success &= CopyParameters(TargetPrefix, "nbt", + PARAMETERS_KEY(NetBT) "\\Interfaces\\Tcpip_", SourcePrefix); + Success &= CopyParameters(TargetPrefix, "tcpip", + PARAMETERS_KEY(Tcpip) "\\Interfaces\\", SourcePrefix); + Success &= CopyParameters(TargetPrefix, "tcpip6", + PARAMETERS_KEY(Tcpip6) "\\Interfaces\\", SourcePrefix); + + free(SourcePrefix); + + SourcePrefix = GetNetLuid(SourceKey); + + if (SourcePrefix == NULL) + goto fail5; + + Success &= CopyIpVersion6Addresses(TargetPrefix, "IPv6_Address____", + NSI_KEY "\\{eb004a01-9b1a-11d4-9123-0050047759bc}\\10\\", SourcePrefix); + + free(SourcePrefix); + + RegCloseKey(SourceKey); + free(TargetPrefix); + + Log("<===="); + + return Success; + +fail5: + Log("fail5"); + +fail4: + Log("fail4"); + + RegCloseKey(SourceKey); + +fail3: + Log("fail3"); + +fail2: + Log("fail2"); + + free(TargetPrefix); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static PTCHAR +GetProperty( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN DWORD Index + ) +{ + DWORD Type; + DWORD PropertyLength; + PTCHAR Property; + HRESULT Error; + + if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet, + DeviceInfoData, + Index, + &Type, + NULL, + 0, + &PropertyLength)) { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + goto fail1; + } + + if (Type != REG_SZ) { + SetLastError(ERROR_BAD_FORMAT); + goto fail2; + } + + PropertyLength += sizeof (TCHAR); + + Property = malloc(PropertyLength); + if (Property == NULL) + goto fail3; + + memset(Property, 0, PropertyLength); + + if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet, + DeviceInfoData, + Index, + NULL, + (PBYTE)Property, + PropertyLength, + NULL)) + goto fail4; + + return Property; + +fail4: + free(Property); + +fail3: + Log("fail3"); + +fail2: + Log("fail2"); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return NULL; +} + +static BOOLEAN +SetFriendlyName( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PTCHAR Description, + IN PTCHAR Location + ) +{ + TCHAR FriendlyName[MAX_PATH]; + DWORD FriendlyNameLength; + HRESULT Result; + HRESULT Error; + + Result = StringCbPrintf(FriendlyName, + MAX_PATH, + TEXT("%s #%s"), + Description, + Location); + if (!SUCCEEDED(Result)) + goto fail1; + + FriendlyNameLength = (DWORD)(strlen(FriendlyName) + sizeof (TCHAR)); + + if (!SetupDiSetDeviceRegistryProperty(DeviceInfoSet, + DeviceInfoData, + SPDRP_FRIENDLYNAME, + (PBYTE)FriendlyName, + FriendlyNameLength)) + goto fail2; + + Log("%s", FriendlyName); + + return TRUE; + +fail2: + Log("fail2"); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static BOOLEAN +InstallDevice( + IN PTCHAR Class, + IN PTCHAR Device + ) +{ + HKEY Key; + DWORD OldLength; + DWORD NewLength; + DWORD Type; + HRESULT Error; + PTCHAR Devices; + ULONG Offset; + + Error = RegCreateKeyEx(HKEY_LOCAL_MACHINE, + PARAMETERS_KEY(XENFILT), + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + NULL, + &Key, + NULL); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail1; + } + + OldLength = 0; + Error = RegQueryValueEx(Key, + Class, + NULL, + &Type, + NULL, + &OldLength); + if (Error != ERROR_SUCCESS) { + if (Error != ERROR_FILE_NOT_FOUND) { + SetLastError(Error); + goto fail2; + } + + OldLength = sizeof (TCHAR); + Type = REG_MULTI_SZ; + } + + if (Type != REG_MULTI_SZ) { + SetLastError(ERROR_BAD_FORMAT); + goto fail3; + } + + NewLength = OldLength + (DWORD)((strlen(Device) + 1) * sizeof (TCHAR)); + + Devices = malloc(NewLength); + if (Devices == NULL) + goto fail4; + + memset(Devices, 0, NewLength); + + Offset = 0; + if (OldLength != sizeof (TCHAR)) { + Error = RegQueryValueEx(Key, + Class, + NULL, + NULL, + (PBYTE)Devices, + &OldLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail5; + } + + while (Devices[Offset] != '\0') { + ULONG DeviceLength; + + DeviceLength = (ULONG)strlen(&Devices[Offset]) / sizeof (TCHAR); + + if (_stricmp(&Devices[Offset], Device) == 0) { + Log("%s already present", Device); + goto done; + } + + Offset += DeviceLength + 1; + } + } + + memmove(&Devices[Offset], Device, strlen(Device)); + Log("added %s", Device); + + Error = RegSetValueEx(Key, + Class, + 0, + Type, + (PBYTE)Devices, + NewLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail6; + } + +done: + free(Devices); + + RegCloseKey(Key); + + return TRUE; + +fail6: + Log("fail6"); + +fail5: + Log("fail5"); + + free(Devices); + +fail4: + Log("fail4"); + +fail3: + Log("fail3"); + +fail2: + Log("fail2"); + + RegCloseKey(Key); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static BOOLEAN +RemoveDevice( + IN PTCHAR Class, + IN PTCHAR Device + ) +{ + HKEY Key; + DWORD OldLength; + DWORD NewLength; + DWORD Type; + HRESULT Error; + PTCHAR Devices; + ULONG Offset; + ULONG DeviceLength; + + Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + PARAMETERS_KEY(XENFILT), + 0, + KEY_ALL_ACCESS, + &Key); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail1; + } + + OldLength = 0; + Error = RegQueryValueEx(Key, + Class, + NULL, + &Type, + NULL, + &OldLength); + if (Error != ERROR_SUCCESS) { + if (Error != ERROR_FILE_NOT_FOUND) { + SetLastError(Error); + goto fail2; + } + + goto done; + } + + if (Type != REG_MULTI_SZ) { + SetLastError(ERROR_BAD_FORMAT); + goto fail3; + } + + Devices = malloc(OldLength); + if (Devices == NULL) + goto fail4; + + memset(Devices, 0, OldLength); + + Error = RegQueryValueEx(Key, + Class, + NULL, + NULL, + (PBYTE)Devices, + &OldLength); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail5; + } + + Offset = 0; + DeviceLength = 0; + while (Devices[Offset] != '\0') { + DeviceLength = (ULONG)strlen(&Devices[Offset]) / sizeof (TCHAR); + + if (_stricmp(&Devices[Offset], Device) == 0) + goto remove; + + Offset += DeviceLength + 1; + } + + free(Devices); + goto done; + +remove: + NewLength = OldLength - ((DeviceLength + 1) * sizeof (TCHAR)); + + memmove(&Devices[Offset], + &Devices[Offset + DeviceLength + 1], + (NewLength - Offset) * sizeof (TCHAR)); + + Log("removed %s", Device); + + if (NewLength == 1) { + Error = RegDeleteValue(Key, + Class); + } else { + Error = RegSetValueEx(Key, + Class, + 0, + Type, + (PBYTE)Devices, + NewLength); + } + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail6; + } + + free(Devices); + +done: + RegCloseKey(Key); + + return TRUE; + +fail6: + Log("fail6"); + +fail5: + Log("fail5"); + + free(Devices); + +fail4: + Log("fail4"); + +fail3: + Log("fail3"); + +fail2: + Log("fail2"); + + RegCloseKey(Key); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static BOOLEAN +IsDeviceEmulated( + IN PTCHAR Class, + IN PTCHAR Device, + OUT PBOOLEAN Present + ) +{ + HKEY Key; + DWORD Length; + DWORD Type; + HRESULT Error; + PTCHAR Devices; + ULONG Offset; + + *Present = FALSE; + + Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + STATUS_KEY(XENFILT), + 0, + KEY_READ, + &Key); + if (Error != ERROR_SUCCESS) { + if (Error == ERROR_FILE_NOT_FOUND) + goto done; + + SetLastError(Error); + goto fail1; + } + + Length = 0; + Error = RegQueryValueEx(Key, + Class, + NULL, + &Type, + NULL, + &Length); + if (Error != ERROR_SUCCESS) { + if (Error == ERROR_FILE_NOT_FOUND) + goto done; + } + + if (Type != REG_MULTI_SZ) { + SetLastError(ERROR_BAD_FORMAT); + goto fail2; + } + + Devices = malloc(Length); + if (Devices == NULL) + goto fail3; + + memset(Devices, 0, Length); + + Error = RegQueryValueEx(Key, + Class, + NULL, + NULL, + (PBYTE)Devices, + &Length); + if (Error != ERROR_SUCCESS) { + SetLastError(Error); + goto fail4; + } + + Offset = 0; + while (Devices[Offset] != '\0') { + ULONG DeviceLength; + + DeviceLength = (ULONG)strlen(&Devices[Offset]) / sizeof (TCHAR); + + if (_stricmp(&Devices[Offset], Device) == 0) { + *Present = TRUE; + break; + } + + Offset += DeviceLength + 1; + } + + free(Devices); + + RegCloseKey(Key); + +done: + return TRUE; + +fail4: + Log("fail4"); + + free(Devices); + +fail3: + Log("fail3"); + +fail2: + Log("fail2"); + + RegCloseKey(Key); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static BOOLEAN +RequestReboot( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData + ) +{ + SP_DEVINSTALL_PARAMS DeviceInstallParams; + HRESULT Error; + + DeviceInstallParams.cbSize = sizeof (DeviceInstallParams); + + if (!SetupDiGetDeviceInstallParams(DeviceInfoSet, + DeviceInfoData, + &DeviceInstallParams)) + goto fail1; + + DeviceInstallParams.Flags |= DI_NEEDREBOOT; + + Log("Flags = %08x", DeviceInstallParams.Flags); + + if (!SetupDiSetDeviceInstallParams(DeviceInfoSet, + DeviceInfoData, + &DeviceInstallParams)) + goto fail2; + + return TRUE; + +fail2: + Log("fail2"); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return FALSE; +} + +static FORCEINLINE HRESULT +__DifInstallPreProcess( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PCOINSTALLER_CONTEXT_DATA Context + ) +{ + HRESULT Error; + HKEY Key; + PTCHAR Interface; + BOOLEAN NeedMigrateSettings; + + Log("====>"); + + Error = OpenSoftwareKey(DeviceInfoSet, + DeviceInfoData, + &Key); + + if (Error == ERROR_SUCCESS) { + Interface = GetInterface(Key); + RegCloseKey(Key); + } else { + Interface = NULL; + } + + if (Interface != NULL) { + free(Interface); + + NeedMigrateSettings = FALSE; + } else { + NeedMigrateSettings = TRUE; + } + + Log("NeedMigrateSettings = %s", + (NeedMigrateSettings) ? "TRUE" : "FALSE"); + + Context->PrivateData = (PVOID)NeedMigrateSettings; + + Log("<===="); + + return ERROR_DI_POSTPROCESSING_REQUIRED; +} + +static FORCEINLINE HRESULT +__DifInstallPostProcess( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PCOINSTALLER_CONTEXT_DATA Context + ) +{ + HRESULT Error; + BOOLEAN NeedMigrateSettings; + PTCHAR Description; + PTCHAR Location; + BOOLEAN MigratedSettings; + BOOLEAN Present; + BOOLEAN Success; + + Log("====>"); + + Error = Context->InstallResult; + if (Error != NO_ERROR) { + SetLastError(Error); + goto fail1; + } + + NeedMigrateSettings = (BOOLEAN)(ULONG_PTR)Context->PrivateData; + + Description = GetProperty(DeviceInfoSet, DeviceInfoData, SPDRP_DEVICEDESC); + if (Description == NULL) + goto fail2; + + Location = GetProperty(DeviceInfoSet, DeviceInfoData, SPDRP_LOCATION_INFORMATION); + if (Location == NULL) + goto fail3; + + Success = SetFriendlyName(DeviceInfoSet, DeviceInfoData, Description, Location); + if (!Success) + goto fail4; + + MigratedSettings = FALSE; + + if (NeedMigrateSettings) { + MigratedSettings = __MigrateFromPV(Location, DeviceInfoSet, DeviceInfoData); + if (!MigratedSettings) + MigratedSettings = __MigrateFromEmulated(Location, DeviceInfoSet, DeviceInfoData); + } + + Success = InstallDevice("VIF", Location); + if (!Success) + goto fail5; + + Success = IsDeviceEmulated("VIF", Location, &Present); + if (!Success) + goto fail6; + + if (!MigratedSettings && !Present) + goto done; + + Success = RequestReboot(DeviceInfoSet, DeviceInfoData); + if (!Success) + goto fail7; + +done: + free(Location); + free(Description); + + Log("<===="); + + return NO_ERROR; + +fail7: + Log("fail7"); + +fail6: + Log("fail6"); + +fail5: + Log("fail5"); + +fail4: + Log("fail4"); + + free(Location); + +fail3: + Log("fail3"); + + free(Description); + +fail2: + Log("fail2"); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return Error; +} + +static DECLSPEC_NOINLINE HRESULT +DifInstall( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PCOINSTALLER_CONTEXT_DATA Context + ) +{ + SP_DEVINSTALL_PARAMS DeviceInstallParams; + HRESULT Error; + + DeviceInstallParams.cbSize = sizeof (DeviceInstallParams); + + if (!SetupDiGetDeviceInstallParams(DeviceInfoSet, + DeviceInfoData, + &DeviceInstallParams)) + goto fail1; + + Log("Flags = %08x", DeviceInstallParams.Flags); + + Error = (!Context->PostProcessing) ? + __DifInstallPreProcess(DeviceInfoSet, DeviceInfoData, Context) : + __DifInstallPostProcess(DeviceInfoSet, DeviceInfoData, Context); + + return Error; + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return Error; +} + +static FORCEINLINE HRESULT +__DifRemovePreProcess( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PCOINSTALLER_CONTEXT_DATA Context + ) +{ + PTCHAR Location; + HRESULT Error; + + Log("====>"); + + Location = GetProperty(DeviceInfoSet, DeviceInfoData, SPDRP_LOCATION_INFORMATION); + if (Location == NULL) + goto fail1; + + Context->PrivateData = Location; + + (VOID) __MigrateToEmulated(DeviceInfoSet, DeviceInfoData, Location); + (VOID) __MigrateToPV(DeviceInfoSet, DeviceInfoData, Location); + + Log("<===="); + + return ERROR_DI_POSTPROCESSING_REQUIRED; + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return Error; +} + +static FORCEINLINE HRESULT +__DifRemovePostProcess( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PCOINSTALLER_CONTEXT_DATA Context + ) +{ + HRESULT Error; + PTCHAR Location; + PEMULATED_DEVICE Table; + BOOLEAN Success; + + Log("====>"); + + Error = Context->InstallResult; + if (Error != NO_ERROR) { + SetLastError(Error); + goto fail1; + } + + Location = Context->PrivateData; + + Success = RemoveDevice("VIF", Location); + if (!Success) + goto fail2; + + Table = GetEmulatedDeviceTable(); + if (Table == NULL) { + Success = FALSE; + } else { + ULONG Index; + + Success = TRUE; + + for (Index = 0; strlen(Table[Index].Alias) != 0; Index++) { + if (_stricmp(Location, Table[Index].Device) == 0) { + Success = RequestReboot(DeviceInfoSet, DeviceInfoData); + break; + } + } + + free(Table); + } + + if (!Success) + goto fail3; + + free(Location); + + Log("<===="); + + return NO_ERROR; + +fail3: + Log("fail3"); + +fail2: + Log("fail2"); + + free(Location); + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return Error; +} + +static DECLSPEC_NOINLINE HRESULT +DifRemove( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PCOINSTALLER_CONTEXT_DATA Context + ) +{ + SP_DEVINSTALL_PARAMS DeviceInstallParams; + HRESULT Error; + + DeviceInstallParams.cbSize = sizeof (DeviceInstallParams); + + if (!SetupDiGetDeviceInstallParams(DeviceInfoSet, + DeviceInfoData, + &DeviceInstallParams)) + goto fail1; + + Log("Flags = %08x", DeviceInstallParams.Flags); + + Error = (!Context->PostProcessing) ? + __DifRemovePreProcess(DeviceInfoSet, DeviceInfoData, Context) : + __DifRemovePostProcess(DeviceInfoSet, DeviceInfoData, Context); + + return Error; + +fail1: + Error = GetLastError(); + + { + PTCHAR Message; + + Message = GetErrorMessage(Error); + Log("fail1 (%s)", Message); + LocalFree(Message); + } + + return Error; +} + +DWORD CALLBACK +Entry( + IN DI_FUNCTION Function, + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PCOINSTALLER_CONTEXT_DATA Context + ) +{ + HRESULT Error; + + Log("%s (%s) ===>", + MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR, + DAY_STR "/" MONTH_STR "/" YEAR_STR); + + switch (Function) { + case DIF_INSTALLDEVICE: { + SP_DRVINFO_DATA DriverInfoData; + BOOLEAN DriverInfoAvailable; + + DriverInfoData.cbSize = sizeof (DriverInfoData); + DriverInfoAvailable = SetupDiGetSelectedDriver(DeviceInfoSet, + DeviceInfoData, + &DriverInfoData) ? + TRUE : + FALSE; + + // The NET class installer will call DIF_REMOVE even in the event of + // a NULL driver add, so we don't need to do it here. However, the + // default installer (for the NULL driver) fails for some reason so + // we squash the error in post-processing. + if (DriverInfoAvailable) { + Error = DifInstall(DeviceInfoSet, DeviceInfoData, Context); + } else { + if (!Context->PostProcessing) { + Log("%s PreProcessing", + FunctionName(Function)); + + Error = ERROR_DI_POSTPROCESSING_REQUIRED; + } else { + Log("%s PostProcessing (%08x)", + FunctionName(Function), + Context->InstallResult); + + Error = NO_ERROR; + } + } + break; + } + case DIF_REMOVE: + Error = DifRemove(DeviceInfoSet, DeviceInfoData, Context); + break; + default: + if (!Context->PostProcessing) { + Log("%s PreProcessing", + FunctionName(Function)); + + Error = NO_ERROR; + } else { + Log("%s PostProcessing (%08x)", + FunctionName(Function), + Context->InstallResult); + + Error = Context->InstallResult; + } + + break; + } + + Log("%s (%s) <===", + MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR, + DAY_STR "/" MONTH_STR "/" YEAR_STR); + + return (DWORD)Error; +} + +DWORD CALLBACK +Version( + IN HWND Window, + IN HINSTANCE Module, + IN PTCHAR Buffer, + IN INT Reserved + ) +{ + UNREFERENCED_PARAMETER(Window); + UNREFERENCED_PARAMETER(Module); + UNREFERENCED_PARAMETER(Buffer); + UNREFERENCED_PARAMETER(Reserved); + + Log("%s (%s)", + MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR, + DAY_STR "/" MONTH_STR "/" YEAR_STR); + + return NO_ERROR; +} + +static FORCEINLINE const CHAR * +__ReasonName( + IN DWORD Reason + ) +{ +#define _NAME(_Reason) \ + case DLL_ ## _Reason: \ + return #_Reason; + + switch (Reason) { + _NAME(PROCESS_ATTACH); + _NAME(PROCESS_DETACH); + _NAME(THREAD_ATTACH); + _NAME(THREAD_DETACH); + default: + break; + } + + return "UNKNOWN"; + +#undef _NAME +} + +BOOL WINAPI +DllMain( + IN HINSTANCE Module, + IN DWORD Reason, + IN PVOID Reserved + ) +{ + UNREFERENCED_PARAMETER(Module); + UNREFERENCED_PARAMETER(Reserved); + + Log("%s (%s): %s", + MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR, + DAY_STR "/" MONTH_STR "/" YEAR_STR, + __ReasonName(Reason)); + + return TRUE; +} diff --git a/src/coinst/xennet_coinst.def b/src/coinst/xennet_coinst.def new file mode 100644 index 0000000..bcdd28b --- /dev/null +++ b/src/coinst/xennet_coinst.def @@ -0,0 +1,37 @@ +; Copyright (c) Citrix Systems Inc. +; All rights reserved. +; +; Redistribution and use in source and binary forms, +; with or without modification, are permitted provided +; that the following conditions are met: +; +; * Redistributions of source code must retain the above +; copyright notice, this list of conditions and the +; following disclaimer. +; * Redistributions in binary form must reproduce the above +; copyright notice, this list of conditions and the +; following disclaimer in the documentation and/or other +; materials provided with the distribution. +; +; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +; CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +; INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +; SUCH DAMAGE. + +LIBRARY XENNET_COINST + +EXPORTS + Entry + Version + + DllMain PRIVATE diff --git a/src/xennet.inf b/src/xennet.inf new file mode 100644 index 0000000..51abf8a --- /dev/null +++ b/src/xennet.inf @@ -0,0 +1,185 @@ +; Copyright 2011 Citrix Systems Inc. All rights reserved. +; Use is subject to license terms. +; + +[Version] +Signature="$Windows NT$" +Class=Net +ClassGUID={4d36e972-e325-11ce-bfc1-08002be10318} +Provider=%Citrix% +CatalogFile=xennet.cat +DriverVer=01/01/1900,0.0.0.0 + +[DestinationDirs] +DefaultDestDir=12 +CoInst_CopyFiles=11 + +[SourceDisksNames] +0=%DiskDesc% + +[SourceDisksFiles] +xennet.sys=0,, +xennet_coinst.dll=0,, + +[XenNet_Copyfiles] +xennet.sys + +[CoInst_CopyFiles] +xennet_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll,xennet_coinst.dll + +[Manufacturer] +%Citrix%=Citrix,NT$ARCH$ + +[Citrix.NT$ARCH$] +%DriverDesc%=XenNet_Inst,XENVIF\DEVICE&REV_02 + +[XenNet_Inst] +Characteristics=0x84 +BusType=1 +*IfType=6 ; IF_TYPE_ETHERNET_CSMACD +*MediaType=0 ; NdisMedium802_3 +*PhysicalMediaType=0 ; NdisPhysicalMediumUnspecified +CopyFiles=XenNet_Copyfiles +AddReg=Xennet_Inst_AddReg + +[XenNet_Inst_AddReg] +HKR, Ndi, Service, 0, "xennet" +HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" +HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" + +HKR, Ndi\params\*IPChecksumOffloadIPv4, ParamDesc, 0, %IPChecksumOffloadIPv4% +HKR, Ndi\params\*IPChecksumOffloadIPv4, Type, 0, "enum" +HKR, Ndi\params\*IPChecksumOffloadIPv4, Default, 0, "3" +HKR, Ndi\params\*IPChecksumOffloadIPv4, Optional, 0, "0" +HKR, Ndi\params\*IPChecksumOffloadIPv4\enum, "0", 0, %Disabled% +HKR, Ndi\params\*IPChecksumOffloadIPv4\enum, "1", 0, %Enabled-Tx% +HKR, Ndi\params\*IPChecksumOffloadIPv4\enum, "2", 0, %Enabled-Rx% +HKR, Ndi\params\*IPChecksumOffloadIPv4\enum, "3", 0, %Enabled-TxRx% + +HKR, Ndi\params\*TCPChecksumOffloadIPv4, ParamDesc, 0, %TCPChecksumOffloadIPv4% +HKR, Ndi\params\*TCPChecksumOffloadIPv4, Type, 0, "enum" +HKR, Ndi\params\*TCPChecksumOffloadIPv4, Default, 0, "3" +HKR, Ndi\params\*TCPChecksumOffloadIPv4, Optional, 0, "0" +HKR, Ndi\params\*TCPChecksumOffloadIPv4\enum, "0", 0, %Disabled% +HKR, Ndi\params\*TCPChecksumOffloadIPv4\enum, "1", 0, %Enabled-Tx% +HKR, Ndi\params\*TCPChecksumOffloadIPv4\enum, "2", 0, %Enabled-Rx% +HKR, Ndi\params\*TCPChecksumOffloadIPv4\enum, "3", 0, %Enabled-TxRx% + +HKR, Ndi\params\*UDPChecksumOffloadIPv4, ParamDesc, 0, %UDPChecksumOffloadIPv4% +HKR, Ndi\params\*UDPChecksumOffloadIPv4, Type, 0, "enum" +HKR, Ndi\params\*UDPChecksumOffloadIPv4, Default, 0, "3" +HKR, Ndi\params\*UDPChecksumOffloadIPv4, Optional, 0, "0" +HKR, Ndi\params\*UDPChecksumOffloadIPv4\enum, "0", 0, %Disabled% +HKR, Ndi\params\*UDPChecksumOffloadIPv4\enum, "1", 0, %Enabled-Tx% +HKR, Ndi\params\*UDPChecksumOffloadIPv4\enum, "2", 0, %Enabled-Rx% +HKR, Ndi\params\*UDPChecksumOffloadIPv4\enum, "3", 0, %Enabled-TxRx% + +HKR, Ndi\params\*TCPChecksumOffloadIPv6, ParamDesc, 0, %TCPChecksumOffloadIPv6% +HKR, Ndi\params\*TCPChecksumOffloadIPv6, Type, 0, "enum" +HKR, Ndi\params\*TCPChecksumOffloadIPv6, Default, 0, "3" +HKR, Ndi\params\*TCPChecksumOffloadIPv6, Optional, 0, "0" +HKR, Ndi\params\*TCPChecksumOffloadIPv6\enum, "0", 0, %Disabled% +HKR, Ndi\params\*TCPChecksumOffloadIPv6\enum, "1", 0, %Enabled-Tx% +HKR, Ndi\params\*TCPChecksumOffloadIPv6\enum, "2", 0, %Enabled-Rx% +HKR, Ndi\params\*TCPChecksumOffloadIPv6\enum, "3", 0, %Enabled-TxRx% + +HKR, Ndi\params\*UDPChecksumOffloadIPv6, ParamDesc, 0, %UDPChecksumOffloadIPv6% +HKR, Ndi\params\*UDPChecksumOffloadIPv6, Type, 0, "enum" +HKR, Ndi\params\*UDPChecksumOffloadIPv6, Default, 0, "3" +HKR, Ndi\params\*UDPChecksumOffloadIPv6, Optional, 0, "0" +HKR, Ndi\params\*UDPChecksumOffloadIPv6\enum, "0", 0, %Disabled% +HKR, Ndi\params\*UDPChecksumOffloadIPv6\enum, "1", 0, %Enabled-Tx% +HKR, Ndi\params\*UDPChecksumOffloadIPv6\enum, "2", 0, %Enabled-Rx% +HKR, Ndi\params\*UDPChecksumOffloadIPv6\enum, "3", 0, %Enabled-TxRx% + +HKR, Ndi\params\NeedChecksumValue, ParamDesc, 0, %NeedChecksumValue% +HKR, Ndi\params\NeedChecksumValue, Type, 0, "enum" +HKR, Ndi\params\NeedChecksumValue, Default, 0, "1" +HKR, Ndi\params\NeedChecksumValue, Optional, 0, "0" +HKR, Ndi\params\NeedChecksumValue\enum, "0", 0, %Disabled% +HKR, Ndi\params\NeedChecksumValue\enum, "1", 0, %Enabled% + +HKR, Ndi\params\*LSOV2IPv4, ParamDesc, 0, %LSOV2IPv4% +HKR, Ndi\params\*LSOV2IPv4, Type, 0, "enum" +HKR, Ndi\params\*LSOV2IPv4, Default, 0, "1" +HKR, Ndi\params\*LSOV2IPv4, Optional, 0, "0" +HKR, Ndi\params\*LSOV2IPv4\enum, "0", 0, %Disabled% +HKR, Ndi\params\*LSOV2IPv4\enum, "1", 0, %Enabled% + +HKR, Ndi\params\*LSOV2IPv6, ParamDesc, 0, %LSOV2IPv6% +HKR, Ndi\params\*LSOV2IPv6, Type, 0, "enum" +HKR, Ndi\params\*LSOV2IPv6, Default, 0, "1" +HKR, Ndi\params\*LSOV2IPv6, Optional, 0, "0" +HKR, Ndi\params\*LSOV2IPv6\enum, "0", 0, %Disabled% +HKR, Ndi\params\*LSOV2IPv6\enum, "1", 0, %Enabled% + +HKR, Ndi\params\LROIPv4, ParamDesc, 0, %LROIPv4% +HKR, Ndi\params\LROIPv4, Type, 0, "enum" +HKR, Ndi\params\LROIPv4, Default, 0, "1" +HKR, Ndi\params\LROIPv4, Optional, 0, "0" +HKR, Ndi\params\LROIPv4\enum, "0", 0, %Disabled% +HKR, Ndi\params\LROIPv4\enum, "1", 0, %Enabled% + +HKR, Ndi\params\LROIPv6, ParamDesc, 0, %LROIPv6% +HKR, Ndi\params\LROIPv6, Type, 0, "enum" +HKR, Ndi\params\LROIPv6, Default, 0, "1" +HKR, Ndi\params\LROIPv6, Optional, 0, "0" +HKR, Ndi\params\LROIPv6\enum, "0", 0, %Disabled% +HKR, Ndi\params\LROIPv6\enum, "1", 0, %Enabled% + +[XenNet_Inst.Services] +AddService=xennet,0x02,XenNet_Service,XenNet_EventLog + +[XenNet_Service] +ServiceType=%SERVICE_KERNEL_DRIVER% +StartType=%SERVICE_DEMAND_START% +ErrorControl=%SERVICE_ERROR_NORMAL% +ServiceBinary=%12%\xennet.sys +LoadOrderGroup="NDIS" + +[XenNet_EventLog] +AddReg=XenNet_EventLog_AddReg + +[XenNet_EventLog_AddReg] +HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\netevent.dll" +HKR,,TypesSupported,0x00010001,7 + +[XenNet_Inst.CoInstallers] +CopyFiles=CoInst_CopyFiles +AddReg=CoInst_AddReg + +[CoInst_AddReg] +HKR,,CoInstallers32,0x00010000,"xennet_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll,Entry" + +[Strings] + +Citrix="Citrix Systems Inc." +DiskDesc="Citrix Tools for Virtual Machines" +DriverDesc="Citrix PV Network Adapter" +IPChecksumOffloadIPv4="IPv4 Checksum Offload" +TCPChecksumOffloadIPv4="TCP Checksum Offload (IPv4)" +UDPChecksumOffloadIPv4="UDP Checksum Offload (IPv4)" +TCPChecksumOffloadIPv6="TCP Checksum Offload (IPv6)" +UDPChecksumOffloadIPv6="UDP Checksum Offload (IPv6)" +NeedChecksumValue="Correct TCP/UDP Checksum Value" +LSOV2IPv4="Large Send Offload V2 (IPv4)" +LSOV2IPv6="Large Send Offload V2 (IPv6)" +LROIPv4="Large Receive Offload (IPv4)" +LROIPv6="Large Receive Offload (IPv6)" +Disabled="Disabled" +Enabled="Enabled" +Enabled-Rx="Rx Enabled" +Enabled-Tx="Tx Enabled" +Enabled-TxRx="Rx & Tx Enabled" + +SERVICE_BOOT_START=0x0 +SERVICE_SYSTEM_START=0x1 +SERVICE_AUTO_START=0x2 +SERVICE_DEMAND_START=0x3 +SERVICE_DISABLED=0x4 + +SERVICE_KERNEL_DRIVER=0x1 +SERVICE_ERROR_IGNORE=0x0 +SERVICE_ERROR_NORMAL=0x1 +SERVICE_ERROR_SEVERE=0x2 +SERVICE_ERROR_CRITICAL=0x3 diff --git a/src/xennet/adapter.c b/src/xennet/adapter.c new file mode 100644 index 0000000..496853a --- /dev/null +++ b/src/xennet/adapter.c @@ -0,0 +1,2402 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include "common.h" + +#pragma warning(disable:4711) + +// +// List of supported OIDs. +// + +static NDIS_STATUS +AdapterStop ( + IN PADAPTER Adapter + ); + +static NDIS_STATUS +AdapterSetRegistrationAttributes ( + IN PADAPTER Adapter + ); + +static NDIS_STATUS +AdapterSetGeneralAttributes ( + IN PADAPTER Adapter + ); + +static NDIS_STATUS +AdapterSetOffloadAttributes ( + IN PADAPTER Adapter + ); + +static VOID +AdapterProcessSGList ( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Reserved, + IN PSCATTER_GATHER_LIST SGL, + IN PVOID Context + ); + +static NDIS_STATUS +AdapterSetInformation ( + IN PADAPTER Adapter, + IN PNDIS_OID_REQUEST NdisRequest + ); + +static NDIS_STATUS +AdapterQueryInformation ( + IN PADAPTER Adapter, + IN PNDIS_OID_REQUEST NdisRequest + ); + +static NDIS_OID XennetSupportedOids[] = +{ + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_PHYSICAL_MEDIUM, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_MAXIMUM_LOOKAHEAD, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_MAC_OPTIONS, + OID_GEN_LINK_SPEED, + OID_GEN_MEDIA_CONNECT_STATUS, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_DRIVER_VERSION, + OID_GEN_MAXIMUM_SEND_PACKETS, + OID_GEN_VENDOR_ID, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_CRC_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_GEN_TRANSMIT_QUEUE_LENGTH, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_STATISTICS, + OID_GEN_DIRECTED_BYTES_XMIT, + OID_GEN_DIRECTED_FRAMES_XMIT, + OID_GEN_MULTICAST_BYTES_XMIT, + OID_GEN_MULTICAST_FRAMES_XMIT, + OID_GEN_BROADCAST_BYTES_XMIT, + OID_GEN_BROADCAST_FRAMES_XMIT, + OID_GEN_DIRECTED_BYTES_RCV, + OID_GEN_DIRECTED_FRAMES_RCV, + OID_GEN_MULTICAST_BYTES_RCV, + OID_GEN_MULTICAST_FRAMES_RCV, + OID_GEN_BROADCAST_BYTES_RCV, + OID_GEN_BROADCAST_FRAMES_RCV, + OID_GEN_INTERRUPT_MODERATION, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, + OID_OFFLOAD_ENCAPSULATION, + OID_TCP_OFFLOAD_PARAMETERS, + OID_PNP_CAPABILITIES, + OID_PNP_QUERY_POWER, + OID_PNP_SET_POWER, +}; + +#define INITIALIZE_NDIS_OBJ_HEADER(obj, type) do { \ + (obj).Header.Type = NDIS_OBJECT_TYPE_ ## type ; \ + (obj).Header.Revision = NDIS_ ## type ## _REVISION_1; \ + (obj).Header.Size = sizeof(obj); \ +} while (0) + +// +// Scatter gather allocate handler callback. +// Should never get called. +// +static VOID +AdapterAllocateComplete ( + IN NDIS_HANDLE MiniportAdapterContext, + IN PVOID VirtualAddress, + IN PNDIS_PHYSICAL_ADDRESS PhysicalAddress, + IN ULONG Length, + IN PVOID Context + ) +{ + UNREFERENCED_PARAMETER(MiniportAdapterContext); + UNREFERENCED_PARAMETER(VirtualAddress); + UNREFERENCED_PARAMETER(PhysicalAddress); + UNREFERENCED_PARAMETER(Length); + UNREFERENCED_PARAMETER(Context); + + ASSERT(FALSE); + + return; +} + +// +// Required NDIS6 handler. +// Should never get called. +// +VOID +AdapterCancelOidRequest ( + IN PADAPTER Adapter, + IN PVOID RequestId + ) +{ + UNREFERENCED_PARAMETER(Adapter); + UNREFERENCED_PARAMETER(RequestId); + + return; +} + +// +// Required NDIS6 handler. +// Should never get called. +// + +VOID +AdapterCancelSendNetBufferLists ( + IN PADAPTER Adapter, + IN PVOID CancelId + ) +{ + UNREFERENCED_PARAMETER(Adapter); + UNREFERENCED_PARAMETER(CancelId); + + return; +} + +BOOLEAN +AdapterCheckForHang ( + IN PADAPTER Adapter + ) +{ + UNREFERENCED_PARAMETER(Adapter); + + return FALSE; +} + +// +// Frees resources obtained by AdapterInitialize. +// +static VOID +AdapterCleanup ( + IN PADAPTER Adapter + ) +{ + Trace("====>\n"); + + TransmitterDelete(&Adapter->Transmitter); + ReceiverCleanup(&Adapter->Receiver); + + if (Adapter->NdisDmaHandle != NULL) + NdisMDeregisterScatterGatherDma(Adapter->NdisDmaHandle); + + if (Adapter->AcquiredInterfaces) { + VIF(Release, Adapter->VifInterface); + Adapter->VifInterface = NULL; + } + + Trace("<====\n"); + return; +} + +// +// Frees adapter storage. +// +VOID +AdapterDelete ( + IN OUT PADAPTER* Adapter + ) +{ + ASSERT(Adapter != NULL); + + if (*Adapter) { + AdapterCleanup(*Adapter); + ExFreePool(*Adapter); + *Adapter = NULL; + } + + return; +} + +// +// Stops adapter and frees all resources. +// +VOID +AdapterHalt ( + IN PADAPTER Adapter, + IN NDIS_HALT_ACTION HaltAction + ) +{ + NDIS_STATUS ndisStatus; + + UNREFERENCED_PARAMETER(HaltAction); + + + ndisStatus = AdapterStop(Adapter); + if (ndisStatus == NDIS_STATUS_SUCCESS) { + AdapterDelete(&Adapter); + } + + return; +} + +static VOID +AdapterMediaStateChange( + IN PADAPTER Adapter + ) +{ + NDIS_LINK_STATE LinkState; + NDIS_STATUS_INDICATION StatusIndication; + + NdisZeroMemory(&LinkState, sizeof (NDIS_LINK_STATE)); + + LinkState.Header.Revision = NDIS_LINK_STATE_REVISION_1; + LinkState.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + LinkState.Header.Size = sizeof(NDIS_LINK_STATE); + + VIF(QueryMediaState, + Adapter->VifInterface, + &LinkState.MediaConnectState, + &LinkState.RcvLinkSpeed, + &LinkState.MediaDuplexState); + + if (LinkState.MediaConnectState == MediaConnectStateUnknown) { + Info("LINK: STATE UNKNOWN\n"); + } else if (LinkState.MediaConnectState == MediaConnectStateDisconnected) { + Info("LINK: DOWN\n"); + } else { + ASSERT3U(LinkState.MediaConnectState, ==, MediaConnectStateConnected); + + if (LinkState.MediaDuplexState == MediaDuplexStateHalf) + Info("LINK: UP: SPEED=%u DUPLEX=HALF\n", LinkState.RcvLinkSpeed); + else if (LinkState.MediaDuplexState == MediaDuplexStateFull) + Info("LINK: UP: SPEED=%u DUPLEX=FULL\n", LinkState.RcvLinkSpeed); + else + Info("LINK: UP: SPEED=%u DUPLEX=UNKNOWN\n", LinkState.RcvLinkSpeed); + } + + LinkState.XmitLinkSpeed = LinkState.RcvLinkSpeed; + + NdisZeroMemory(&StatusIndication, sizeof (NDIS_STATUS_INDICATION)); + + StatusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION; + StatusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1; + StatusIndication.Header.Size = sizeof (NDIS_STATUS_INDICATION); + StatusIndication.SourceHandle = Adapter->NdisAdapterHandle; + StatusIndication.StatusCode = NDIS_STATUS_LINK_STATE; + StatusIndication.StatusBuffer = &LinkState; + StatusIndication.StatusBufferSize = sizeof (NDIS_LINK_STATE); + + NdisMIndicateStatusEx(Adapter->NdisAdapterHandle, &StatusIndication); +} + + +// +// Initializes adapter by allocating required resources and connects to +// netback. +// + +static VOID +AdapterVifCallback( + IN PVOID Context, + IN XENVIF_CALLBACK_TYPE Type, + ...) +{ + PADAPTER Adapter = Context; + va_list Arguments; + + va_start(Arguments, Type); + + switch (Type) { + case XENVIF_CALLBACK_COMPLETE_PACKETS: { + PXENVIF_TRANSMITTER_PACKET HeadPacket; + + HeadPacket = va_arg(Arguments, PXENVIF_TRANSMITTER_PACKET); + + TransmitterCompletePackets(Adapter->Transmitter, HeadPacket); + break; + } + case XENVIF_CALLBACK_RECEIVE_PACKETS: { + PLIST_ENTRY List; + + List = va_arg(Arguments, PLIST_ENTRY); + + ReceiverReceivePackets(&Adapter->Receiver, List); + break; + } + case XENVIF_CALLBACK_MEDIA_STATE_CHANGE: { + AdapterMediaStateChange(Adapter); + break; + } + } + + va_end(Arguments); +} + +NDIS_STATUS +AdapterGetAdvancedSettings( + IN PADAPTER pAdapter + ) +{ + NDIS_CONFIGURATION_OBJECT configObject; + NDIS_HANDLE hConfigurationHandle; + NDIS_STRING ndisValue; + PNDIS_CONFIGURATION_PARAMETER pNdisData; + NDIS_STATUS ndisStatus; + NTSTATUS status; + + configObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT; + configObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1; + configObject.Header.Size = NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1; + configObject.NdisHandle = pAdapter->NdisAdapterHandle; + configObject.Flags = 0; + + ndisStatus = NdisOpenConfigurationEx(&configObject, &hConfigurationHandle); + + status = STATUS_UNSUCCESSFUL; + if (ndisStatus != NDIS_STATUS_SUCCESS) + goto fail1; + +#define read_property(field, name, default_val) \ + do { \ + RtlInitUnicodeString(&ndisValue, name); \ + NdisReadConfiguration(&ndisStatus, &pNdisData, hConfigurationHandle, &ndisValue, NdisParameterInteger); \ + if (ndisStatus == NDIS_STATUS_SUCCESS) { \ + pAdapter->Properties.field = pNdisData->ParameterData.IntegerData; \ + } else { \ + pAdapter->Properties.field = default_val; \ + } \ + } while (FALSE); + + read_property(ipv4_csum, L"*IPChecksumOffloadIPv4", 3); + read_property(tcpv4_csum, L"*TCPChecksumOffloadIPv4", 3); + read_property(udpv4_csum, L"*UDPChecksumOffloadIPv4", 3); + read_property(tcpv6_csum, L"*TCPChecksumOffloadIPv6", 3); + read_property(udpv6_csum, L"*UDPChecksumOffloadIPv6", 3); + read_property(lsov4, L"*LSOv2IPv4", 1); + read_property(lsov6, L"*LSOv2IPv6", 1); + read_property(lrov4, L"LROIPv4", 1); + read_property(lrov6, L"LROIPv6", 1); + read_property(need_csum_value, L"NeedChecksumValue", 1); + + NdisCloseConfiguration(hConfigurationHandle); + + return NDIS_STATUS_SUCCESS; + +fail1: + Error("fail1\n"); + return NDIS_STATUS_FAILURE; +} + +NDIS_STATUS +AdapterInitialize ( + IN PADAPTER Adapter, + IN NDIS_HANDLE AdapterHandle + ) +{ + NDIS_STATUS ndisStatus; + NDIS_SG_DMA_DESCRIPTION DmaDescription; + NTSTATUS status; + + Trace("====>\n"); + + Adapter->NdisAdapterHandle = AdapterHandle; + + RtlZeroMemory(&Adapter->Capabilities, sizeof (Adapter->Capabilities)); + + Adapter->Transmitter = ExAllocatePoolWithTag(NonPagedPool, sizeof(TRANSMITTER), ' TEN'); + if (!Adapter->Transmitter) { + ndisStatus = NDIS_STATUS_RESOURCES; + goto exit; + } + + RtlZeroMemory(Adapter->Transmitter, sizeof (TRANSMITTER)); + + ndisStatus = ReceiverInitialize(&Adapter->Receiver); + if (ndisStatus != NDIS_STATUS_SUCCESS) { + goto exit; + } + + ndisStatus = TransmitterInitialize(Adapter->Transmitter, Adapter); + if (ndisStatus != NDIS_STATUS_SUCCESS) { + goto exit; + } + + ndisStatus = AdapterGetAdvancedSettings(Adapter); + if (ndisStatus != NDIS_STATUS_SUCCESS) { + goto exit; + } + + ndisStatus = AdapterSetRegistrationAttributes(Adapter); + if (ndisStatus != NDIS_STATUS_SUCCESS) { + goto exit; + } + + ndisStatus = AdapterSetGeneralAttributes(Adapter); + if (ndisStatus != NDIS_STATUS_SUCCESS) { + goto exit; + } + + ndisStatus = AdapterSetOffloadAttributes(Adapter); + if (ndisStatus != NDIS_STATUS_SUCCESS) { + goto exit; + } + + NdisZeroMemory(&DmaDescription, sizeof(DmaDescription)); + + DmaDescription.Header.Type = NDIS_OBJECT_TYPE_SG_DMA_DESCRIPTION; + DmaDescription.Header.Revision = NDIS_SG_DMA_DESCRIPTION_REVISION_1; + DmaDescription.Header.Size = sizeof(NDIS_SG_DMA_DESCRIPTION); + DmaDescription.Flags = NDIS_SG_DMA_64_BIT_ADDRESS; + DmaDescription.MaximumPhysicalMapping = 65536; + DmaDescription.ProcessSGListHandler = AdapterProcessSGList; + DmaDescription.SharedMemAllocateCompleteHandler = AdapterAllocateComplete; + + ndisStatus = NdisMRegisterScatterGatherDma(Adapter->NdisAdapterHandle, + &DmaDescription, + &Adapter->NdisDmaHandle); + if (ndisStatus != NDIS_STATUS_SUCCESS) + Adapter->NdisDmaHandle = NULL; + + ASSERT(!Adapter->Enabled); + VIF(Acquire, Adapter->VifInterface); + + status = VIF(Enable, + Adapter->VifInterface, + AdapterVifCallback, + Adapter); + if (NT_SUCCESS(status)) { + TransmitterEnable(Adapter->Transmitter); + Adapter->Enabled = TRUE; + ndisStatus = NDIS_STATUS_SUCCESS; + } else { + ndisStatus = NDIS_STATUS_FAILURE; + } + +exit: + Trace("<==== (%08x)\n", ndisStatus); + return ndisStatus; +} + +// +// Scatter gather process handler callback. +// Should never get called. +// +static VOID +AdapterProcessSGList ( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Reserved, + IN PSCATTER_GATHER_LIST SGL, + IN PVOID Context + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Reserved); + UNREFERENCED_PARAMETER(SGL); + UNREFERENCED_PARAMETER(Context); + + ASSERT(FALSE); + + return; +} + +// +// Get\Set OID handler. +// +NDIS_STATUS +AdapterOidRequest ( + IN PADAPTER Adapter, + IN PNDIS_OID_REQUEST NdisRequest + ) +{ + NDIS_STATUS ndisStatus; + + UNREFERENCED_PARAMETER(Adapter); + UNREFERENCED_PARAMETER(NdisRequest); + + switch (NdisRequest->RequestType) { + case NdisRequestSetInformation: + ndisStatus = AdapterSetInformation(Adapter, NdisRequest); + break; + + case NdisRequestQueryInformation: + case NdisRequestQueryStatistics: + ndisStatus = AdapterQueryInformation(Adapter, NdisRequest); + break; + + default: + ndisStatus = NDIS_STATUS_NOT_SUPPORTED; + break; + }; + + return ndisStatus; +} + +// +// Temporarily pauses adapter. +// +NDIS_STATUS +AdapterPause ( + IN PADAPTER Adapter, + IN PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters + ) +{ + UNREFERENCED_PARAMETER(MiniportPauseParameters); + + Trace("====>\n"); + + if (!Adapter->Enabled) + goto done; + + VIF(Disable, + Adapter->VifInterface); + + AdapterMediaStateChange(Adapter); + + Adapter->Enabled = FALSE; + +done: + Trace("<====\n"); + return NDIS_STATUS_SUCCESS; +} + +// +// Handles PNP and Power events. NOP. +// +VOID +AdapterPnPEventHandler ( + IN PADAPTER Adapter, + IN PNET_DEVICE_PNP_EVENT NetDevicePnPEvent + ) +{ + UNREFERENCED_PARAMETER(Adapter); + + + switch (NetDevicePnPEvent->DevicePnPEvent) { + case NdisDevicePnPEventQueryRemoved: + break; + + case NdisDevicePnPEventRemoved: + break; + + case NdisDevicePnPEventSurpriseRemoved: + break; + + case NdisDevicePnPEventQueryStopped: + break; + + case NdisDevicePnPEventStopped: + break; + + case NdisDevicePnPEventPowerProfileChanged: + break; + + default: + break; + }; + + return; +} + +// +// Reports general statistics to NDIS. +// +static NDIS_STATUS +AdapterQueryGeneralStatistics ( + IN PADAPTER Adapter, + IN PNDIS_STATISTICS_INFO NdisStatisticsInfo + ) +{ + NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + NdisZeroMemory(NdisStatisticsInfo, sizeof(NDIS_STATISTICS_INFO)); + NdisStatisticsInfo->Header.Revision = NDIS_OBJECT_REVISION_1; + NdisStatisticsInfo->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + NdisStatisticsInfo->Header.Size = sizeof(NDIS_STATISTICS_INFO); + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR; + NdisStatisticsInfo->ifInErrors = + Statistics.Receiver.BackendError + + Statistics.Receiver.FrontendError; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS; + NdisStatisticsInfo->ifInDiscards = Statistics.Receiver.Drop; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV; + NdisStatisticsInfo->ifHCInOctets = Statistics.Receiver.UnicastBytes + + Statistics.Receiver.MulticastBytes + + Statistics.Receiver.BroadcastBytes; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV; + NdisStatisticsInfo->ifHCInUcastOctets = Statistics.Receiver.UnicastBytes; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV; + NdisStatisticsInfo->ifHCInUcastPkts = Statistics.Receiver.Unicast; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV; + NdisStatisticsInfo->ifHCInMulticastOctets = Statistics.Receiver.MulticastBytes; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV; + NdisStatisticsInfo->ifHCInMulticastPkts = Statistics.Receiver.Multicast; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV; + NdisStatisticsInfo->ifHCInBroadcastOctets = Statistics.Receiver.BroadcastBytes; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV; + NdisStatisticsInfo->ifHCInBroadcastPkts = Statistics.Receiver.Broadcast; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR; + NdisStatisticsInfo->ifOutErrors = + Statistics.Transmitter.BackendError + + Statistics.Transmitter.FrontendError; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT; + NdisStatisticsInfo->ifHCOutOctets = Statistics.Transmitter.UnicastBytes + + Statistics.Transmitter.MulticastBytes + + Statistics.Transmitter.BroadcastBytes; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT; + NdisStatisticsInfo->ifHCOutUcastOctets = Statistics.Transmitter.UnicastBytes; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT; + NdisStatisticsInfo->ifHCOutUcastPkts = Statistics.Transmitter.Unicast; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT; + NdisStatisticsInfo->ifHCOutMulticastOctets = Statistics.Transmitter.MulticastBytes; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT; + NdisStatisticsInfo->ifHCOutMulticastPkts = Statistics.Transmitter.MulticastBytes; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT; + NdisStatisticsInfo->ifHCOutBroadcastOctets = Statistics.Transmitter.BroadcastBytes; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT; + NdisStatisticsInfo->ifHCOutBroadcastPkts = Statistics.Transmitter.Broadcast; + + NdisStatisticsInfo->SupportedStatistics |= NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS; + NdisStatisticsInfo->ifOutDiscards = 0; + + return ndisStatus; +} + +static VOID +GetPacketFilter(PADAPTER Adapter, PULONG PacketFilter) +{ + XENVIF_MAC_FILTER_LEVEL UnicastFilterLevel; + XENVIF_MAC_FILTER_LEVEL MulticastFilterLevel; + XENVIF_MAC_FILTER_LEVEL BroadcastFilterLevel; + + VIF(QueryFilterLevel, + Adapter->VifInterface, + ETHERNET_ADDRESS_UNICAST, + &UnicastFilterLevel); + + VIF(QueryFilterLevel, + Adapter->VifInterface, + ETHERNET_ADDRESS_MULTICAST, + &MulticastFilterLevel); + + VIF(QueryFilterLevel, + Adapter->VifInterface, + ETHERNET_ADDRESS_BROADCAST, + &BroadcastFilterLevel); + + *PacketFilter = 0; + + if (UnicastFilterLevel == MAC_FILTER_ALL) { + ASSERT3U(MulticastFilterLevel, ==, MAC_FILTER_ALL); + ASSERT3U(BroadcastFilterLevel, ==, MAC_FILTER_ALL); + + *PacketFilter |= NDIS_PACKET_TYPE_PROMISCUOUS; + return; + } else if (UnicastFilterLevel == MAC_FILTER_MATCHING) { + *PacketFilter |= NDIS_PACKET_TYPE_DIRECTED; + } + + if (MulticastFilterLevel == MAC_FILTER_ALL) + *PacketFilter |= NDIS_PACKET_TYPE_ALL_MULTICAST; + else if (MulticastFilterLevel == MAC_FILTER_MATCHING) + *PacketFilter |= NDIS_PACKET_TYPE_MULTICAST; + + if (BroadcastFilterLevel == MAC_FILTER_ALL) + *PacketFilter |= NDIS_PACKET_TYPE_BROADCAST; +} + +#define MIN(_x, _y) (((_x) < (_y)) ? (_x) : (_y)) + +// +// Handles OID queries. +// +static NDIS_STATUS +AdapterQueryInformation ( + IN PADAPTER Adapter, + IN PNDIS_OID_REQUEST NdisRequest + ) +{ + ULONG bytesAvailable = 0; + ULONG bytesNeeded = 0; + ULONG bytesWritten = 0; + BOOLEAN doCopy = TRUE; + PVOID info = NULL; + ULONGLONG infoData; + ULONG informationBufferLength; + PVOID informationBuffer; + NDIS_INTERRUPT_MODERATION_PARAMETERS intModParams; + NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; + NDIS_OID oid; + + informationBuffer = NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + informationBufferLength = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength; + oid = NdisRequest->DATA.QUERY_INFORMATION.Oid; + switch (oid) { + case OID_PNP_CAPABILITIES: + Trace("PNP_CAPABILITIES\n"); + + info = &Adapter->Capabilities; + bytesAvailable = sizeof(Adapter->Capabilities); + break; + + case OID_PNP_QUERY_POWER: + Trace("QUERY_POWER\n"); + + bytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE); + if (informationBufferLength >= bytesNeeded) { + PNDIS_DEVICE_POWER_STATE state; + + state = (PNDIS_DEVICE_POWER_STATE)informationBuffer; + switch (*state) { + case NdisDeviceStateD0: + Trace("D0\n"); + break; + + case NdisDeviceStateD1: + Trace("D1\n"); + break; + + case NdisDeviceStateD2: + Trace("D2\n"); + break; + + case NdisDeviceStateD3: + Trace("D3\n"); + break; + } + } + break; + + case OID_GEN_SUPPORTED_LIST: + info = &XennetSupportedOids[0]; + bytesAvailable = sizeof(XennetSupportedOids); + break; + + case OID_GEN_HARDWARE_STATUS: + infoData = NdisHardwareStatusReady; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + infoData = XENNET_MEDIA_TYPE; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + infoData = Adapter->MaximumFrameSize; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + VIF(QueryTransmitterRingSize, + Adapter->VifInterface, + (PULONG)&infoData); + infoData *= Adapter->MaximumFrameSize; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + VIF(QueryTransmitterRingSize, + Adapter->VifInterface, + (PULONG)&infoData); + infoData *= Adapter->MaximumFrameSize; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + infoData = Adapter->MaximumFrameSize; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_VENDOR_DESCRIPTION: + info = "Citrix"; + bytesAvailable = (ULONG)strlen(info) + 1; + break; + + case OID_GEN_VENDOR_DRIVER_VERSION: + infoData = ((MAJOR_VERSION << 8) | MINOR_VERSION) << 8; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_DRIVER_VERSION: + infoData = (6 << 8) | 0; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_MAC_OPTIONS: + infoData = XENNET_MAC_OPTIONS; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_STATISTICS: + doCopy = FALSE; + + bytesAvailable = sizeof(NDIS_STATISTICS_INFO); + if (informationBufferLength >= bytesAvailable) { + ndisStatus = AdapterQueryGeneralStatistics(Adapter, + informationBuffer); + + } + + break; + + case OID_802_3_MULTICAST_LIST: { + ULONG Count; + + doCopy = FALSE; + + VIF(QueryMulticastAddresses, + Adapter->VifInterface, + NULL, + &Count); + bytesAvailable = Count * ETHERNET_ADDRESS_LENGTH; + + if (informationBufferLength >= bytesAvailable) { + NTSTATUS status; + + status = VIF(QueryMulticastAddresses, + Adapter->VifInterface, + informationBuffer, + &Count); + if (!NT_SUCCESS(status)) + ndisStatus = NDIS_STATUS_FAILURE; + } + + break; + } + case OID_802_3_PERMANENT_ADDRESS: + VIF(QueryPermanentAddress, + Adapter->VifInterface, + (PETHERNET_ADDRESS)&infoData); + info = &infoData; + bytesAvailable = ETH_LENGTH_OF_ADDRESS; + break; + + case OID_802_3_CURRENT_ADDRESS: + VIF(QueryCurrentAddress, + Adapter->VifInterface, + (PETHERNET_ADDRESS)&infoData); + info = &infoData; + bytesAvailable = ETH_LENGTH_OF_ADDRESS; + break; + + case OID_GEN_MAXIMUM_FRAME_SIZE: + infoData = Adapter->MaximumFrameSize - sizeof (ETHERNET_HEADER); + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + case OID_GEN_MAXIMUM_TOTAL_SIZE: { + infoData = Adapter->MaximumFrameSize - 4; + + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_CURRENT_LOOKAHEAD: + infoData = Adapter->CurrentLookahead; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_VENDOR_ID: + infoData = 0x5853; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_LINK_SPEED: { + ULONG64 LinkSpeed; + + VIF(QueryMediaState, + Adapter->VifInterface, + NULL, + &LinkSpeed, + NULL); + + infoData = (ULONG)(LinkSpeed / 100); + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_MEDIA_CONNECT_STATUS: { + NET_IF_MEDIA_CONNECT_STATE MediaConnectState; + + VIF(QueryMediaState, + Adapter->VifInterface, + &MediaConnectState, + NULL, + NULL); + + infoData = (MediaConnectState != MediaConnectStateDisconnected) ? + NdisMediaStateConnected : + NdisMediaStateDisconnected; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_MAXIMUM_SEND_PACKETS: + infoData = 16; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + GetPacketFilter(Adapter, (PULONG)&infoData); + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_XMIT_OK: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = Statistics.Transmitter.Unicast + + Statistics.Transmitter.Multicast + + Statistics.Transmitter.Broadcast; + + info = &infoData; + bytesAvailable = sizeof(ULONGLONG); + break; + } + case OID_GEN_RCV_OK: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = Statistics.Receiver.Unicast + + Statistics.Receiver.Multicast + + Statistics.Receiver.Broadcast; + + info = &infoData; + bytesAvailable = sizeof(ULONGLONG); + break; + } + case OID_GEN_XMIT_ERROR: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)(Statistics.Transmitter.BackendError + + Statistics.Transmitter.FrontendError); + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_RCV_ERROR: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)(Statistics.Receiver.BackendError + + Statistics.Receiver.FrontendError); + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_RCV_NO_BUFFER: + infoData = 0; // We'd need to query VIF TX drop stats from dom0 + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + infoData = 0; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + infoData = MAXIMUM_MULTICAST_ADDRESS_COUNT; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_IP4_OFFLOAD_STATS: + case OID_IP6_OFFLOAD_STATS: + case OID_GEN_SUPPORTED_GUIDS: + ndisStatus = NDIS_STATUS_NOT_SUPPORTED; + break; + + case OID_GEN_RCV_CRC_ERROR: + infoData = 0; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_802_3_RCV_ERROR_ALIGNMENT: + case OID_802_3_XMIT_ONE_COLLISION: + case OID_802_3_XMIT_MORE_COLLISIONS: + infoData = 0; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + + case OID_GEN_DIRECTED_BYTES_XMIT: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Transmitter.UnicastBytes; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_DIRECTED_FRAMES_XMIT: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Transmitter.Unicast; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_MULTICAST_BYTES_XMIT: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Transmitter.MulticastBytes; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_MULTICAST_FRAMES_XMIT: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Transmitter.Multicast; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_BROADCAST_BYTES_XMIT: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Transmitter.BroadcastBytes; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_BROADCAST_FRAMES_XMIT: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Transmitter.Broadcast; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_DIRECTED_BYTES_RCV: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Receiver.UnicastBytes; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_DIRECTED_FRAMES_RCV: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Receiver.Unicast; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_MULTICAST_BYTES_RCV: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Receiver.MulticastBytes; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_MULTICAST_FRAMES_RCV: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Receiver.Multicast; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_BROADCAST_BYTES_RCV: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Receiver.BroadcastBytes; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_BROADCAST_FRAMES_RCV: { + XENVIF_PACKET_STATISTICS Statistics; + + VIF(QueryPacketStatistics, + Adapter->VifInterface, + &Statistics); + + infoData = (ULONG)Statistics.Receiver.Broadcast; + info = &infoData; + bytesAvailable = sizeof(ULONG); + break; + } + case OID_GEN_INTERRUPT_MODERATION: + intModParams.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + intModParams.Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; + intModParams.Header.Size = sizeof(NDIS_INTERRUPT_MODERATION_PARAMETERS); + intModParams.Flags = 0; + intModParams.InterruptModeration = NdisInterruptModerationNotSupported; + info = &intModParams; + bytesAvailable = sizeof(intModParams); + break; + + // We don't handle these since NDIS 6.0 is supposed to do this for us + case OID_GEN_MAC_ADDRESS: + case OID_GEN_MAX_LINK_SPEED: + ndisStatus = NDIS_STATUS_NOT_SUPPORTED; + break; + + // ignore these common unwanted OIDs + case OID_GEN_INIT_TIME_MS: + case OID_GEN_RESET_COUNTS: + case OID_GEN_MEDIA_SENSE_COUNTS: + ndisStatus = NDIS_STATUS_NOT_SUPPORTED; + break; + + default: + ndisStatus = NDIS_STATUS_NOT_SUPPORTED; + break; + }; + + if (ndisStatus == NDIS_STATUS_SUCCESS) { + if (bytesAvailable <= informationBufferLength) { + bytesNeeded = bytesAvailable; + bytesWritten = bytesAvailable; + } else { + bytesNeeded = bytesAvailable; + bytesWritten = informationBufferLength; + ndisStatus = NDIS_STATUS_BUFFER_TOO_SHORT; + } + + if (bytesWritten && doCopy) { + NdisMoveMemory(informationBuffer, info, bytesWritten); + + if (oid == OID_GEN_XMIT_OK || oid == OID_GEN_RCV_OK) + ndisStatus = NDIS_STATUS_SUCCESS; + } + } + + NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = bytesWritten; + NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = bytesNeeded; + return ndisStatus; +} + +NDIS_STATUS +AdapterReset ( + IN NDIS_HANDLE MiniportAdapterContext, + OUT PBOOLEAN AddressingReset + ) +{ + UNREFERENCED_PARAMETER(MiniportAdapterContext); + + + *AddressingReset = FALSE; + + return NDIS_STATUS_SUCCESS; +} + +// +// Restarts a paused adapter. +// +NDIS_STATUS +AdapterRestart ( + IN PADAPTER Adapter, + IN PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters + ) +{ + NTSTATUS status; + NDIS_STATUS ndisStatus; + + UNREFERENCED_PARAMETER(MiniportRestartParameters); + + Trace("====>\n"); + + if (Adapter->Enabled) { + ndisStatus = NDIS_STATUS_SUCCESS; + goto done; + } + + status = VIF(Enable, + Adapter->VifInterface, + AdapterVifCallback, + Adapter); + if (NT_SUCCESS(status)) { + TransmitterEnable(Adapter->Transmitter); + Adapter->Enabled = TRUE; + ndisStatus = NDIS_STATUS_SUCCESS; + } else { + ndisStatus = NDIS_STATUS_FAILURE; + } + +done: + Trace("<====\n"); + return ndisStatus; +} + +// +// Recycle of received net buffer lists. +// +VOID +AdapterReturnNetBufferLists ( + IN PADAPTER Adapter, + IN PNET_BUFFER_LIST NetBufferLists, + IN ULONG ReturnFlags + ) +{ + ReceiverReturnNetBufferLists(&Adapter->Receiver, + NetBufferLists, + ReturnFlags); + + return; +} + +// +// Used to send net buffer lists. +// +VOID +AdapterSendNetBufferLists ( + IN PADAPTER Adapter, + IN PNET_BUFFER_LIST NetBufferList, + IN NDIS_PORT_NUMBER PortNumber, + IN ULONG SendFlags + ) +{ + TransmitterSendNetBufferLists(Adapter->Transmitter, + NetBufferList, + PortNumber, + SendFlags); +} + +#define XENNET_MEDIA_MAX_SPEED 1000000000ull + +#define XENNET_SUPPORTED_PACKET_FILTERS \ + (NDIS_PACKET_TYPE_DIRECTED | \ + NDIS_PACKET_TYPE_MULTICAST | \ + NDIS_PACKET_TYPE_ALL_MULTICAST | \ + NDIS_PACKET_TYPE_BROADCAST | \ + NDIS_PACKET_TYPE_PROMISCUOUS) + +// +// Sets general adapter attributes. +// +static NDIS_STATUS +AdapterSetGeneralAttributes ( + IN PADAPTER Adapter + ) +{ + PNDIS_MINIPORT_ADAPTER_ATTRIBUTES adapterAttributes; + NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES generalAttributes; + NDIS_STATUS ndisStatus; + + NdisZeroMemory(&generalAttributes, + sizeof(NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES)); + + generalAttributes.Header.Type = + NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES; + + generalAttributes.Header.Revision = + NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; + + generalAttributes.Header.Size = + sizeof(NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES); + + generalAttributes.MediaType = XENNET_MEDIA_TYPE; + + VIF(QueryMaximumFrameSize, + Adapter->VifInterface, + (PULONG)&Adapter->MaximumFrameSize); + + generalAttributes.MtuSize = Adapter->MaximumFrameSize - sizeof (ETHERNET_HEADER); + generalAttributes.MaxXmitLinkSpeed = XENNET_MEDIA_MAX_SPEED; + generalAttributes.MaxRcvLinkSpeed = XENNET_MEDIA_MAX_SPEED; + generalAttributes.XmitLinkSpeed = XENNET_MEDIA_MAX_SPEED; + generalAttributes.RcvLinkSpeed = XENNET_MEDIA_MAX_SPEED; + generalAttributes.MediaConnectState = MediaConnectStateConnected; + generalAttributes.MediaDuplexState = MediaDuplexStateFull; + generalAttributes.LookaheadSize = Adapter->MaximumFrameSize; + generalAttributes.PowerManagementCapabilities = &Adapter->Capabilities; + generalAttributes.MacOptions = XENNET_MAC_OPTIONS; + + generalAttributes.SupportedPacketFilters = XENNET_SUPPORTED_PACKET_FILTERS; + + generalAttributes.MaxMulticastListSize = MAXIMUM_MULTICAST_ADDRESS_COUNT; + generalAttributes.MacAddressLength = ETHERNET_ADDRESS_LENGTH; + + VIF(QueryPermanentAddress, + Adapter->VifInterface, + (PETHERNET_ADDRESS)&generalAttributes.PermanentMacAddress); + VIF(QueryCurrentAddress, + Adapter->VifInterface, + (PETHERNET_ADDRESS)&generalAttributes.CurrentMacAddress); + + generalAttributes.PhysicalMediumType = NdisPhysicalMedium802_3; + generalAttributes.RecvScaleCapabilities = NULL; + generalAttributes.AccessType = NET_IF_ACCESS_BROADCAST; + generalAttributes.DirectionType = NET_IF_DIRECTION_SENDRECEIVE; + generalAttributes.ConnectionType = NET_IF_CONNECTION_DEDICATED; + generalAttributes.IfType = IF_TYPE_ETHERNET_CSMACD; + generalAttributes.IfConnectorPresent = TRUE; + + generalAttributes.SupportedStatistics = NDIS_STATISTICS_XMIT_OK_SUPPORTED | + NDIS_STATISTICS_XMIT_ERROR_SUPPORTED | + NDIS_STATISTICS_DIRECTED_BYTES_XMIT_SUPPORTED | + NDIS_STATISTICS_DIRECTED_FRAMES_XMIT_SUPPORTED | + NDIS_STATISTICS_MULTICAST_BYTES_XMIT_SUPPORTED | + NDIS_STATISTICS_MULTICAST_FRAMES_XMIT_SUPPORTED | + NDIS_STATISTICS_BROADCAST_BYTES_XMIT_SUPPORTED | + NDIS_STATISTICS_BROADCAST_FRAMES_XMIT_SUPPORTED | + NDIS_STATISTICS_RCV_OK_SUPPORTED | + NDIS_STATISTICS_RCV_ERROR_SUPPORTED | + NDIS_STATISTICS_DIRECTED_BYTES_RCV_SUPPORTED | + NDIS_STATISTICS_DIRECTED_FRAMES_RCV_SUPPORTED | + NDIS_STATISTICS_MULTICAST_BYTES_RCV_SUPPORTED | + NDIS_STATISTICS_MULTICAST_FRAMES_RCV_SUPPORTED | + NDIS_STATISTICS_BROADCAST_BYTES_RCV_SUPPORTED | + NDIS_STATISTICS_BROADCAST_FRAMES_RCV_SUPPORTED | + NDIS_STATISTICS_GEN_STATISTICS_SUPPORTED; + + generalAttributes.SupportedOidList = XennetSupportedOids; + generalAttributes.SupportedOidListLength = sizeof(XennetSupportedOids); + adapterAttributes = + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&generalAttributes; + + ndisStatus = NdisMSetMiniportAttributes(Adapter->NdisAdapterHandle, + adapterAttributes); + + return ndisStatus; +} + +#define DISPLAY_OFFLOAD(_Offload) \ + do { \ + if ((_Offload).Checksum.IPv4Receive.IpChecksum) \ + Info("Checksum.IPv4Receive.IpChecksum ON\n"); \ + else \ + Info("Checksum.IPv4Receive.IpChecksum OFF\n"); \ + \ + if ((_Offload).Checksum.IPv4Receive.TcpChecksum) \ + Info("Checksum.IPv4Receive.TcpChecksum ON\n"); \ + else \ + Info("Checksum.IPv4Receive.TcpChecksum OFF\n"); \ + \ + if ((_Offload).Checksum.IPv4Receive.UdpChecksum) \ + Info("Checksum.IPv4Receive.UdpChecksum ON\n"); \ + else \ + Info("Checksum.IPv4Receive.UdpChecksum OFF\n"); \ + \ + if ((_Offload).Checksum.IPv6Receive.TcpChecksum) \ + Info("Checksum.IPv6Receive.TcpChecksum ON\n"); \ + else \ + Info("Checksum.IPv6Receive.TcpChecksum OFF\n"); \ + \ + if ((_Offload).Checksum.IPv6Receive.UdpChecksum) \ + Info("Checksum.IPv6Receive.UdpChecksum ON\n"); \ + else \ + Info("Checksum.IPv6Receive.UdpChecksum OFF\n"); \ + \ + if ((_Offload).Checksum.IPv4Transmit.IpChecksum) \ + Info("Checksum.IPv4Transmit.IpChecksum ON\n"); \ + else \ + Info("Checksum.IPv4Transmit.IpChecksum OFF\n"); \ + \ + if ((_Offload).Checksum.IPv4Transmit.TcpChecksum) \ + Info("Checksum.IPv4Transmit.TcpChecksum ON\n"); \ + else \ + Info("Checksum.IPv4Transmit.TcpChecksum OFF\n"); \ + \ + if ((_Offload).Checksum.IPv4Transmit.UdpChecksum) \ + Info("Checksum.IPv4Transmit.UdpChecksum ON\n"); \ + else \ + Info("Checksum.IPv4Transmit.UdpChecksum OFF\n"); \ + \ + if ((_Offload).Checksum.IPv6Transmit.TcpChecksum) \ + Info("Checksum.IPv6Transmit.TcpChecksum ON\n"); \ + else \ + Info("Checksum.IPv6Transmit.TcpChecksum OFF\n"); \ + \ + if ((_Offload).Checksum.IPv6Transmit.UdpChecksum) \ + Info("Checksum.IPv6Transmit.UdpChecksum ON\n"); \ + else \ + Info("Checksum.IPv6Transmit.UdpChecksum OFF\n"); \ + \ + if ((_Offload).LsoV2.IPv4.MaxOffLoadSize != 0) \ + Info("LsoV2.IPv4.MaxOffLoadSize = %u\n", \ + (_Offload).LsoV2.IPv4.MaxOffLoadSize); \ + else \ + Info("LsoV2.IPv4 OFF\n"); \ + \ + if ((_Offload).LsoV2.IPv6.MaxOffLoadSize != 0) \ + Info("LsoV2.IPv6.MaxOffLoadSize = %u\n", \ + (_Offload).LsoV2.IPv6.MaxOffLoadSize); \ + else \ + Info("LsoV2.IPv6 OFF\n"); \ + } while (FALSE) + +static NDIS_STATUS +AdapterSetOffloadAttributes( + IN PADAPTER Adapter + ) +{ + PNDIS_MINIPORT_ADAPTER_ATTRIBUTES adapterAttributes; + NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES offloadAttributes; + XENVIF_OFFLOAD_OPTIONS Options; + NDIS_OFFLOAD current; + NDIS_OFFLOAD supported; + NDIS_STATUS ndisStatus; + + Adapter->Receiver.OffloadOptions.Value = 0; + Adapter->Receiver.OffloadOptions.OffloadTagManipulation = 1; + + if (Adapter->Properties.need_csum_value) + Adapter->Receiver.OffloadOptions.NeedChecksumValue = 1; + + if (Adapter->Properties.lrov4) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion4LargePacket = 1; + Adapter->Receiver.OffloadOptions.NeedLargePacketSplit = 1; + } + + if (Adapter->Properties.lrov6) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion6LargePacket = 1; + Adapter->Receiver.OffloadOptions.NeedLargePacketSplit = 1; + } + + Adapter->Transmitter->OffloadOptions.Value = 0; + Adapter->Transmitter->OffloadOptions.OffloadTagManipulation = 1; + + NdisZeroMemory(&offloadAttributes, sizeof(offloadAttributes)); + NdisZeroMemory(¤t, sizeof(current)); + NdisZeroMemory(&supported, sizeof(supported)); + + VIF(UpdateOffloadOptions, + Adapter->VifInterface, + Adapter->Receiver.OffloadOptions); + + supported.Header.Type = NDIS_OBJECT_TYPE_OFFLOAD; + supported.Header.Revision = NDIS_OFFLOAD_REVISION_1; + supported.Header.Size = sizeof(supported); + + supported.Checksum.IPv4Receive.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + + supported.Checksum.IPv4Receive.IpChecksum = 1; + supported.Checksum.IPv4Receive.IpOptionsSupported = 1; + + supported.Checksum.IPv4Receive.TcpChecksum = 1; + supported.Checksum.IPv4Receive.TcpOptionsSupported = 1; + + supported.Checksum.IPv4Receive.UdpChecksum = 1; + + supported.Checksum.IPv6Receive.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + + supported.Checksum.IPv6Receive.IpExtensionHeadersSupported = 1; + + supported.Checksum.IPv6Receive.TcpChecksum = 1; + supported.Checksum.IPv6Receive.TcpOptionsSupported = 1; + + supported.Checksum.IPv6Receive.UdpChecksum = 1; + + VIF(QueryOffloadOptions, + Adapter->VifInterface, + &Options); + + supported.Checksum.IPv4Transmit.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + + if (Options.OffloadIpVersion4HeaderChecksum) { + supported.Checksum.IPv4Transmit.IpChecksum = 1; + supported.Checksum.IPv4Transmit.IpOptionsSupported = 1; + } + + if (Options.OffloadIpVersion4TcpChecksum) { + supported.Checksum.IPv4Transmit.TcpChecksum = 1; + supported.Checksum.IPv4Transmit.TcpOptionsSupported = 1; + } + + if (Options.OffloadIpVersion4UdpChecksum) + supported.Checksum.IPv4Transmit.UdpChecksum = 1; + + supported.Checksum.IPv6Transmit.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + + supported.Checksum.IPv6Transmit.IpExtensionHeadersSupported = 1; + + if (Options.OffloadIpVersion6TcpChecksum) { + supported.Checksum.IPv6Transmit.TcpChecksum = 1; + supported.Checksum.IPv6Transmit.TcpOptionsSupported = 1; + } + + if (Options.OffloadIpVersion6UdpChecksum) + supported.Checksum.IPv6Transmit.UdpChecksum = 1; + + if (Options.OffloadIpVersion4LargePacket) { + ULONG Size; + + VIF(QueryLargePacketSize, + Adapter->VifInterface, + 4, + &Size); + + supported.LsoV2.IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + supported.LsoV2.IPv4.MaxOffLoadSize = Size; + supported.LsoV2.IPv4.MinSegmentCount = 2; + } + + if (Options.OffloadIpVersion6LargePacket) { + ULONG Size; + + VIF(QueryLargePacketSize, + Adapter->VifInterface, + 6, + &Size); + + supported.LsoV2.IPv6.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + supported.LsoV2.IPv6.MaxOffLoadSize = Size; + supported.LsoV2.IPv6.MinSegmentCount = 2; + supported.LsoV2.IPv6.IpExtensionHeadersSupported = 1; + supported.LsoV2.IPv6.TcpOptionsSupported = 1; + } + + current = supported; + + if (!(Adapter->Properties.ipv4_csum & 2)) + current.Checksum.IPv4Receive.IpChecksum = 0; + + if (!(Adapter->Properties.tcpv4_csum & 2)) + current.Checksum.IPv4Receive.TcpChecksum = 0; + + if (!(Adapter->Properties.udpv4_csum & 2)) + current.Checksum.IPv4Receive.UdpChecksum = 0; + + if (!(Adapter->Properties.tcpv6_csum & 2)) + current.Checksum.IPv6Receive.TcpChecksum = 0; + + if (!(Adapter->Properties.udpv6_csum & 2)) + current.Checksum.IPv6Receive.UdpChecksum = 0; + + if (!(Adapter->Properties.ipv4_csum & 1)) + current.Checksum.IPv4Transmit.IpChecksum = 0; + + if (!(Adapter->Properties.tcpv4_csum & 1)) + current.Checksum.IPv4Transmit.TcpChecksum = 0; + + if (!(Adapter->Properties.udpv4_csum & 1)) + current.Checksum.IPv4Transmit.UdpChecksum = 0; + + if (!(Adapter->Properties.tcpv6_csum & 1)) + current.Checksum.IPv6Transmit.TcpChecksum = 0; + + if (!(Adapter->Properties.udpv6_csum & 1)) + current.Checksum.IPv6Transmit.UdpChecksum = 0; + + if (!(Adapter->Properties.lsov4)) { + current.LsoV2.IPv4.MaxOffLoadSize = 0; + current.LsoV2.IPv4.MinSegmentCount = 0; + } + + if (!(Adapter->Properties.lsov6)) { + current.LsoV2.IPv6.MaxOffLoadSize = 0; + current.LsoV2.IPv6.MinSegmentCount = 0; + } + + if (!RtlEqualMemory(&Adapter->Offload, ¤t, sizeof (NDIS_OFFLOAD))) { + Adapter->Offload = current; + + DISPLAY_OFFLOAD(current); + } + + offloadAttributes.Header.Type = + NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES; + offloadAttributes.Header.Revision = + NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES_REVISION_1; + offloadAttributes.Header.Size = sizeof(offloadAttributes); + offloadAttributes.DefaultOffloadConfiguration = ¤t; + offloadAttributes.HardwareOffloadCapabilities = &supported; + + adapterAttributes = + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&offloadAttributes; + ndisStatus = NdisMSetMiniportAttributes(Adapter->NdisAdapterHandle, + adapterAttributes); + + return ndisStatus; +} + +static void +AdapterIndicateOffloadChanged ( + IN PADAPTER Adapter + ) +{ + NDIS_STATUS_INDICATION indication; + NDIS_OFFLOAD offload; + + NdisZeroMemory(&offload, sizeof(offload)); + INITIALIZE_NDIS_OBJ_HEADER(offload, OFFLOAD); + + offload.Checksum.IPv4Receive.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + + if (Adapter->Receiver.OffloadOptions.OffloadIpVersion4HeaderChecksum) { + offload.Checksum.IPv4Receive.IpChecksum = 1; + offload.Checksum.IPv4Receive.IpOptionsSupported = 1; + } + + if (Adapter->Receiver.OffloadOptions.OffloadIpVersion4TcpChecksum) { + offload.Checksum.IPv4Receive.TcpChecksum = 1; + offload.Checksum.IPv4Receive.TcpOptionsSupported = 1; + } + + if (Adapter->Receiver.OffloadOptions.OffloadIpVersion4UdpChecksum) { + offload.Checksum.IPv4Receive.UdpChecksum = 1; + } + + offload.Checksum.IPv6Receive.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + + offload.Checksum.IPv6Receive.IpExtensionHeadersSupported = 1; + + if (Adapter->Receiver.OffloadOptions.OffloadIpVersion6TcpChecksum) { + offload.Checksum.IPv6Receive.TcpChecksum = 1; + offload.Checksum.IPv6Receive.TcpOptionsSupported = 1; + } + + if (Adapter->Receiver.OffloadOptions.OffloadIpVersion6UdpChecksum) { + offload.Checksum.IPv6Receive.UdpChecksum = 1; + } + + VIF(UpdateOffloadOptions, + Adapter->VifInterface, + Adapter->Receiver.OffloadOptions); + + offload.Checksum.IPv4Transmit.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion4HeaderChecksum) { + offload.Checksum.IPv4Transmit.IpChecksum = 1; + offload.Checksum.IPv4Transmit.IpOptionsSupported = 1; + } + + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion4TcpChecksum) { + offload.Checksum.IPv4Transmit.TcpChecksum = 1; + offload.Checksum.IPv4Transmit.TcpOptionsSupported = 1; + } + + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion4UdpChecksum) { + offload.Checksum.IPv4Transmit.UdpChecksum = 1; + } + + offload.Checksum.IPv6Transmit.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + + offload.Checksum.IPv6Transmit.IpExtensionHeadersSupported = 1; + + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion6TcpChecksum) { + offload.Checksum.IPv6Transmit.TcpChecksum = 1; + offload.Checksum.IPv6Transmit.TcpOptionsSupported = 1; + } + + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion6UdpChecksum) { + offload.Checksum.IPv6Transmit.UdpChecksum = 1; + } + + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion4LargePacket) { + ULONG Size; + + VIF(QueryLargePacketSize, + Adapter->VifInterface, + 4, + &Size); + + offload.LsoV2.IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + offload.LsoV2.IPv4.MaxOffLoadSize = Size; + offload.LsoV2.IPv4.MinSegmentCount = 2; + } + + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion6LargePacket) { + ULONG Size; + + VIF(QueryLargePacketSize, + Adapter->VifInterface, + 6, + &Size); + + offload.LsoV2.IPv6.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3; + offload.LsoV2.IPv6.MaxOffLoadSize = Size; + offload.LsoV2.IPv6.MinSegmentCount = 2; + offload.LsoV2.IPv6.IpExtensionHeadersSupported = 1; + offload.LsoV2.IPv6.TcpOptionsSupported = 1; + } + + if (!RtlEqualMemory(&Adapter->Offload, &offload, sizeof (NDIS_OFFLOAD))) { + Adapter->Offload = offload; + + DISPLAY_OFFLOAD(offload); + } + + NdisZeroMemory(&indication, sizeof(indication)); + INITIALIZE_NDIS_OBJ_HEADER(indication, STATUS_INDICATION); + indication.SourceHandle = Adapter->NdisAdapterHandle; + indication.StatusCode = NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG; + indication.StatusBuffer = &offload; + indication.StatusBufferSize = sizeof(offload); + + NdisMIndicateStatusEx(Adapter->NdisAdapterHandle, &indication); + +} + +static NDIS_STATUS +SetMulticastAddresses(PADAPTER Adapter, PETHERNET_ADDRESS Address, ULONG Count) +{ + NTSTATUS status; + + ASSERT3U(Count, <=, MAXIMUM_MULTICAST_ADDRESS_COUNT); + + status = VIF(UpdateMulticastAddresses, + Adapter->VifInterface, + Address, + Count); + if (!NT_SUCCESS(status)) + return NDIS_STATUS_INVALID_DATA; + + return NDIS_STATUS_SUCCESS; +} + +static NDIS_STATUS +SetPacketFilter(PADAPTER Adapter, PULONG PacketFilter) +{ + XENVIF_MAC_FILTER_LEVEL UnicastFilterLevel; + XENVIF_MAC_FILTER_LEVEL MulticastFilterLevel; + XENVIF_MAC_FILTER_LEVEL BroadcastFilterLevel; + + if (*PacketFilter & ~XENNET_SUPPORTED_PACKET_FILTERS) + return NDIS_STATUS_INVALID_PARAMETER; + + if (*PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) { + UnicastFilterLevel = MAC_FILTER_ALL; + MulticastFilterLevel = MAC_FILTER_ALL; + BroadcastFilterLevel = MAC_FILTER_ALL; + goto done; + } + + if (*PacketFilter & NDIS_PACKET_TYPE_DIRECTED) + UnicastFilterLevel = MAC_FILTER_MATCHING; + else + UnicastFilterLevel = MAC_FILTER_NONE; + + if (*PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) + MulticastFilterLevel = MAC_FILTER_ALL; + else if (*PacketFilter & NDIS_PACKET_TYPE_MULTICAST) + MulticastFilterLevel = MAC_FILTER_MATCHING; + else + MulticastFilterLevel = MAC_FILTER_NONE; + + if (*PacketFilter & NDIS_PACKET_TYPE_BROADCAST) + BroadcastFilterLevel = MAC_FILTER_ALL; + else + BroadcastFilterLevel = MAC_FILTER_NONE; + +done: + VIF(UpdateFilterLevel, + Adapter->VifInterface, + ETHERNET_ADDRESS_UNICAST, + UnicastFilterLevel); + + VIF(UpdateFilterLevel, + Adapter->VifInterface, + ETHERNET_ADDRESS_MULTICAST, + MulticastFilterLevel); + + VIF(UpdateFilterLevel, + Adapter->VifInterface, + ETHERNET_ADDRESS_BROADCAST, + BroadcastFilterLevel); + + return NDIS_STATUS_SUCCESS; +} + +// +// Set OID handler. +// +static NDIS_STATUS +AdapterSetInformation ( + IN PADAPTER Adapter, + IN PNDIS_OID_REQUEST NdisRequest + ) +{ + ULONG addressCount; + ULONG bytesNeeded = 0; + ULONG bytesRead = 0; + PVOID informationBuffer; + ULONG informationBufferLength; + NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; + NDIS_OID oid; + BOOLEAN offloadChanged; + + informationBuffer = NdisRequest->DATA.SET_INFORMATION.InformationBuffer; + informationBufferLength = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength; + oid = NdisRequest->DATA.QUERY_INFORMATION.Oid; + switch (oid) { + case OID_PNP_SET_POWER: + bytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE); + if (informationBufferLength >= bytesNeeded) { + PNDIS_DEVICE_POWER_STATE state; + + state = (PNDIS_DEVICE_POWER_STATE)informationBuffer; + switch (*state) { + case NdisDeviceStateD0: + Info("SET_POWER: D0\n"); + break; + + case NdisDeviceStateD1: + Info("SET_POWER: D1\n"); + break; + + case NdisDeviceStateD2: + Info("SET_POWER: D2\n"); + break; + + case NdisDeviceStateD3: + Info("SET_POWER: D3\n"); + break; + } + } + break; + + case OID_GEN_MACHINE_NAME: + ndisStatus = NDIS_STATUS_NOT_SUPPORTED; + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + bytesNeeded = sizeof(ULONG); + Adapter->CurrentLookahead = Adapter->MaximumFrameSize; + if (informationBufferLength == sizeof(ULONG)) { + Adapter->CurrentLookahead = *(PULONG)informationBuffer; + bytesRead = sizeof(ULONG); + } + + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + bytesNeeded = sizeof(ULONG); + if (informationBufferLength == sizeof(ULONG)) { + ndisStatus = SetPacketFilter(Adapter, (PULONG)informationBuffer); + bytesRead = sizeof(ULONG); + } + + break; + + case OID_802_3_MULTICAST_LIST: + bytesNeeded = ETHERNET_ADDRESS_LENGTH; + if (informationBufferLength % ETHERNET_ADDRESS_LENGTH == 0) { + addressCount = informationBufferLength / ETHERNET_ADDRESS_LENGTH; + + ndisStatus = SetMulticastAddresses(Adapter, informationBuffer, addressCount); + if (ndisStatus == NDIS_STATUS_SUCCESS) + bytesRead = informationBufferLength; + } else { + ndisStatus = NDIS_STATUS_INVALID_LENGTH; + } + + break; + + case OID_GEN_INTERRUPT_MODERATION: + ndisStatus = NDIS_STATUS_INVALID_DATA; + break; + + case OID_OFFLOAD_ENCAPSULATION: { + PNDIS_OFFLOAD_ENCAPSULATION offloadEncapsulation; + + bytesNeeded = sizeof(*offloadEncapsulation); + if (informationBufferLength >= bytesNeeded) { + XENVIF_OFFLOAD_OPTIONS Options; + + bytesRead = bytesNeeded; + offloadEncapsulation = informationBuffer; + ndisStatus = NDIS_STATUS_SUCCESS; + + if (offloadEncapsulation->IPv4.Enabled == NDIS_OFFLOAD_SET_ON) { + if (offloadEncapsulation->IPv4.EncapsulationType != NDIS_ENCAPSULATION_IEEE_802_3) + ndisStatus = NDIS_STATUS_INVALID_PARAMETER; + } + + if (offloadEncapsulation->IPv6.Enabled == NDIS_OFFLOAD_SET_ON) { + if (offloadEncapsulation->IPv6.EncapsulationType != NDIS_ENCAPSULATION_IEEE_802_3) + ndisStatus = NDIS_STATUS_INVALID_PARAMETER; + } + + VIF(QueryOffloadOptions, + Adapter->VifInterface, + &Options); + + Adapter->Transmitter->OffloadOptions.Value = 0; + Adapter->Transmitter->OffloadOptions.OffloadTagManipulation = 1; + + if ((Adapter->Properties.lsov4) && (Options.OffloadIpVersion4LargePacket)) + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4LargePacket = 1; + + if ((Adapter->Properties.lsov6) && (Options.OffloadIpVersion6LargePacket)) + Adapter->Transmitter->OffloadOptions.OffloadIpVersion6LargePacket = 1; + + if ((Adapter->Properties.ipv4_csum & 1) && Options.OffloadIpVersion4HeaderChecksum) + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4HeaderChecksum = 1; + + if ((Adapter->Properties.tcpv4_csum & 1) && Options.OffloadIpVersion4TcpChecksum) + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4TcpChecksum = 1; + + if ((Adapter->Properties.udpv4_csum & 1) && Options.OffloadIpVersion4UdpChecksum) + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4UdpChecksum = 1; + + if ((Adapter->Properties.tcpv6_csum & 1) && Options.OffloadIpVersion6TcpChecksum) + Adapter->Transmitter->OffloadOptions.OffloadIpVersion6TcpChecksum = 1; + + if ((Adapter->Properties.udpv6_csum & 1) && Options.OffloadIpVersion6UdpChecksum) + Adapter->Transmitter->OffloadOptions.OffloadIpVersion6UdpChecksum = 1; + + Adapter->Receiver.OffloadOptions.Value = 0; + Adapter->Receiver.OffloadOptions.OffloadTagManipulation = 1; + + if (Adapter->Properties.need_csum_value) + Adapter->Receiver.OffloadOptions.NeedChecksumValue = 1; + + if (Adapter->Properties.lrov4) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion4LargePacket = 1; + Adapter->Receiver.OffloadOptions.NeedLargePacketSplit = 1; + } + + if (Adapter->Properties.lrov6) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion6LargePacket = 1; + Adapter->Receiver.OffloadOptions.NeedLargePacketSplit = 1; + } + + if (Adapter->Properties.ipv4_csum & 2) + Adapter->Receiver.OffloadOptions.OffloadIpVersion4HeaderChecksum = 1; + + if (Adapter->Properties.tcpv4_csum & 2) + Adapter->Receiver.OffloadOptions.OffloadIpVersion4TcpChecksum = 1; + + if (Adapter->Properties.udpv4_csum & 2) + Adapter->Receiver.OffloadOptions.OffloadIpVersion4UdpChecksum = 1; + + if (Adapter->Properties.tcpv6_csum & 2) + Adapter->Receiver.OffloadOptions.OffloadIpVersion6TcpChecksum = 1; + + if (Adapter->Properties.udpv6_csum & 2) + Adapter->Receiver.OffloadOptions.OffloadIpVersion6UdpChecksum = 1; + + AdapterIndicateOffloadChanged(Adapter); + } + break; + } + case OID_TCP_OFFLOAD_PARAMETERS: { + PNDIS_OFFLOAD_PARAMETERS offloadParameters; + + bytesNeeded = sizeof(*offloadParameters); + if (informationBufferLength >= bytesNeeded) { + bytesRead = bytesNeeded; + offloadParameters = informationBuffer; + ndisStatus = NDIS_STATUS_SUCCESS; + +#define no_change(x) ((x) == NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) + + if (!no_change(offloadParameters->IPsecV1)) + ndisStatus = NDIS_STATUS_INVALID_PARAMETER; + + if (!no_change(offloadParameters->LsoV1)) + ndisStatus = NDIS_STATUS_INVALID_PARAMETER; + + if (!no_change(offloadParameters->TcpConnectionIPv4)) + ndisStatus = NDIS_STATUS_INVALID_PARAMETER; + + if (!no_change(offloadParameters->TcpConnectionIPv6)) + ndisStatus = NDIS_STATUS_INVALID_PARAMETER; + + if (!no_change(offloadParameters->LsoV2IPv4)) { + XENVIF_OFFLOAD_OPTIONS Options; + + VIF(QueryOffloadOptions, + Adapter->VifInterface, + &Options); + + if (!(Options.OffloadIpVersion4LargePacket)) + ndisStatus = NDIS_STATUS_INVALID_PARAMETER; + } + + if (!no_change(offloadParameters->LsoV2IPv6)) { + XENVIF_OFFLOAD_OPTIONS Options; + + VIF(QueryOffloadOptions, + Adapter->VifInterface, + &Options); + + if (!(Options.OffloadIpVersion6LargePacket)) + ndisStatus = NDIS_STATUS_INVALID_PARAMETER; + } + +#define rx_enabled(x) ((x) == NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED || \ + (x) == NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED) +#define tx_enabled(x) ((x) == NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED || \ + (x) == NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED) + + if (ndisStatus == NDIS_STATUS_SUCCESS) { + offloadChanged = FALSE; + + if (offloadParameters->LsoV2IPv4 == NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED) { + if (!Adapter->Transmitter->OffloadOptions.OffloadIpVersion4LargePacket) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4LargePacket = 1; + offloadChanged = TRUE; + } + } else if (offloadParameters->LsoV2IPv4 == NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED) { + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion4LargePacket) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4LargePacket = 0; + offloadChanged = TRUE; + } + } + + if (offloadParameters->LsoV2IPv6 == NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED) { + if (!Adapter->Transmitter->OffloadOptions.OffloadIpVersion6LargePacket) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion6LargePacket = 1; + offloadChanged = TRUE; + } + } else if (offloadParameters->LsoV2IPv6 == NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED) { + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion6LargePacket) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion6LargePacket = 0; + offloadChanged = TRUE; + } + } + + if (tx_enabled(offloadParameters->IPv4Checksum)) { + if (!Adapter->Transmitter->OffloadOptions.OffloadIpVersion4HeaderChecksum) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4HeaderChecksum = 1; + offloadChanged = TRUE; + } + } else { + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion4HeaderChecksum) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4HeaderChecksum = 0; + offloadChanged = TRUE; + } + } + + if (tx_enabled(offloadParameters->TCPIPv4Checksum)) { + if (!Adapter->Transmitter->OffloadOptions.OffloadIpVersion4TcpChecksum) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4TcpChecksum = 1; + offloadChanged = TRUE; + } + } else { + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion4TcpChecksum) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4TcpChecksum = 0; + offloadChanged = TRUE; + } + } + + if (tx_enabled(offloadParameters->UDPIPv4Checksum)) { + if (!Adapter->Transmitter->OffloadOptions.OffloadIpVersion4UdpChecksum) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4UdpChecksum = 1; + offloadChanged = TRUE; + } + } else { + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion4UdpChecksum) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion4UdpChecksum = 0; + offloadChanged = TRUE; + } + } + + if (tx_enabled(offloadParameters->TCPIPv6Checksum)) { + if (!Adapter->Transmitter->OffloadOptions.OffloadIpVersion6TcpChecksum) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion6TcpChecksum = 1; + offloadChanged = TRUE; + } + } else { + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion6TcpChecksum) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion6TcpChecksum = 0; + offloadChanged = TRUE; + } + } + + if (tx_enabled(offloadParameters->UDPIPv6Checksum)) { + if (!Adapter->Transmitter->OffloadOptions.OffloadIpVersion6UdpChecksum) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion6UdpChecksum = 1; + offloadChanged = TRUE; + } + } else { + if (Adapter->Transmitter->OffloadOptions.OffloadIpVersion6UdpChecksum) { + Adapter->Transmitter->OffloadOptions.OffloadIpVersion6UdpChecksum = 0; + offloadChanged = TRUE; + } + } + + if (rx_enabled(offloadParameters->IPv4Checksum)) { + if (!Adapter->Receiver.OffloadOptions.OffloadIpVersion4HeaderChecksum) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion4HeaderChecksum = 1; + offloadChanged = TRUE; + } + } else { + if (Adapter->Receiver.OffloadOptions.OffloadIpVersion4HeaderChecksum) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion4HeaderChecksum = 0; + offloadChanged = TRUE; + } + } + + if (rx_enabled(offloadParameters->TCPIPv4Checksum)) { + if (!Adapter->Receiver.OffloadOptions.OffloadIpVersion4TcpChecksum) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion4TcpChecksum = 1; + offloadChanged = TRUE; + } + } else { + if (Adapter->Receiver.OffloadOptions.OffloadIpVersion4TcpChecksum) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion4TcpChecksum = 0; + offloadChanged = TRUE; + } + } + + if (rx_enabled(offloadParameters->UDPIPv4Checksum)) { + if (!Adapter->Receiver.OffloadOptions.OffloadIpVersion4UdpChecksum) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion4UdpChecksum = 1; + offloadChanged = TRUE; + } + } else { + if (Adapter->Receiver.OffloadOptions.OffloadIpVersion4UdpChecksum) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion4UdpChecksum = 0; + offloadChanged = TRUE; + } + } + + if (rx_enabled(offloadParameters->TCPIPv6Checksum)) { + if (!Adapter->Receiver.OffloadOptions.OffloadIpVersion6TcpChecksum) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion6TcpChecksum = 1; + offloadChanged = TRUE; + } + } else { + if (Adapter->Receiver.OffloadOptions.OffloadIpVersion6TcpChecksum) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion6TcpChecksum = 0; + offloadChanged = TRUE; + } + } + + if (rx_enabled(offloadParameters->UDPIPv6Checksum)) { + if (!Adapter->Receiver.OffloadOptions.OffloadIpVersion6UdpChecksum) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion6UdpChecksum = 1; + offloadChanged = TRUE; + } + } else { + if (Adapter->Receiver.OffloadOptions.OffloadIpVersion6UdpChecksum) { + Adapter->Receiver.OffloadOptions.OffloadIpVersion6UdpChecksum = 0; + offloadChanged = TRUE; + } + } + +#undef tx_enabled +#undef rx_enabled +#undef no_change + + if (offloadChanged) + AdapterIndicateOffloadChanged(Adapter); + } + } else { + ndisStatus = NDIS_STATUS_INVALID_LENGTH; + } + break; + } + default: + ndisStatus = NDIS_STATUS_NOT_SUPPORTED; + break; + }; + + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = bytesNeeded; + if (ndisStatus == NDIS_STATUS_SUCCESS) { + NdisRequest->DATA.SET_INFORMATION.BytesRead = bytesRead; + } + + return ndisStatus; +} + +// +// Sets miniport registration attributes. +// +static NDIS_STATUS +AdapterSetRegistrationAttributes ( + IN PADAPTER Adapter + ) +{ + PNDIS_MINIPORT_ADAPTER_ATTRIBUTES adapterAttributes; + NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES registrationAttributes; + NDIS_STATUS ndisStatus; + + + NdisZeroMemory(®istrationAttributes, + sizeof(NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES)); + + registrationAttributes.Header.Type = + NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES; + + registrationAttributes.Header.Revision = + NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; + + registrationAttributes.Header.Size = + sizeof(NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES); + + registrationAttributes.MiniportAdapterContext = (NDIS_HANDLE)Adapter; + registrationAttributes.AttributeFlags = NDIS_MINIPORT_ATTRIBUTES_BUS_MASTER | + NDIS_MINIPORT_ATTRIBUTES_NO_HALT_ON_SUSPEND; + + registrationAttributes.CheckForHangTimeInSeconds = 0; + registrationAttributes.InterfaceType = XENNET_INTERFACE_TYPE; + + adapterAttributes = + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)®istrationAttributes; + + ndisStatus = NdisMSetMiniportAttributes(Adapter->NdisAdapterHandle, + adapterAttributes); + + return ndisStatus; +} + +// +// Shuts down adapter. +// +VOID +AdapterShutdown ( + IN PADAPTER Adapter, + IN NDIS_SHUTDOWN_ACTION ShutdownAction + ) +{ + UNREFERENCED_PARAMETER(ShutdownAction); + + if (ShutdownAction != NdisShutdownBugCheck) + AdapterStop(Adapter); + + return; +} + +// +// Stops adapter. Waits for currently transmitted packets to complete. +// Stops transmission of new packets. +// Stops received packet indication to NDIS. +// +static NDIS_STATUS +AdapterStop ( +IN PADAPTER Adapter +) +{ + Trace("====>\n"); + + if (!Adapter->Enabled) + goto done; + + VIF(Disable, + Adapter->VifInterface); + + Adapter->Enabled = FALSE; + +done: + Trace("<====\n"); + return NDIS_STATUS_SUCCESS; +} diff --git a/src/xennet/adapter.h b/src/xennet/adapter.h new file mode 100644 index 0000000..209d6be --- /dev/null +++ b/src/xennet/adapter.h @@ -0,0 +1,163 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +#define XENNET_INTERFACE_TYPE NdisInterfaceInternal + +#define XENNET_MEDIA_TYPE NdisMedium802_3 + +#define XENNET_MAC_OPTIONS (NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \ + NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | \ + NDIS_MAC_OPTION_NO_LOOPBACK | \ + NDIS_MAC_OPTION_8021P_PRIORITY | \ + NDIS_MAC_OPTION_SUPPORTS_MAC_ADDRESS_OVERWRITE) + +typedef struct _PROPERTIES { + int ipv4_csum; + int tcpv4_csum; + int udpv4_csum; + int tcpv6_csum; + int udpv6_csum; + int need_csum_value; + int lsov4; + int lsov6; + int lrov4; + int lrov6; +} PROPERTIES, *PPROPERTIES; + +struct _ADAPTER { + LIST_ENTRY ListEntry; + PXENVIF_VIF_INTERFACE VifInterface; + BOOLEAN AcquiredInterfaces; + ULONG MaximumFrameSize; + ULONG CurrentLookahead; + NDIS_HANDLE NdisAdapterHandle; + NDIS_HANDLE NdisDmaHandle; + NDIS_PNP_CAPABILITIES Capabilities; + PROPERTIES Properties; + RECEIVER Receiver; + PTRANSMITTER Transmitter; + BOOLEAN Enabled; + NDIS_OFFLOAD Offload; +}; + +VOID +AdapterCancelOidRequest ( + IN PADAPTER Adapter, + IN PVOID RequestId + ); + +VOID +AdapterCancelSendNetBufferLists ( + IN PADAPTER Adapter, + IN PVOID CancelId + ); + +BOOLEAN +AdapterCheckForHang ( + IN PADAPTER Adapter + ); + +VOID +AdapterDelete ( + IN OUT PADAPTER* Adapter + ); + +VOID +AdapterHalt ( + IN PADAPTER Adapter, + IN NDIS_HALT_ACTION HaltAction + ); + +NDIS_STATUS +AdapterInitialize ( + IN PADAPTER Adapter, + IN NDIS_HANDLE AdapterHandle + ); + +NDIS_STATUS +AdapterOidRequest ( + IN PADAPTER Adapter, + IN PNDIS_OID_REQUEST NdisRequest + ); + +NDIS_STATUS +AdapterPause ( + IN PADAPTER Adapter, + IN PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters + ); + +VOID +AdapterPnPEventHandler ( + IN PADAPTER Adapter, + IN PNET_DEVICE_PNP_EVENT NetDevicePnPEvent + ); + +NDIS_STATUS +AdapterReset ( + IN NDIS_HANDLE MiniportAdapterContext, + OUT PBOOLEAN AddressingReset + ); + +NDIS_STATUS +AdapterRestart ( + IN PADAPTER Adapter, + IN PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters + ); + +VOID +AdapterReturnNetBufferLists ( + IN PADAPTER Adapter, + IN PNET_BUFFER_LIST NetBufferLists, + IN ULONG ReturnFlags + ); + +VOID +AdapterSendNetBufferLists ( + IN PADAPTER Adapter, + IN PNET_BUFFER_LIST NetBufferList, + IN NDIS_PORT_NUMBER PortNumber, + IN ULONG SendFlags + ); + +VOID +AdapterShutdown ( + IN PADAPTER Adapter, + IN NDIS_SHUTDOWN_ACTION ShutdownAction + ); + +extern VOID +ReceiverReceivePackets( + IN PRECEIVER Receiver, + IN PLIST_ENTRY List + ); + diff --git a/src/xennet/assert.h b/src/xennet/assert.h new file mode 100644 index 0000000..2debb8e --- /dev/null +++ b/src/xennet/assert.h @@ -0,0 +1,173 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _XENNET_ASSERT_H +#define _XENNET_ASSERT_H + +#include + +#include "log.h" + +static FORCEINLINE VOID +__BugCheck( + IN ULONG Code, + IN ULONG_PTR Parameter1, + IN ULONG_PTR Parameter2, + IN ULONG_PTR Parameter3, + IN ULONG_PTR Parameter4 + ) +{ +#pragma prefast(suppress:28159) + KeBugCheckEx(Code, + Parameter1, + Parameter2, + Parameter3, + Parameter4); +} + +#define ASSERTION_FAILURE 0x0000DEAD + +#define BUG(_TEXT) \ + do { \ + const CHAR *_Text = (_TEXT); \ + const CHAR *_File = __FILE__; \ + ULONG _Line = __LINE__; \ + \ + Error("BUG: " _TEXT "\n"); \ + __BugCheck(ASSERTION_FAILURE, \ + (ULONG_PTR)_Text, \ + (ULONG_PTR)_File, \ + (ULONG_PTR)_Line, \ + 0); \ + } while (FALSE) + +#define BUG_ON(_EXP) \ + if (_EXP) BUG(#_EXP) + +#if DBG + +#define __NT_ASSERT(_EXP) \ + ((!(_EXP)) ? \ + (Error("ASSERTION FAILED: " #_EXP "\n"), \ + __annotation(L"Debug", L"AssertFail", L#_EXP), \ + DbgRaiseAssertionFailure(), FALSE) : \ + TRUE) + +#define __ASSERT(_EXP) __NT_ASSERT(_EXP) + +#else // DBG + +#define __ASSERT(_EXP) BUG_ON(!(_EXP)) + +#endif // DBG + +#undef ASSERT + +#define ASSERT(_EXP) \ + do { \ + __ASSERT(_EXP); \ + } while (FALSE) + +#define ASSERT3U(_X, _OP, _Y) \ + do { \ + ULONGLONG _Lval = (ULONGLONG)(_X); \ + ULONGLONG _Rval = (ULONGLONG)(_Y); \ + if (!(_Lval _OP _Rval)) { \ + Error("%s = %llu\n", #_X, _Lval); \ + Error("%s = %llu\n", #_Y, _Rval); \ + ASSERT(_X _OP _Y); \ + } \ + } while (FALSE) + +#define ASSERT3S(_X, _OP, _Y) \ + do { \ + LONGLONG _Lval = (LONGLONG)(_X); \ + LONGLONG _Rval = (LONGLONG)(_Y); \ + if (!(_Lval _OP _Rval)) { \ + Error("%s = %lld\n", #_X, _Lval); \ + Error("%s = %lld\n", #_Y, _Rval); \ + ASSERT(_X _OP _Y); \ + } \ + } while (FALSE) + +#define ASSERT3P(_X, _OP, _Y) \ + do { \ + PVOID _Lval = (PVOID)(_X); \ + PVOID _Rval = (PVOID)(_Y); \ + if (!(_Lval _OP _Rval)) { \ + Error("%s = %p\n", #_X, _Lval); \ + Error("%s = %p\n", #_Y, _Rval); \ + ASSERT(_X _OP _Y); \ + } \ + } while (FALSE) + +#ifndef TEST_MEMORY +#define TEST_MEMORY DBG +#endif + +#if TEST_MEMORY + +static __inline BOOLEAN +_IsZeroMemory( + IN const PCHAR Caller, + IN const PCHAR Name, + IN PVOID Buffer, + IN ULONG Length + ) +{ + ULONG Offset; + + Offset = 0; + while (Offset < Length) { + if (*((PUCHAR)Buffer + Offset) != 0) { + Error("%s: non-zero byte in %s (0x%p+0x%x)\n", Caller, Name, Buffer, Offset); + return FALSE; + } + Offset++; + } + + return TRUE; +} + +#define IsZeroMemory(_Buffer, _Length) \ + _IsZeroMemory(__FUNCTION__, #_Buffer, (_Buffer), (_Length)) + +#else // TEST_MEMORY + +#define IsZeroMemory(_Buffer, _Length) TRUE + +#endif // TEST_MEMORY + +#define IMPLY(_X, _Y) (!(_X) || (_Y)) +#define EQUIV(_X, _Y) (IMPLY((_X), (_Y)) && IMPLY((_Y), (_X))) + +#endif // _XENNET_ASSERT_H + diff --git a/src/xennet/common.h b/src/xennet/common.h new file mode 100644 index 0000000..7ec6a08 --- /dev/null +++ b/src/xennet/common.h @@ -0,0 +1,36 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#pragma once + +#include "std.h" +#include "project.h" +#include "log.h" +#include "assert.h" diff --git a/src/xennet/log.h b/src/xennet/log.h new file mode 100644 index 0000000..40fa389 --- /dev/null +++ b/src/xennet/log.h @@ -0,0 +1,135 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _XENNET_LOG_H +#define _XENNET_LOG_H + +#include + +#pragma warning(disable:4127) // conditional expression is constant + +static __inline VOID +__Error( + IN const CHAR *Prefix, + IN const CHAR *Format, + ... + ) +{ + va_list Arguments; + + va_start(Arguments, Format); + +#pragma prefast(suppress:6001) // Using uninitialized memory + vDbgPrintExWithPrefix(Prefix, + DPFLTR_IHVDRIVER_ID, + DPFLTR_ERROR_LEVEL, + Format, + Arguments); + va_end(Arguments); +} + +#define Error(...) \ + __Error(__MODULE__ "|" __FUNCTION__ ": ", __VA_ARGS__) + +static __inline VOID +__Warning( + IN const CHAR *Prefix, + IN const CHAR *Format, + ... + ) +{ + va_list Arguments; + + va_start(Arguments, Format); + +#pragma prefast(suppress:6001) // Using uninitialized memory + vDbgPrintExWithPrefix(Prefix, + DPFLTR_IHVDRIVER_ID, + DPFLTR_WARNING_LEVEL, + Format, + Arguments); + va_end(Arguments); +} + +#define Warning(...) \ + __Warning(__MODULE__ "|" __FUNCTION__ ": ", __VA_ARGS__) + +#if DBG +static __inline VOID +__Trace( + IN const CHAR *Prefix, + IN const CHAR *Format, + ... + ) +{ + va_list Arguments; + + va_start(Arguments, Format); + +#pragma prefast(suppress:6001) // Using uninitialized memory + vDbgPrintExWithPrefix(Prefix, + DPFLTR_IHVDRIVER_ID, + DPFLTR_TRACE_LEVEL, + Format, + Arguments); + va_end(Arguments); +} + +#define Trace(...) \ + __Trace(__MODULE__ "|" __FUNCTION__ ": ", __VA_ARGS__) +#else // DBG +#define Trace(...) (VOID)(__VA_ARGS__) +#endif // DBG + +static __inline VOID +__Info( + IN const CHAR *Prefix, + IN const CHAR *Format, + ... + ) +{ + va_list Arguments; + + va_start(Arguments, Format); + +#pragma prefast(suppress:6001) // Using uninitialized memory + vDbgPrintExWithPrefix(Prefix, + DPFLTR_IHVDRIVER_ID, + DPFLTR_INFO_LEVEL, + Format, + Arguments); + va_end(Arguments); +} + +#define Info(...) \ + __Info(__MODULE__ "|" __FUNCTION__ ": ", __VA_ARGS__) + +#endif // _XENNET_LOG_H diff --git a/src/xennet/main.c b/src/xennet/main.c new file mode 100644 index 0000000..bd3e9d2 --- /dev/null +++ b/src/xennet/main.c @@ -0,0 +1,306 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "common.h" + +#pragma NDIS_INIT_FUNCTION(DriverEntry) + +// +// Global miniport data. +// + +static NDIS_HANDLE MiniportDriverHandle; + +extern NDIS_STATUS +MiniportInitialize ( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE MiniportDriverContext, + IN PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters + ); + +typedef struct _XENNET_CONTEXT { + PDEVICE_CAPABILITIES Capabilities; + PIO_COMPLETION_ROUTINE CompletionRoutine; + PVOID CompletionContext; + UCHAR CompletionControl; +} XENNET_CONTEXT, *PXENNET_CONTEXT; + +static NTSTATUS (*NdisDispatchPnp)(PDEVICE_OBJECT, PIRP); + +static NTSTATUS +__QueryCapabilities( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID _Context + ) +{ + PXENNET_CONTEXT Context = _Context; + NTSTATUS status; + + Trace("====>\n"); + + Context->Capabilities->SurpriseRemovalOK = 1; + + if (Context->CompletionRoutine != NULL && + (Context->CompletionControl & SL_INVOKE_ON_SUCCESS)) + status = Context->CompletionRoutine(DeviceObject, Irp, Context->CompletionContext); + else + status = STATUS_SUCCESS; + + ExFreePool(Context); + + Trace("<====\n"); + + return status; +} + +NTSTATUS +QueryCapabilities( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + PXENNET_CONTEXT Context; + NTSTATUS status; + + Trace("====>\n"); + + Trace("%p\n", DeviceObject); + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + + Context = ExAllocatePoolWithTag(NonPagedPool, sizeof (XENNET_CONTEXT), ' TEN'); + if (Context != NULL) { + Context->Capabilities = StackLocation->Parameters.DeviceCapabilities.Capabilities; + Context->CompletionRoutine = StackLocation->CompletionRoutine; + Context->CompletionContext = StackLocation->Context; + Context->CompletionControl = StackLocation->Control; + + StackLocation->CompletionRoutine = __QueryCapabilities; + StackLocation->Context = Context; + StackLocation->Control = SL_INVOKE_ON_SUCCESS; + } + + status = NdisDispatchPnp(DeviceObject, Irp); + + Trace("<====\n"); + + return status; +} + +NTSTATUS +DispatchPnp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + UCHAR MinorFunction; + NTSTATUS status; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + MinorFunction = StackLocation->MinorFunction; + + switch (StackLocation->MinorFunction) { + case IRP_MN_QUERY_CAPABILITIES: + status = QueryCapabilities(DeviceObject, Irp); + break; + + default: + status = NdisDispatchPnp(DeviceObject, Irp); + break; + } + + return status; +} + +NTSTATUS +DispatchFail( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(DeviceObject); + + Trace("%p\n", Irp); + + status = STATUS_UNSUCCESSFUL; + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +NTSTATUS +DriverEntry ( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +{ + NDIS_STATUS ndisStatus; + NDIS_MINIPORT_DRIVER_CHARACTERISTICS mpChars; + NDIS_CONFIGURATION_OBJECT ConfigurationObject; + NDIS_HANDLE ConfigurationHandle; + NDIS_STRING ParameterName; + PNDIS_CONFIGURATION_PARAMETER ParameterValue; + ULONG FailCreateClose; + ULONG FailDeviceControl; + + ExInitializeDriverRuntime(DrvRtPoolNxOptIn); + + Trace("====>\n"); + + Info("%s (%s)\n", + MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR, + DAY_STR "/" MONTH_STR "/" YEAR_STR); + + if (*InitSafeBootMode > 0) + return NDIS_STATUS_SUCCESS; + + // + // Register miniport with NDIS. + // + + NdisZeroMemory(&mpChars, sizeof(mpChars)); + mpChars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS, + mpChars.Header.Size = sizeof(NDIS_MINIPORT_DRIVER_CHARACTERISTICS); + mpChars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1; + + mpChars.MajorNdisVersion = 6; + mpChars.MinorNdisVersion = 0; + mpChars.MajorDriverVersion = MAJOR_VERSION; + mpChars.MinorDriverVersion = MINOR_VERSION; + + mpChars.CancelOidRequestHandler = AdapterCancelOidRequest; + mpChars.CancelSendHandler = AdapterCancelSendNetBufferLists; + mpChars.CheckForHangHandlerEx = AdapterCheckForHang; + mpChars.InitializeHandlerEx = MiniportInitialize; + mpChars.HaltHandlerEx = AdapterHalt; + mpChars.OidRequestHandler = AdapterOidRequest; + mpChars.PauseHandler = AdapterPause; + mpChars.DevicePnPEventNotifyHandler = AdapterPnPEventHandler; + mpChars.ResetHandlerEx = AdapterReset; + mpChars.RestartHandler = AdapterRestart; + mpChars.ReturnNetBufferListsHandler = AdapterReturnNetBufferLists; + mpChars.SendNetBufferListsHandler = AdapterSendNetBufferLists; + mpChars.ShutdownHandlerEx = AdapterShutdown; + mpChars.UnloadHandler = DriverUnload; + + MiniportDriverHandle = NULL; + ndisStatus = NdisMRegisterMiniportDriver(DriverObject, + RegistryPath, + NULL, + &mpChars, + &MiniportDriverHandle); + if (ndisStatus != NDIS_STATUS_SUCCESS) { + Error("Failed (0x%08X) to register miniport.\n", ndisStatus); + goto fail; + } + + ConfigurationObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT; + ConfigurationObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1; + ConfigurationObject.Header.Size = NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1; + ConfigurationObject.NdisHandle = MiniportDriverHandle; + ConfigurationObject.Flags = 0; + + ndisStatus = NdisOpenConfigurationEx(&ConfigurationObject, &ConfigurationHandle); + if (ndisStatus != NDIS_STATUS_SUCCESS) { + Error("Failed (0x%08X) to open driver configuration.\n", ndisStatus); + NdisMDeregisterMiniportDriver(MiniportDriverHandle); + goto fail; + } + + RtlInitUnicodeString(&ParameterName, L"FailCreateClose"); + + NdisReadConfiguration(&ndisStatus, + &ParameterValue, + ConfigurationHandle, + &ParameterName, + NdisParameterInteger); + if (ndisStatus == NDIS_STATUS_SUCCESS && + ParameterValue->ParameterType == NdisParameterInteger) + FailCreateClose = ParameterValue->ParameterData.IntegerData; + else + FailCreateClose = 0; + + RtlInitUnicodeString(&ParameterName, L"FailDeviceControl"); + + NdisReadConfiguration(&ndisStatus, + &ParameterValue, + ConfigurationHandle, + &ParameterName, + NdisParameterInteger); + if (ndisStatus == NDIS_STATUS_SUCCESS && + ParameterValue->ParameterType == NdisParameterInteger) + FailDeviceControl = ParameterValue->ParameterData.IntegerData; + else + FailDeviceControl = 0; + + NdisCloseConfiguration(ConfigurationHandle); + ndisStatus = NDIS_STATUS_SUCCESS; + + NdisDispatchPnp = DriverObject->MajorFunction[IRP_MJ_PNP]; + DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; + + if (FailCreateClose != 0) { + DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchFail; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchFail; + } + + if (FailDeviceControl != 0) { + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchFail; + } + +fail: + Trace("<====\n"); + return ndisStatus; +} + +VOID +DriverUnload ( + IN PDRIVER_OBJECT DriverObject + ) +{ + UNREFERENCED_PARAMETER(DriverObject); + + Trace("====>\n"); + + if (MiniportDriverHandle) + NdisMDeregisterMiniportDriver(MiniportDriverHandle); + + Trace("<====\n"); +} diff --git a/src/xennet/miniport.c b/src/xennet/miniport.c new file mode 100644 index 0000000..3ba84cf --- /dev/null +++ b/src/xennet/miniport.c @@ -0,0 +1,165 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define INITGUID 1 + +#include "common.h" + +#pragma warning( disable : 4098 ) + +static NTSTATUS +QueryVifInterface( + IN PDEVICE_OBJECT DeviceObject, + IN PADAPTER Adapter + ) +{ + KEVENT Event; + IO_STATUS_BLOCK StatusBlock; + PIRP Irp; + PIO_STACK_LOCATION StackLocation; + INTERFACE Interface; + NTSTATUS status; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + RtlZeroMemory(&StatusBlock, sizeof(IO_STATUS_BLOCK)); + + Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, + DeviceObject, + NULL, + 0, + NULL, + &Event, + &StatusBlock); + + status = STATUS_UNSUCCESSFUL; + if (Irp == NULL) + goto fail1; + + StackLocation = IoGetNextIrpStackLocation(Irp); + StackLocation->MinorFunction = IRP_MN_QUERY_INTERFACE; + + StackLocation->Parameters.QueryInterface.InterfaceType = &GUID_VIF_INTERFACE; + StackLocation->Parameters.QueryInterface.Size = sizeof (INTERFACE); + StackLocation->Parameters.QueryInterface.Version = VIF_INTERFACE_VERSION; + StackLocation->Parameters.QueryInterface.Interface = &Interface; + + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + status = IoCallDriver(DeviceObject, Irp); + if (status == STATUS_PENDING) { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + status = StatusBlock.Status; + } + + if (!NT_SUCCESS(status)) + goto fail2; + + status = STATUS_INVALID_PARAMETER; + if (Interface.Version != VIF_INTERFACE_VERSION) + goto fail3; + + Adapter->VifInterface = Interface.Context; + + return STATUS_SUCCESS; + +fail3: + Error("fail3\n"); + +fail2: + Error("fail2\n"); + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +NDIS_STATUS +MiniportInitialize ( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE MiniportDriverContext, + IN PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters + ) +{ + PADAPTER adapter = NULL; + NDIS_STATUS ndisStatus; + PDEVICE_OBJECT pdo; + NTSTATUS status; + + UNREFERENCED_PARAMETER(MiniportDriverContext); + UNREFERENCED_PARAMETER(MiniportInitParameters); + + Trace("====>\n"); + + adapter = ExAllocatePoolWithTag(NonPagedPool, sizeof (ADAPTER), ' TEN'); + + if (adapter == NULL) { + ndisStatus = NDIS_STATUS_RESOURCES; + goto exit; + } + + RtlZeroMemory(adapter, sizeof (ADAPTER)); + + pdo = NULL; + NdisMGetDeviceProperty(MiniportAdapterHandle, + &pdo, + NULL, + NULL, + NULL, + NULL); + + status = QueryVifInterface(pdo, adapter); + if (!NT_SUCCESS(status)) { + ndisStatus = NDIS_STATUS_ADAPTER_NOT_FOUND; + goto exit; + } + + adapter->AcquiredInterfaces = TRUE; + + ndisStatus = AdapterInitialize(adapter, MiniportAdapterHandle); + if (ndisStatus != NDIS_STATUS_SUCCESS) { + goto exit; + } + +exit: + if (ndisStatus != NDIS_STATUS_SUCCESS) { + if (adapter != NULL) { + AdapterDelete(&adapter); + } + } + + Trace("<====\n"); + return ndisStatus; +} diff --git a/src/xennet/project.h b/src/xennet/project.h new file mode 100644 index 0000000..7b90ead --- /dev/null +++ b/src/xennet/project.h @@ -0,0 +1,64 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include + +typedef struct _ADAPTER ADAPTER, *PADAPTER; + +NTSTATUS +DriverEntry ( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +VOID +DriverUnload ( + IN PDRIVER_OBJECT DriverObject + ); + +NDIS_STATUS +MpSetAdapterSettings( + IN PADAPTER Adapter + ); + +NDIS_STATUS +MpGetAdvancedSettings( + IN PADAPTER Adapter + ); + +#include "transmitter.h" +#include "receiver.h" +#include "adapter.h" diff --git a/src/xennet/receiver.c b/src/xennet/receiver.c new file mode 100644 index 0000000..efa45fa --- /dev/null +++ b/src/xennet/receiver.c @@ -0,0 +1,421 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "common.h" + +#pragma warning(disable:4711) + +NDIS_STATUS +ReceiverInitialize ( + IN PRECEIVER Receiver + ) +{ + PADAPTER Adapter; + NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; + NET_BUFFER_LIST_POOL_PARAMETERS poolParameters; + ULONG Cpu; + + Receiver->PutList = NULL; + for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) + Receiver->GetList[Cpu] = NULL; + + Adapter = CONTAINING_RECORD(Receiver, ADAPTER, Receiver); + + NdisZeroMemory(&poolParameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS)); + poolParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + poolParameters.Header.Revision = + NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1; + poolParameters.Header.Size = sizeof(poolParameters); + poolParameters.ProtocolId = 0; + poolParameters.ContextSize = 0; + poolParameters.fAllocateNetBuffer = TRUE; + poolParameters.PoolTag = ' TEN'; + + Receiver->NetBufferListPool = + NdisAllocateNetBufferListPool(Adapter->NdisAdapterHandle, + &poolParameters); + + if (!Receiver->NetBufferListPool) + ndisStatus = NDIS_STATUS_RESOURCES; + + return ndisStatus; +} + +VOID +ReceiverCleanup ( + IN PRECEIVER Receiver + ) +{ + ULONG Cpu; + PNET_BUFFER_LIST NetBufferList; + + ASSERT(Receiver != NULL); + + for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) { + NetBufferList = Receiver->GetList[Cpu]; + while (NetBufferList != NULL) { + PNET_BUFFER_LIST Next; + + Next = NET_BUFFER_LIST_NEXT_NBL(NetBufferList); + NET_BUFFER_LIST_NEXT_NBL(NetBufferList) = NULL; + + NdisFreeNetBufferList(NetBufferList); + + NetBufferList = Next; + } + } + + NetBufferList = Receiver->PutList; + while (NetBufferList != NULL) { + PNET_BUFFER_LIST Next; + + Next = NET_BUFFER_LIST_NEXT_NBL(NetBufferList); + NET_BUFFER_LIST_NEXT_NBL(NetBufferList) = NULL; + + NdisFreeNetBufferList(NetBufferList); + + NetBufferList = Next; + } + + if (Receiver->NetBufferListPool) { + NdisFreeNetBufferListPool(Receiver->NetBufferListPool); + Receiver->NetBufferListPool = NULL; + } + + return; +} + +PNET_BUFFER_LIST +ReceiverAllocateNetBufferList( + IN PRECEIVER Receiver, + IN PMDL Mdl, + IN ULONG Offset, + IN ULONG Length + ) +{ + ULONG Cpu; + PNET_BUFFER_LIST NetBufferList; + + Cpu = KeGetCurrentProcessorNumber(); + + NetBufferList = Receiver->GetList[Cpu]; + + if (NetBufferList == NULL) + Receiver->GetList[Cpu] = InterlockedExchangePointer(&Receiver->PutList, NULL); + + NetBufferList = Receiver->GetList[Cpu]; + + if (NetBufferList != NULL) { + PNET_BUFFER NetBuffer; + + Receiver->GetList[Cpu] = NET_BUFFER_LIST_NEXT_NBL(NetBufferList); + NET_BUFFER_LIST_NEXT_NBL(NetBufferList) = NULL; + + NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList); + NET_BUFFER_FIRST_MDL(NetBuffer) = Mdl; + NET_BUFFER_CURRENT_MDL(NetBuffer) = Mdl; + NET_BUFFER_DATA_OFFSET(NetBuffer) = Offset; + NET_BUFFER_DATA_LENGTH(NetBuffer) = Length; + NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer) = Offset; + } else { + NetBufferList = NdisAllocateNetBufferAndNetBufferList(Receiver->NetBufferListPool, + 0, + 0, + Mdl, + Offset, + Length); + ASSERT(IMPLY(NetBufferList != NULL, NET_BUFFER_LIST_NEXT_NBL(NetBufferList) == NULL)); + } + + return NetBufferList; +} + +VOID +ReceiverReleaseNetBufferList( + IN PRECEIVER Receiver, + IN PNET_BUFFER_LIST NetBufferList, + IN BOOLEAN Cache + ) +{ + if (Cache) { + PNET_BUFFER_LIST Old; + PNET_BUFFER_LIST New; + + ASSERT3P(NET_BUFFER_LIST_NEXT_NBL(NetBufferList), ==, NULL); + + do { + Old = Receiver->PutList; + + NET_BUFFER_LIST_NEXT_NBL(NetBufferList) = Old; + New = NetBufferList; + } while (InterlockedCompareExchangePointer(&Receiver->PutList, New, Old) != Old); + } else { + NdisFreeNetBufferList(NetBufferList); + } +} + +static FORCEINLINE ULONG +__ReceiverReturnNetBufferLists( + IN PRECEIVER Receiver, + IN PNET_BUFFER_LIST NetBufferList, + IN BOOLEAN Cache + ) +{ + PADAPTER Adapter; + ULONG Count; + + Adapter = CONTAINING_RECORD(Receiver, ADAPTER, Receiver); + + Count = 0; + while (NetBufferList != NULL) { + PNET_BUFFER_LIST Next; + PNET_BUFFER NetBuffer; + PMDL Mdl; + PXENVIF_RECEIVER_PACKET Packet; + + Next = NET_BUFFER_LIST_NEXT_NBL(NetBufferList); + NET_BUFFER_LIST_NEXT_NBL(NetBufferList) = NULL; + + NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList); + ASSERT3P(NET_BUFFER_NEXT_NB(NetBuffer), ==, NULL); + + Mdl = NET_BUFFER_FIRST_MDL(NetBuffer); + + ReceiverReleaseNetBufferList(Receiver, NetBufferList, Cache); + + Packet = CONTAINING_RECORD(Mdl, XENVIF_RECEIVER_PACKET, Mdl); + + VIF(ReturnPacket, + Adapter->VifInterface, + Packet); + + Count++; + NetBufferList = Next; + } + + return Count; +} + +VOID +ReceiverReturnNetBufferLists( + IN PRECEIVER Receiver, + IN PNET_BUFFER_LIST HeadNetBufferList, + IN ULONG Flags + ) +{ + ULONG Count; + + UNREFERENCED_PARAMETER(Flags); + + Count = __ReceiverReturnNetBufferLists(Receiver, HeadNetBufferList, TRUE); + (VOID) __InterlockedSubtract(&Receiver->InNDIS, Count); +} + +static PNET_BUFFER_LIST +ReceiverReceivePacket( + IN PRECEIVER Receiver, + IN PMDL Mdl, + IN ULONG Offset, + IN ULONG Length, + IN XENVIF_CHECKSUM_FLAGS Flags, + IN USHORT TagControlInformation + ) +{ + PADAPTER Adapter; + PNET_BUFFER_LIST NetBufferList; + NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo; + + Adapter = CONTAINING_RECORD(Receiver, ADAPTER, Receiver); + + NetBufferList = ReceiverAllocateNetBufferList(Receiver, + Mdl, + Offset, + Length); + if (NetBufferList == NULL) + goto fail1; + + NetBufferList->SourceHandle = Adapter->NdisAdapterHandle; + + csumInfo.Value = 0; + + csumInfo.Receive.IpChecksumSucceeded = Flags.IpChecksumSucceeded; + csumInfo.Receive.IpChecksumFailed = Flags.IpChecksumFailed; + + csumInfo.Receive.TcpChecksumSucceeded = Flags.TcpChecksumSucceeded; + csumInfo.Receive.TcpChecksumFailed = Flags.TcpChecksumFailed; + + csumInfo.Receive.UdpChecksumSucceeded = Flags.UdpChecksumSucceeded; + csumInfo.Receive.UdpChecksumFailed = Flags.UdpChecksumFailed; + + NET_BUFFER_LIST_INFO(NetBufferList, TcpIpChecksumNetBufferListInfo) = (PVOID)(ULONG_PTR)csumInfo.Value; + + if (TagControlInformation != 0) { + NDIS_NET_BUFFER_LIST_8021Q_INFO Ieee8021QInfo; + + UNPACK_TAG_CONTROL_INFORMATION(TagControlInformation, + Ieee8021QInfo.TagHeader.UserPriority, + Ieee8021QInfo.TagHeader.CanonicalFormatId, + Ieee8021QInfo.TagHeader.VlanId); + + if (Ieee8021QInfo.TagHeader.VlanId != 0) + goto fail2; + + NET_BUFFER_LIST_INFO(NetBufferList, Ieee8021QNetBufferListInfo) = Ieee8021QInfo.Value; + } + + return NetBufferList; + +fail2: + ReceiverReleaseNetBufferList(Receiver, NetBufferList, TRUE); + +fail1: + return NULL; +} + +static VOID +ReceiverPushPackets( + IN PRECEIVER Receiver, + IN PNET_BUFFER_LIST NetBufferList, + IN ULONG Count, + IN BOOLEAN LowResources + ) +{ + PADAPTER Adapter; + ULONG Flags; + LONG InNDIS; + + Adapter = CONTAINING_RECORD(Receiver, ADAPTER, Receiver); + + InNDIS = Receiver->InNDIS; + + Flags = NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL; + if (LowResources) { + Flags |= NDIS_RECEIVE_FLAGS_RESOURCES; + } else { + InNDIS = __InterlockedAdd(&Receiver->InNDIS, Count); + } + + for (;;) { + LONG InNDISMax; + + InNDISMax = Receiver->InNDISMax; + KeMemoryBarrier(); + + if (InNDIS <= InNDISMax) + break; + + if (InterlockedCompareExchange(&Receiver->InNDISMax, InNDIS, InNDISMax) == InNDISMax) + break; + } + + NdisMIndicateReceiveNetBufferLists(Adapter->NdisAdapterHandle, + NetBufferList, + NDIS_DEFAULT_PORT_NUMBER, + Count, + Flags); + + if (LowResources) + (VOID) __ReceiverReturnNetBufferLists(Receiver, NetBufferList, FALSE); +} + +#define IN_NDIS_MAX 1024 + +VOID +ReceiverReceivePackets( + IN PRECEIVER Receiver, + IN PLIST_ENTRY List + ) +{ + PADAPTER Adapter; + PNET_BUFFER_LIST HeadNetBufferList; + PNET_BUFFER_LIST *TailNetBufferList; + ULONG Count; + BOOLEAN LowResources; + + Adapter = CONTAINING_RECORD(Receiver, ADAPTER, Receiver); + LowResources = FALSE; + +again: + HeadNetBufferList = NULL; + TailNetBufferList = &HeadNetBufferList; + Count = 0; + + while (!IsListEmpty(List)) { + PLIST_ENTRY ListEntry; + PXENVIF_RECEIVER_PACKET Packet; + PMDL Mdl; + ULONG Offset; + ULONG Length; + XENVIF_CHECKSUM_FLAGS Flags; + USHORT TagControlInformation; + PNET_BUFFER_LIST NetBufferList; + + if (!LowResources && + Receiver->InNDIS + Count > IN_NDIS_MAX) + break; + + ListEntry = RemoveHeadList(List); + ASSERT(ListEntry != List); + + RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY)); + + Packet = CONTAINING_RECORD(ListEntry, XENVIF_RECEIVER_PACKET, ListEntry); + Mdl = &Packet->Mdl; + Offset = Packet->Offset; + Length = Packet->Length; + Flags = Packet->Flags; + TagControlInformation = Packet->TagControlInformation; + + NetBufferList = ReceiverReceivePacket(Receiver, Mdl, Offset, Length, Flags, TagControlInformation); + + if (NetBufferList != NULL) { + *TailNetBufferList = NetBufferList; + TailNetBufferList = &NET_BUFFER_LIST_NEXT_NBL(NetBufferList); + Count++; + } else { + VIF(ReturnPacket, + Adapter->VifInterface, + Packet); + } + } + + if (Count != 0) { + ASSERT(HeadNetBufferList != NULL); + + ReceiverPushPackets(Receiver, HeadNetBufferList, Count, LowResources); + } + + if (!IsListEmpty(List)) { + ASSERT(!LowResources); + LowResources = TRUE; + goto again; + } +} diff --git a/src/xennet/receiver.h b/src/xennet/receiver.h new file mode 100644 index 0000000..fe32057 --- /dev/null +++ b/src/xennet/receiver.h @@ -0,0 +1,77 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +typedef struct _RECEIVER { + NDIS_HANDLE NetBufferListPool; + PNET_BUFFER_LIST PutList; + PNET_BUFFER_LIST GetList[MAXIMUM_PROCESSORS]; + LONG InNDIS; + LONG InNDISMax; + XENVIF_OFFLOAD_OPTIONS OffloadOptions; +} RECEIVER, *PRECEIVER; + +VOID +ReceiverDebugDump ( + IN PRECEIVER Receiver + ); + +VOID +ReceiverCleanup ( + IN PRECEIVER Receiver + ); + +VOID +ReceiverHandleNotification ( + IN PRECEIVER Receiver + ); + +NDIS_STATUS +ReceiverInitialize ( + IN PRECEIVER Receiver + ); + +VOID +ReceiverReturnNetBufferLists ( + IN PRECEIVER Receiver, + IN PNET_BUFFER_LIST NetBufferList, + IN ULONG ReturnFlags + ); + +VOID +ReceiverWaitForPacketReturn( + IN PRECEIVER Receiver, + IN BOOLEAN Locked + ); + +void ReceiverPause(PRECEIVER receiver); +void ReceiverUnpause(PRECEIVER receiver); diff --git a/src/xennet/std.h b/src/xennet/std.h new file mode 100644 index 0000000..c72325a --- /dev/null +++ b/src/xennet/std.h @@ -0,0 +1,45 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +#pragma warning(disable:4214) // bit field types other than int + +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4115) // named type definition in parentheses +#pragma warning(disable:4127) // conditional expression is constant +#pragma warning(disable:4054) // cast of function pointer to PVOID +#pragma warning(disable:4206) // translation unit is empty + +#include +#include + +extern PULONG InitSafeBootMode; diff --git a/src/xennet/transmitter.c b/src/xennet/transmitter.c new file mode 100644 index 0000000..d1bfff3 --- /dev/null +++ b/src/xennet/transmitter.c @@ -0,0 +1,313 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "common.h" + +#pragma warning(disable:4711) + +NDIS_STATUS +TransmitterInitialize( + IN PTRANSMITTER Transmitter, + IN PADAPTER Adapter + ) +{ + Transmitter->Adapter = Adapter; + + return NDIS_STATUS_SUCCESS; +} + +VOID +TransmitterEnable( + IN PTRANSMITTER Transmitter + ) +{ + XENVIF_TRANSMITTER_PACKET_METADATA Metadata; + + Metadata.OffsetOffset = (LONG_PTR)&NET_BUFFER_CURRENT_MDL_OFFSET((PNET_BUFFER)NULL) - + (LONG_PTR)&NET_BUFFER_MINIPORT_RESERVED((PNET_BUFFER)NULL); + Metadata.LengthOffset = (LONG_PTR)&NET_BUFFER_DATA_LENGTH((PNET_BUFFER)NULL) - + (LONG_PTR)&NET_BUFFER_MINIPORT_RESERVED((PNET_BUFFER)NULL); + Metadata.MdlOffset = (LONG_PTR)&NET_BUFFER_CURRENT_MDL((PNET_BUFFER)NULL) - + (LONG_PTR)&NET_BUFFER_MINIPORT_RESERVED((PNET_BUFFER)NULL); + + VIF(UpdatePacketMetadata, + Transmitter->Adapter->VifInterface, + &Metadata); +} + +VOID +TransmitterDelete ( + IN OUT PTRANSMITTER *Transmitter + ) +{ + ASSERT(Transmitter != NULL); + + if (*Transmitter) { + ExFreePool(*Transmitter); + *Transmitter = NULL; + } +} + +typedef struct _NET_BUFFER_LIST_RESERVED { + LONG Reference; +} NET_BUFFER_LIST_RESERVED, *PNET_BUFFER_LIST_RESERVED; + +C_ASSERT(sizeof (NET_BUFFER_LIST_RESERVED) <= RTL_FIELD_SIZE(NET_BUFFER_LIST, MiniportReserved)); + +typedef struct _NET_BUFFER_RESERVED { + XENVIF_TRANSMITTER_PACKET Packet; + PNET_BUFFER_LIST NetBufferList; +} NET_BUFFER_RESERVED, *PNET_BUFFER_RESERVED; + +C_ASSERT(sizeof (NET_BUFFER_RESERVED) <= RTL_FIELD_SIZE(NET_BUFFER, MiniportReserved)); + +static VOID +TransmitterAbortNetBufferList( + IN PTRANSMITTER Transmitter, + IN PNET_BUFFER_LIST NetBufferList + ) +{ + ASSERT3P(NET_BUFFER_LIST_NEXT_NBL(NetBufferList), ==, NULL); + + NET_BUFFER_LIST_STATUS(NetBufferList) = NDIS_STATUS_NOT_ACCEPTED; + + NdisMSendNetBufferListsComplete(Transmitter->Adapter->NdisAdapterHandle, + NetBufferList, + NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); +} + +VOID +TransmitterAbortPackets( + IN PTRANSMITTER Transmitter, + IN PXENVIF_TRANSMITTER_PACKET Packet + ) +{ + while (Packet != NULL) { + PXENVIF_TRANSMITTER_PACKET Next; + PNET_BUFFER_RESERVED Reserved; + PNET_BUFFER_LIST NetBufferList; + PNET_BUFFER_LIST_RESERVED ListReserved; + + Next = Packet->Next; + Packet->Next = NULL; + + Reserved = CONTAINING_RECORD(Packet, NET_BUFFER_RESERVED, Packet); + + NetBufferList = Reserved->NetBufferList; + ASSERT(NetBufferList != NULL); + + ListReserved = (PNET_BUFFER_LIST_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(NetBufferList); + + ASSERT(ListReserved->Reference != 0); + if (InterlockedDecrement(&ListReserved->Reference) == 0) + TransmitterAbortNetBufferList(Transmitter, NetBufferList); + + Packet = Next; + } +} + +VOID +TransmitterSendNetBufferLists( + IN PTRANSMITTER Transmitter, + IN PNET_BUFFER_LIST NetBufferList, + IN NDIS_PORT_NUMBER PortNumber, + IN ULONG SendFlags + ) +{ + PXENVIF_TRANSMITTER_PACKET HeadPacket; + PXENVIF_TRANSMITTER_PACKET *TailPacket; + KIRQL Irql; + + UNREFERENCED_PARAMETER(PortNumber); + + HeadPacket = NULL; + TailPacket = &HeadPacket; + + if (!NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags)) { + ASSERT3U(NDIS_CURRENT_IRQL(), <=, DISPATCH_LEVEL); + NDIS_RAISE_IRQL_TO_DISPATCH(&Irql); + } else { + Irql = DISPATCH_LEVEL; + } + + while (NetBufferList != NULL) { + PNET_BUFFER_LIST ListNext; + PNET_BUFFER_LIST_RESERVED ListReserved; + PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO LargeSendInfo; + PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO ChecksumInfo; + PNDIS_NET_BUFFER_LIST_8021Q_INFO Ieee8021QInfo; + PNET_BUFFER NetBuffer; + + ListNext = NET_BUFFER_LIST_NEXT_NBL(NetBufferList); + NET_BUFFER_LIST_NEXT_NBL(NetBufferList) = NULL; + + ListReserved = (PNET_BUFFER_LIST_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(NetBufferList); + RtlZeroMemory(ListReserved, sizeof (NET_BUFFER_LIST_RESERVED)); + + LargeSendInfo = (PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO)&NET_BUFFER_LIST_INFO(NetBufferList, + TcpLargeSendNetBufferListInfo); + ChecksumInfo = (PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO)&NET_BUFFER_LIST_INFO(NetBufferList, + TcpIpChecksumNetBufferListInfo); + Ieee8021QInfo = (PNDIS_NET_BUFFER_LIST_8021Q_INFO)&NET_BUFFER_LIST_INFO(NetBufferList, + Ieee8021QNetBufferListInfo); + + NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList); + while (NetBuffer != NULL) { + PNET_BUFFER_RESERVED Reserved; + PXENVIF_TRANSMITTER_PACKET Packet; + + Reserved = (PNET_BUFFER_RESERVED)NET_BUFFER_MINIPORT_RESERVED(NetBuffer); + RtlZeroMemory(Reserved, sizeof (NET_BUFFER_RESERVED)); + + Reserved->NetBufferList = NetBufferList; + ListReserved->Reference++; + + Packet = &Reserved->Packet; + + if (ChecksumInfo->Transmit.IsIPv4) { + if (ChecksumInfo->Transmit.IpHeaderChecksum) + Packet->Send.OffloadOptions.OffloadIpVersion4HeaderChecksum = 1; + + if (ChecksumInfo->Transmit.TcpChecksum) + Packet->Send.OffloadOptions.OffloadIpVersion4TcpChecksum = 1; + + if (ChecksumInfo->Transmit.UdpChecksum) + Packet->Send.OffloadOptions.OffloadIpVersion4UdpChecksum = 1; + } + + if (ChecksumInfo->Transmit.IsIPv6) { + if (ChecksumInfo->Transmit.TcpChecksum) + Packet->Send.OffloadOptions.OffloadIpVersion6TcpChecksum = 1; + + if (ChecksumInfo->Transmit.UdpChecksum) + Packet->Send.OffloadOptions.OffloadIpVersion6UdpChecksum = 1; + } + + if (Ieee8021QInfo->TagHeader.UserPriority != 0) { + Packet->Send.OffloadOptions.OffloadTagManipulation = 1; + + ASSERT3U(Ieee8021QInfo->TagHeader.CanonicalFormatId, ==, 0); + ASSERT3U(Ieee8021QInfo->TagHeader.VlanId, ==, 0); + + PACK_TAG_CONTROL_INFORMATION(Packet->Send.TagControlInformation, + Ieee8021QInfo->TagHeader.UserPriority, + Ieee8021QInfo->TagHeader.CanonicalFormatId, + Ieee8021QInfo->TagHeader.VlanId); + } + + if (LargeSendInfo->LsoV2Transmit.MSS != 0) { + if (LargeSendInfo->LsoV2Transmit.IPVersion == NDIS_TCP_LARGE_SEND_OFFLOAD_IPv4) + Packet->Send.OffloadOptions.OffloadIpVersion4LargePacket = 1; + + if (LargeSendInfo->LsoV2Transmit.IPVersion == NDIS_TCP_LARGE_SEND_OFFLOAD_IPv6) + Packet->Send.OffloadOptions.OffloadIpVersion6LargePacket = 1; + + ASSERT3U(LargeSendInfo->LsoV2Transmit.MSS >> 16, ==, 0); + Packet->Send.MaximumSegmentSize = (USHORT)LargeSendInfo->LsoV2Transmit.MSS; + } + + Packet->Send.OffloadOptions.Value &= Transmitter->OffloadOptions.Value; + + ASSERT3P(Packet->Next, ==, NULL); + *TailPacket = Packet; + TailPacket = &Packet->Next; + + NetBuffer = NET_BUFFER_NEXT_NB(NetBuffer); + } + + NetBufferList = ListNext; + } + + if (HeadPacket != NULL) { + NTSTATUS status; + + status = VIF(QueuePackets, + Transmitter->Adapter->VifInterface, + HeadPacket); + if (!NT_SUCCESS(status)) + TransmitterAbortPackets(Transmitter, HeadPacket); + } + + NDIS_LOWER_IRQL(Irql, DISPATCH_LEVEL); +} + +static VOID +TransmitterCompleteNetBufferList( + IN PTRANSMITTER Transmitter, + IN PNET_BUFFER_LIST NetBufferList + ) +{ + PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO LargeSendInfo; + + ASSERT3P(NET_BUFFER_LIST_NEXT_NBL(NetBufferList), ==, NULL); + + LargeSendInfo = (PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO)&NET_BUFFER_LIST_INFO(NetBufferList, + TcpLargeSendNetBufferListInfo); + + if (LargeSendInfo->LsoV2Transmit.MSS != 0) + LargeSendInfo->LsoV2TransmitComplete.Reserved = 0; + + NET_BUFFER_LIST_STATUS(NetBufferList) = NDIS_STATUS_SUCCESS; + + NdisMSendNetBufferListsComplete(Transmitter->Adapter->NdisAdapterHandle, + NetBufferList, + NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); +} + +VOID +TransmitterCompletePackets( + IN PTRANSMITTER Transmitter, + IN PXENVIF_TRANSMITTER_PACKET Packet + ) +{ + while (Packet != NULL) { + PXENVIF_TRANSMITTER_PACKET Next; + PNET_BUFFER_RESERVED Reserved; + PNET_BUFFER_LIST NetBufferList; + PNET_BUFFER_LIST_RESERVED ListReserved; + + Next = Packet->Next; + Packet->Next = NULL; + + Reserved = CONTAINING_RECORD(Packet, NET_BUFFER_RESERVED, Packet); + + NetBufferList = Reserved->NetBufferList; + ASSERT(NetBufferList != NULL); + + ListReserved = (PNET_BUFFER_LIST_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(NetBufferList); + + ASSERT(ListReserved->Reference != 0); + if (InterlockedDecrement(&ListReserved->Reference) == 0) + TransmitterCompleteNetBufferList(Transmitter, NetBufferList); + + Packet = Next; + } +} diff --git a/src/xennet/transmitter.h b/src/xennet/transmitter.h new file mode 100644 index 0000000..93d734b --- /dev/null +++ b/src/xennet/transmitter.h @@ -0,0 +1,75 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +typedef struct _TRANSMITTER { + PADAPTER Adapter; + XENVIF_OFFLOAD_OPTIONS OffloadOptions; +} TRANSMITTER, *PTRANSMITTER; + +VOID +TransmitterCleanup ( + IN OUT PTRANSMITTER* Transmitter + ); + +NDIS_STATUS +TransmitterInitialize ( + IN PTRANSMITTER Transmitter, + IN PADAPTER Adapter + ); + +VOID +TransmitterEnable ( + IN PTRANSMITTER Transmitter + ); + +VOID +TransmitterDelete ( + IN OUT PTRANSMITTER* Transmitter + ); + +VOID +TransmitterSendNetBufferLists ( + IN PTRANSMITTER Transmitter, + IN PNET_BUFFER_LIST NetBufferList, + IN NDIS_PORT_NUMBER PortNumber, + IN ULONG SendFlags + ); + +VOID +TransmitterCompletePackets( + IN PTRANSMITTER Transmitter, + IN PXENVIF_TRANSMITTER_PACKET Packet + ); + +void TransmitterPause(PTRANSMITTER Transmitter); +void TransmitterUnpause(PTRANSMITTER Transmitter); diff --git a/src/xennet/xennet.rc b/src/xennet/xennet.rc new file mode 100644 index 0000000..784ea12 --- /dev/null +++ b/src/xennet/xennet.rc @@ -0,0 +1,56 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + + +#undef VER_COMPANYNAME_STR +#undef VER_PRODUCTNAME_STR +#undef VER_PRODUCTVERSION +#undef VER_PRODUCTVERSION_STR + +#define VER_COMPANYNAME_STR "Citrix Systems Inc." +#define VER_LEGALCOPYRIGHT_STR "Copyright " YEAR_STR VER_COMPANYNAME_STR + +#include + +#define VER_PRODUCTNAME_STR "Citrix PV Tools for Virtual Machines" +#define VER_PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,MICRO_VERSION,BUILD_NUMBER +#define VER_PRODUCTVERSION_STR MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR + +#define VER_INTERNALNAME_STR "XENNET.SYS" +#define VER_FILEDESCRIPTION_STR "Citrix PV Network Driver" + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM + +#include