From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM04-MW2-obe.outbound.protection.outlook.com (NAM04-MW2-obe.outbound.protection.outlook.com [40.107.101.67]) by mx.groups.io with SMTP id smtpd.web10.4928.1680866858980169326 for ; Fri, 07 Apr 2023 04:27:39 -0700 Authentication-Results: mx.groups.io; dkim=fail, err=mail: missing word in phrase: charset not supported: "iso-2022-jp"; spf=pass (domain: ami.com, ip: 40.107.101.67, mailfrom: richardho@ami.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=UFwNEg+W22otvJHQq3BE/yWsboEXusqcx4tG2gAey85wXf3HLEr2BhoaYS7gVrninZnyZVTX/79WYDR4vC8wolWlzzQPi1siCbzmitXaOrxPkZ3D0BfJn19T2W1h6Q081YYY6/j/0eY826BEOc7JEyFcCNodSnNXpZBLHQEkIVzL2Sj54vz1ZEQzS9qm7/iCwACJkrg33YsWy5hJ32m71ByqaglsKwpndKKccr3rrU9ax1V/NxUUewrS6e2aob2A+MsGn4lkzOQf3EW/tYR0p0Banj9wjB7uCjIR56BqPmDD3Gl3+C3jNmAAOt3Wmz5C/37Bt+A0FWGQP0C0NnsS+g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=+9f34ZZP1VH0WAdc/DW0dKsj98/waEQxj4/cV8oSfe4=; b=MljJlFl5R+yB2GHiT+W4eeFICeLKZV3vREuZenUgVflHnbSTbDugKIcsHpelV6c+vV9qBj7TVoFhbiJKQbE5o5btffZbDi+xNftPW6f4o7cSqMVDzMjAy7OavT8b+DtfSlAWGAONfNUu7VS09g8QHNCrDKozgkqUUkgR3zpjI9ciMIqDHGwSWUBNMrplCVgx/7Nby06qtAzTTZoOCEFnUdC8hwVhQ4awd8ENEjLCCsY/tihmIjpCKzpC7LfMZvV0jpFYYPIL23i40KZWGloShX+oSqEwQgqYggvHeHnG7kz0sqtTP/eYbRE5UgOpIQtVQom6kuhjZTuNJErN9VS85Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=ami.com; dmarc=pass action=none header.from=ami.com; dkim=pass header.d=ami.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ami.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=+9f34ZZP1VH0WAdc/DW0dKsj98/waEQxj4/cV8oSfe4=; b=RRGDfNhtROXP1Hkgp3RudvLcWlfOrAsKWfKf2HJiDHtip/328+0+VY1m/MNEHC5iL5TGt+KWW4Wkn25LkvbI7+3iXqN0Je9HT1lrKKP5x7kUxGbdYY+8rDwPWJMsSs7szRG1i3+uGiLbtAeDlxvBxpe3Bdo+RRA/IsThphCsJUU= Received: from CY8PR10MB6441.namprd10.prod.outlook.com (2603:10b6:930:63::16) by DS7PR10MB4893.namprd10.prod.outlook.com (2603:10b6:5:3a2::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6277.35; Fri, 7 Apr 2023 11:27:28 +0000 Received: from CY8PR10MB6441.namprd10.prod.outlook.com ([fe80::b965:7721:e4d7:5409]) by CY8PR10MB6441.namprd10.prod.outlook.com ([fe80::b965:7721:e4d7:5409%6]) with mapi id 15.20.6277.031; Fri, 7 Apr 2023 11:27:27 +0000 From: =?UTF-8?B?UmljaGFyZEhvIFvkvZXmmI7lv6Bd?= To: "devel@edk2.groups.io" CC: Andrew Fish , Leif Lindholm , Michael D Kinney , Michael Kubacki , Zhiguang Liu , Liming Gao , Rebecca Cran , Tinh Nguyen , =?iso-2022-jp?B?VG9ueSBMbyAoGyRCTWU2Yj4+GyhCKQ==?= Subject: [PATCH v7 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support Thread-Topic: [PATCH v7 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support Thread-Index: AQHZaUPu7eInPejPwEWzz4ffhuMEYw== Date: Fri, 7 Apr 2023 11:27:27 +0000 Message-ID: <20230407112638.405-1-richardho@ami.com> Accept-Language: zh-TW, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-mailer: git-send-email 2.35.1.windows.2 authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=ami.com; x-ms-publictraffictype: Email x-ms-traffictypediagnostic: CY8PR10MB6441:EE_|DS7PR10MB4893:EE_ x-ms-office365-filtering-correlation-id: abdf5a18-2e31-4f4b-1143-08db375b116c x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: iDEjuaJKWEf6FglSu8+YdjEigaY/9ap66GufR2FqlVZdFJQf0EzLNi1LLO1CFViJL+PWMT+ejTee1CGzz2UcBA8vFl5jxlq/wXTcpDKCG1HiE4c2nydAiGerBErRnktlTey38+OiIqjK14IF+ba2yD9SHoRXhi9q1LUHI2lakpOtdNTOvm1eMzT4L+eAQ1IXGl2uBCEpN9kS9OePfDOcm8lC1tBE7VufaVBWJGFiE5BZaGdFYDThsC0c8sUJljKFgYFPzo73L2QRN+jZKAlQuKt2fmo7DoJWSiNPv1cWD1UQVjTu0NjIWkFbfyPEdEWzQRapoBWJM4yQA91L5DYR54iaxHEf9siP3hi8ej5fBZMeO/WUFNVt4g/4XSERoQtHsO8e+clUb/tVUvgKV3FX96htWmAKxyfwFrqoeO0tWkcex4zYSscpRZwl454a2jyzroTdJXBTZNPqJNhoO6KIapOwtILlIGvy8Lg71ADphjhN2bY+wMHP9DQ/aafCDlAMLws+fsLMerEPBcipBQN8RoIel+tgStm5irTpki9uddCwvCQX256U4NFMPAmyD58x40YcA39tjTOJeOVef+kxJNVbHsf4oWLY3MJyIIrJb22TjB5qXQnNdHU39C/uqYDBF9GnrmNa9cMZQ5gA8JwTUg== x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CY8PR10MB6441.namprd10.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230028)(4636009)(366004)(376002)(136003)(39850400004)(346002)(396003)(451199021)(19627235002)(54906003)(76116006)(91956017)(66946007)(66556008)(66476007)(66446008)(64756008)(8676002)(4326008)(6916009)(316002)(71200400001)(41300700001)(45080400002)(8936002)(5660300002)(6486002)(30864003)(2906002)(83380400001)(6512007)(6506007)(186003)(26005)(1076003)(478600001)(2616005)(122000001)(38100700002)(38070700005)(36756003)(85182001)(40140700001)(86362001)(579004)(559001)(44824005);DIR:OUT;SFP:1101; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?iso-2022-jp?B?YzBvTlNKbkNKMi9NYmgrcGoyMSttSG8zUjczaDFvNjNJU2h6ckJXMTNh?= =?iso-2022-jp?B?YVNXWUF1YVllMDErRGJqM3dTbGZlcVIzMU9KYUp0R240S3lEWWdzd1or?= =?iso-2022-jp?B?ZkxpaHFnUWplTUxTQ2YzV0h1NWRBYXVXcHQvdXptZjZjb29BUlRtVEN3?= =?iso-2022-jp?B?UXBxS2k0REV3RElFQ0pXN2FxczVYZFpyVUFZOUp1WHlxL05QVmQ1Z1Rs?= =?iso-2022-jp?B?Nm83UzNqamlJdGcvZDVFaGFxOEllM09LSkhnNktMNEJUSzlEemx2NW5T?= =?iso-2022-jp?B?QUVod0I5K0dMYklsczdWRVQyMVdaSEVuOUUvb1Nud2ZPdlFxUXVUVGFC?= =?iso-2022-jp?B?RmJpS0c1RHNTOUxNNjk5ODBEeEJqYmtWaUtpS0h0NEtHdzBqTXNDNHkv?= =?iso-2022-jp?B?clA4QXJTN2s3aXFwWUhvUzgza25CNlNsWFovampZZHF0ZDVnWWlaL0pX?= =?iso-2022-jp?B?aUhtbXdTS0dHZEkwUzBjQWN0U2Z1ODd3K0tFODdRNnI2STc3Mnk2RWFu?= =?iso-2022-jp?B?QVZyQ2hPNWw5U3p4UXFJYkhXTjRYOVJIdWhuTWptaENnNG9IOUFIS2ox?= =?iso-2022-jp?B?aEVMRGdTR1RIdzZyejZBeFNIMlBsbzhQa2xWNVRUQXRSWGlyS3V6am1T?= =?iso-2022-jp?B?U2cvVklpcm5RY1VVOTczWE1pNmNFdSt4aHlGOTk3eWZIZHJqZXV1V3o4?= =?iso-2022-jp?B?bGRzakM2d1FXUUpOWDVIOFRiU2FiU1U3ZDlsdkl5WUxYMkIrcmhuWVJk?= =?iso-2022-jp?B?ckpua09Za3hXR3ZUSGNjamdOZmtuN1F6NWJpN0xiTW9PRzJ3V3NMaFdi?= =?iso-2022-jp?B?bWpoZ290ZjNUMnRDNDRzZktXcjZ4R3ROcXhETUlkbEpTWnd2ZzVJMW41?= =?iso-2022-jp?B?RzRiTnB6Tm9SSGlCY1U1MVcybmVsTFFveHNSS1poSm1WbXhIdEhoekNI?= =?iso-2022-jp?B?enZ3WTZQUEU0dWRGV0I0WlhqcWQyczU0Ti9zTzYvc0RFU3FKenZncXRh?= =?iso-2022-jp?B?ZFZjTHB3bG5JRmJtaWJaUE1abnhLN25UZWIySHZYLy95Q2JZd0xWUmxn?= =?iso-2022-jp?B?UDJOTDAwYk53UG04YVRYaEhsWWZuVjBDeGhLQ05nMHlBbUd2dWZiNGhu?= =?iso-2022-jp?B?cjlUTDMvQzExQm10VS9nTkROTEIxTnFqdEcrMzlwSlhrdUl1N0lXWXZn?= =?iso-2022-jp?B?REkrQ21kblQySFRSYkF3Yk9TMENiVW0ybStRSUxHdkdkcTNZZ2QzMytB?= =?iso-2022-jp?B?RWo4eUkxSDRnWlE2bEd2ZTIzcUw1NVpFQnc1QkY5V0s4UHhUeTl2bVZI?= =?iso-2022-jp?B?U3hNZ0hQMG96TElHcTlGYUc0V3pOeFp1Wk9SbzJTbWJsWUhYV0YrbWxu?= =?iso-2022-jp?B?dUVnR3pRVS9tL1lqVXZtOUFrejlTaW5HSENSaUZZbDJ4NHFLMW1waU1Q?= =?iso-2022-jp?B?ZXJQOE1HSmt3NXhSRXBDcEVGeEM4VUQybGVyZ3JIMkM0Z2NMSTc2R2Yx?= =?iso-2022-jp?B?S2FINHVPOTZHK0U5WSsyUWQ0Z3VhckwzOUpjVkxOaEp2NlNMM3R2RERM?= =?iso-2022-jp?B?ODNZUGFaR1ZNOVF3OWcvdHFDNHpsVm8yVzR5QURudzAvWllTaXpLQlpK?= =?iso-2022-jp?B?bVIwVDd6SFJIQmZvSDNFY1BYN09uNlhXcTVwZWkyaE40a1ZteTcrY1Nq?= =?iso-2022-jp?B?UExwZjJiaVVNcEFWR1M4ZzdqNTVSM0Y3a0svMTIzOFR3anBadkVqMDVE?= =?iso-2022-jp?B?S2ZVcFV6UHppbDVOMFNaNnY4OWJzKzVYWThDZkdnVWNSenNKbThzd2ZL?= =?iso-2022-jp?B?Nzh3b01vTmQ4LzhDZ0dsMjRoL0c0U0NBaDR0QVQ3ZmlnUU1CUjV0WjY4?= =?iso-2022-jp?B?UGxKSTB1N2VESk1rZU5oNEx6bjRrVWl4ckREMHdVWko2NXZvNnpWcnFX?= =?iso-2022-jp?B?K2R1RlRld1FhMU5rV3dSUTNBK01zV3ZVcXFYK3h3ZHBRdFdQalU1azRP?= =?iso-2022-jp?B?OWhRbUwyMXUxSXpiNjVmb0Z3RlV1SmtIZlpHaFZCeGd6S0FPSXFObCty?= =?iso-2022-jp?B?YVNubTRYblphdys4THQ0QVF2M01mQjczV0UwZG1idjB4YnQ1czdDVHZv?= =?iso-2022-jp?B?Q3dndHJJa201elg1S044OVI2OU9keE9zMldQRTl0ZUtUWHZnS0dGcEdu?= =?iso-2022-jp?B?VjlzZElISmhPRWxKc0FnWWZtb0pRZVZQdjVZVkVKbFlveGlPQTF2bFhh?= =?iso-2022-jp?B?MWZIUGo4SDIrZEFydlo0L0Fpb0xyNG9VL0NBR2JJMURGbjFFSStwT0pL?= =?iso-2022-jp?B?VkE1Mw==?= MIME-Version: 1.0 X-OriginatorOrg: ami.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: CY8PR10MB6441.namprd10.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: abdf5a18-2e31-4f4b-1143-08db375b116c X-MS-Exchange-CrossTenant-originalarrivaltime: 07 Apr 2023 11:27:27.6291 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 27e97857-e15f-486c-b58e-86c2b3040f93 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: a5jkZFJ5U9514pdVqjzfxdTwiQSlrTe83N3yLRpgLzvf/uPI0xZHqsqVbOxH6Ed9lll5uUN+K6dzARrNo74K0w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS7PR10MB4893 Content-Language: en-US Content-Type: text/plain; charset="iso-2022-jp" Content-Transfer-Encoding: quoted-printable This driver provides UEFI driver for USB RNDIS device Signed-off-by: Richard Ho Cc: Andrew Fish Cc: Leif Lindholm Cc: Michael D Kinney Cc: Michael Kubacki Cc: Zhiguang Liu Cc: Liming Gao Cc: Rebecca Cran Tested-by: Tinh Nguyen Reviewed-by: Tony Lo --- .../Protocol/EdkIIUsbEthernetProtocol.h | 878 ++++++++ UsbNetworkPkg/NetworkCommon/ComponentName.c | 263 +++ UsbNetworkPkg/NetworkCommon/DriverBinding.c | 595 ++++++ UsbNetworkPkg/NetworkCommon/DriverBinding.h | 266 +++ UsbNetworkPkg/NetworkCommon/NetworkCommon.inf | 49 + UsbNetworkPkg/NetworkCommon/PxeFunction.c | 1803 +++++++++++++++++ UsbNetworkPkg/ReadMe.md | 65 + UsbNetworkPkg/UsbNetworkPkg.ci.yaml | 65 + UsbNetworkPkg/UsbNetworkPkg.dec | 46 + UsbNetworkPkg/UsbNetworkPkg.dsc | 50 + UsbNetworkPkg/UsbNetworkPkg.dsc.inc | 27 + .../UsbNetworkPkgComponentsDxe.dsc.inc | 20 + .../UsbNetworkPkgComponentsDxe.fdf.inc | 20 + UsbNetworkPkg/UsbNetworkPkgPcds.dsc.inc | 14 + UsbNetworkPkg/UsbRndis/ComponentName.c | 172 ++ UsbNetworkPkg/UsbRndis/UsbRndis.c | 886 ++++++++ UsbNetworkPkg/UsbRndis/UsbRndis.h | 586 ++++++ UsbNetworkPkg/UsbRndis/UsbRndis.inf | 42 + UsbNetworkPkg/UsbRndis/UsbRndisFunction.c | 1718 ++++++++++++++++ 19 files changed, 7565 insertions(+) create mode 100644 UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol= .h create mode 100644 UsbNetworkPkg/NetworkCommon/ComponentName.c create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.c create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.h create mode 100644 UsbNetworkPkg/NetworkCommon/NetworkCommon.inf create mode 100644 UsbNetworkPkg/NetworkCommon/PxeFunction.c create mode 100644 UsbNetworkPkg/ReadMe.md create mode 100644 UsbNetworkPkg/UsbNetworkPkg.ci.yaml create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dec create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dsc create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dsc.inc create mode 100644 UsbNetworkPkg/UsbNetworkPkgComponentsDxe.dsc.inc create mode 100644 UsbNetworkPkg/UsbNetworkPkgComponentsDxe.fdf.inc create mode 100644 UsbNetworkPkg/UsbNetworkPkgPcds.dsc.inc create mode 100644 UsbNetworkPkg/UsbRndis/ComponentName.c create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.c create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.h create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.inf create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndisFunction.c diff --git a/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h b/Us= bNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h new file mode 100644 index 0000000000..f54946c7aa --- /dev/null +++ b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h @@ -0,0 +1,878 @@ +/** @file + Header file contains code for USB Ethernet Protocol + definitions + + Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef EDKII_USB_ETHERNET_PROTOCOL_H_ +#define EDKII_USB_ETHERNET_PROTOCOL_H_ + +#define EDKII_USB_ETHERNET_PROTOCOL_GUID \ + {0x8d8969cc, 0xfeb0, 0x4303, {0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56= , 0x43}} + +typedef struct _EDKII_USB_ETHERNET_PROTOCOL EDKII_USB_ETHERNET_PROTOCOL; + +#define USB_CDC_CLASS 0x02 +#define USB_CDC_ACM_SUBCLASS 0x02 +#define USB_CDC_ECM_SUBCLASS 0x06 +#define USB_CDC_NCM_SUBCLASS 0x0D +#define USB_CDC_DATA_CLASS 0x0A +#define USB_CDC_DATA_SUBCLASS 0x00 +#define USB_NO_CLASS_PROTOCOL 0x00 +#define USB_NCM_NTB_PROTOCOL 0x01 +#define USB_VENDOR_PROTOCOL 0xFF + +// Type Values for the DescriptorType Field +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +// Descriptor SubType in Functional Descriptors +#define HEADER_FUN_DESCRIPTOR 0x00 +#define UNION_FUN_DESCRIPTOR 0x06 +#define ETHERNET_FUN_DESCRIPTOR 0x0F + +#define MAX_LAN_INTERFACE 0x10 + +// Table 20: Class-Specific Notification Codes +#define USB_CDC_NETWORK_CONNECTION 0x00 + +// 6.3.1 NetworkConnection +#define NETWORK_CONNECTED 0x01 +#define NETWORK_DISCONNECT 0x00 + +// USB Header functional Descriptor +typedef struct { + UINT8 FunctionLength; + UINT8 DescriptorType; + UINT8 DescriptorSubtype; + UINT16 BcdCdc; +} USB_HEADER_FUN_DESCRIPTOR; + +// USB Union Functional Descriptor +typedef struct { + UINT8 FunctionLength; + UINT8 DescriptorType; + UINT8 DescriptorSubtype; + UINT8 MasterInterface; + UINT8 SlaveInterface; +} USB_UNION_FUN_DESCRIPTOR; + +// USB Ethernet Functional Descriptor +typedef struct { + UINT8 FunctionLength; + UINT8 DescriptorType; + UINT8 DescriptorSubtype; + UINT8 MacAddress; + UINT32 EthernetStatistics; + UINT16 MaxSegmentSize; + UINT16 NumberMcFilters; + UINT8 NumberPowerFilters; +} USB_ETHERNET_FUN_DESCRIPTOR; + +typedef struct { + UINT32 UsBitRate; + UINT32 DsBitRate; +} USB_CONNECT_SPEED_CHANGE; + +// Request Type Codes for USB Ethernet +#define USB_ETHERNET_GET_REQ_TYPE 0xA1 +#define USB_ETHERNET_SET_REQ_TYPE 0x21 + +// Class-Specific Request Codes for Ethernet subclass +// USB ECM 1.2 specification, Section 6.2 +#define SET_ETH_MULTICAST_FILTERS_REQ 0x40 +#define SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x41 +#define GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x42 +#define SET_ETH_PACKET_FILTER_REQ 0x43 +#define GET_ETH_STATISTIC_REQ 0x44 + +// USB ECM command request length +#define USB_ETH_POWER_FILTER_LENGTH 2 // Section 6.2.3 +#define USB_ETH_PACKET_FILTER_LENGTH 0 // Section 6.2.4 +#define USB_ETH_STATISTIC 4 // Section 6.2.5 + +// USB Ethernet Packet Filter Bitmap +// USB ECM 1.2 specification, Section 6.2.4 +#define USB_ETH_PACKET_TYPE_PROMISCUOUS BIT0 +#define USB_ETH_PACKET_TYPE_ALL_MULTICAST BIT1 +#define USB_ETH_PACKET_TYPE_DIRECTED BIT2 +#define USB_ETH_PACKET_TYPE_BROADCAST BIT3 +#define USB_ETH_PACKET_TYPE_MULTICAST BIT4 + +// USB Ethernet Statistics Feature Selector Codes +// USB ECM 1.2 specification, Section 6.2.5 +#define USB_ETH_XMIT_OK 0x01 +#define USB_ETH_RCV_OK 0x02 +#define USB_ETH_XMIT_ERROR 0x03 +#define USB_ETH_RCV_ERROR 0x04 +#define USB_ETH_RCV_NO_BUFFER 0x05 +#define USB_ETH_DIRECTED_BYTES_XMIT 0x06 +#define USB_ETH_DIRECTED_FRAMES_XMIT 0x07 +#define USB_ETH_MULTICAST_BYTES_XMIT 0x08 +#define USB_ETH_MULTICAST_FRAMES_XMIT 0x09 +#define USB_ETH_BROADCAST_BYTES_XMIT 0x0A +#define USB_ETH_BROADCAST_FRAMES_XMIT 0x0B +#define USB_ETH_DIRECTED_BYTES_RCV 0x0C +#define USB_ETH_DIRECTED_FRAMES_RCV 0x0D +#define USB_ETH_MULTICAST_BYTES_RCV 0x0E +#define USB_ETH_MULTICAST_FRAMES_RCV 0x0F +#define USB_ETH_BROADCAST_BYTES_RCV 0x10 +#define USB_ETH_BROADCAST_FRAMES_RCV 0x11 +#define USB_ETH_RCV_CRC_ERROR 0x12 +#define USB_ETH_TRANSMIT_QUEUE_LENGTH 0x13 +#define USB_ETH_RCV_ERROR_ALIGNMENT 0x14 +#define USB_ETH_XMIT_ONE_COLLISION 0x15 +#define USB_ETH_XMIT_MORE_COLLISIONS 0x16 +#define USB_ETH_XMIT_DEFERRED 0x17 +#define USB_ETH_XMIT_MAX_COLLISIONS 0x18 +#define USB_ETH_RCV_OVERRUN 0x19 +#define USB_ETH_XMIT_UNDERRUN 0x1A +#define USB_ETH_XMIT_HEARTBEAT_FAILURE 0x1B +#define USB_ETH_XMIT_TIMES_CRS_LOST 0x1C +#define USB_ETH_XMIT_LATE_COLLISIONS 0x1D + +// NIC Information +typedef struct { + UINT32 Signature; + EDKII_USB_ETHERNET_PROTOCOL *UsbEth; + UINT16 InterrupOpFlag; + UINT64 MappedAddr; + PXE_MAC_ADDR McastList[MAX_MCAST_ADDRESS_CNT]; + UINT8 McastCount; + UINT64 MediaHeader[MAX_XMIT_BUFFERS]; + UINT8 TxBufferCount; + UINT16 State; + BOOLEAN CanTransmit; + UINT16 ReceiveStatus; + UINT8 RxFilter; + UINT32 RxFrame; + UINT32 TxFrame; + UINT16 NetworkConnect; + UINT8 CableDetect; + UINT16 MaxSegmentSize; + EFI_MAC_ADDRESS MacAddr; + PXE_CPB_START_31 PxeStart; + PXE_CPB_INITIALIZE PxeInit; + UINT8 PermNodeAddress[PXE_MAC_LENGTH]; + UINT8 CurrentNodeAddress[PXE_MAC_LENGTH]; + UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH]; + EFI_USB_DEVICE_REQUEST Request; + EFI_EVENT RateLimiter; + UINT32 RateLimitingCredit; + UINT32 RateLimitingCreditCount; + UINT32 RateLimitingPollTimer; + BOOLEAN RateLimitingEnable; +} NIC_DATA; + +#define NIC_DATA_SIGNATURE SIGNATURE_32('n', 'i', 'c', 'd') +#define NIC_DATA_FROM_EDKII_USB_ETHERNET_PROTOCOL(a) CR (a, NIC_DATA, Usb= Eth, NIC_DATA_SIGNATURE) + +/** + This command is used to determine the operational state of the UNDI. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATE)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command is used to change the UNDI operational state from stopped t= o started. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_START)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command is used to change the UNDI operational state from started t= o stopped. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STOP)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command is used to retrieve initialization information that is + needed by drivers and applications to initialized UNDI. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command is used to retrieve configuration information about + the NIC being controlled by the UNDI. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command resets the network adapter and initializes UNDI using + the parameters supplied in the CPB. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INITIALIZE)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command resets the network adapter and reinitializes the UNDI + with the same parameters provided in the Initialize command. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RESET)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + The Shutdown command resets the network adapter and leaves it in a + safe state for another driver to initialize. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_SHUTDOWN)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + The Interrupt Enables command can be used to read and/or change + the current external interrupt enable settings. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command is used to read and change receive filters and, + if supported, read and change the multicast MAC address filter list. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command is used to get current station and broadcast MAC addresses + and, if supported, to change the current station MAC address. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command is used to read and clear the NIC traffic statistics. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATISTICS)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + Translate a multicast IPv4 or IPv6 address to a multicast MAC address. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command is used to read and write (if supported by NIC H/W) + nonvolatile storage on the NIC. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_NV_DATA)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command returns the current interrupt status and/or the + transmitted buffer addresses and the current media status. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATUS)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command is used to fill the media header(s) in transmit packet(s). + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_FILL_HEADER)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + The Transmit command is used to place a packet into the transmit queue. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_TRANSMIT)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + When the network adapter has received a frame, this command is used + to copy the frame into driver/application storage. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE)( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +/** + This command resets the network adapter and initializes UNDI using + the parameters supplied in the CPB. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in, out] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_INITIALIZE)( + IN PXE_CDB *Cdb, + IN OUT NIC_DATA *Nic + ); + +/** + This command is used to read and clear the NIC traffic statistics. + + @param[in] Nic A pointer to the Network interface controller data. + @param[in] DbAddr Data Block Address. + @param[in] DbSize Data Block Size. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_STATISTICS)( + IN NIC_DATA *Nic, + IN UINT64 DbAddr, + IN UINT16 DbSize + ); + +/** + This function is used to manage a USB device with the bulk transfer pipe= . The endpoint is Bulk in. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOC= OL instance. + @param[in, out] Packet A pointer to the buffer of data that will = be transmitted to USB + device or received from USB device. + @param[in, out] PacketLength A pointer to the PacketLength. + + @retval EFI_SUCCESS The bulk transfer has been successfully ex= ecuted. + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status i= s returned in status. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to = a lack of resources. + @retval EFI_TIMEOUT The control transfer fails due to timeout. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_RECEIVE)( + IN PXE_CDB *Cdb, + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN OUT VOID *Packet, + IN OUT UINTN *PacketLength + ); + +/** + This function is used to manage a USB device with the bulk transfer pipe= . The endpoint is Bulk out. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOC= OL instance. + @param[in, out] Packet A pointer to the buffer of data that will = be transmitted to USB + device or received from USB device. + @param[in, out] PacketLength A pointer to the PacketLength. + + @retval EFI_SUCCESS The bulk transfer has been successfully ex= ecuted. + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status i= s returned in status. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to = a lack of resources. + @retval EFI_TIMEOUT The control transfer fails due to timeout. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_TRANSMIT)( + IN PXE_CDB *Cdb, + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN OUT VOID *Packet, + IN OUT UINTN *PacketLength + ); + +/** + This function is used to manage a USB device with an interrupt transfer = pipe. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOC= OL instance. + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted = to USB controller. If + FALSE, the interrupt transfer is deleted f= rom the device's interrupt + transfer queue. + @param[in] PollingInterval Indicates the periodic rate, in millisecon= ds, that the transfer is to be + executed.This parameter is required when I= sNewTransfer is TRUE. The + value must be between 1 to 255, otherwise = EFI_INVALID_PARAMETER is returned. + The units are in milliseconds. + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST da= ta. + + @retval EFI_SUCCESS The asynchronous USB transfer request tran= sfer has been successfully executed. + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request fail= ed. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_INTERRUPT)( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN BOOLEAN IsNewTransfer, + IN UINTN PollingInterval, + IN EFI_USB_DEVICE_REQUEST *Request + ); + +/** + Retrieves the USB Ethernet Mac Address. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL i= nstance. + @param[out] MacAddress A pointer to the caller allocated USB Ethernet= Mac Address. + + @retval EFI_SUCCESS The USB Header Functional descriptor was r= etrieved successfully. + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL. + @retval EFI_NOT_FOUND The USB Header Functional descriptor was n= ot found. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_GET_ETH_MAC_ADDRESS)( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT EFI_MAC_ADDRESS *MacAddress + ); + +/** + Retrieves the USB Ethernet Bulk transfer data size. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL i= nstance. + @param[out] BulkSize A pointer to the Bulk transfer data size. + + @retval EFI_SUCCESS The USB Header Functional descriptor was r= etrieved successfully. + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL. + @retval EFI_NOT_FOUND The USB Header Functional descriptor was n= ot found. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETH_MAX_BULK_SIZE)( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT UINTN *BulkSize + ); + +/** + Retrieves the USB Header functional Descriptor. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_P= ROTOCOL instance. + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB= Header Functional Descriptor. + + @retval EFI_SUCCESS The USB Header Functional descriptor was r= etrieved successfully. + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL. + @retval EFI_NOT_FOUND The USB Header Functional descriptor was n= ot found. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR)( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor + ); + +/** + Retrieves the USB Union functional Descriptor. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_P= ROTOCOL instance. + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB= Union Functional Descriptor. + + @retval EFI_SUCCESS The USB Union Functional descriptor was re= trieved successfully. + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL. + @retval EFI_NOT_FOUND The USB Union Functional descriptor was no= t found. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR)( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor + ); + +/** + Retrieves the USB Ethernet functional Descriptor. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_P= ROTOCOL instance. + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB= Ethernet Functional Descriptor. + + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was= retrieved successfully. + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL. + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was= not found. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR)( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor + ); + +/** + This request sets the Ethernet device multicast filters as specified in = the + sequential list of 48 bit Ethernet multicast addresses. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_P= ROTOCOL instance. + @param[in] Value Number of filters. + @param[in] McastAddr A pointer to the value of the multica= st addresses. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS)( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value, + IN VOID *McastAddr + ); + +/** + This request sets up the specified Ethernet power management pattern fil= ter as + described in the data structure. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_P= ROTOCOL instance. + @param[in] Value Number of filters. + @param[in] Length Size of the power management pattern = filter data. + @param[in] PatternFilter A pointer to the power management pat= tern filter structure. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER)( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value, + IN UINT16 Length, + IN VOID *PatternFilter + ); + +/** + This request retrieves the status of the specified Ethernet power manage= ment + pattern filter from the device. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_P= ROTOCOL instance. + @param[in] Value The filter number. + @param[out] PatternActive A pointer to the pattern active boole= an. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER)( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value, + OUT BOOLEAN *PatternActive + ); + +/** + This request is used to configure device Ethernet packet filter settings= . + + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOC= OL instance. + @param[in] Value Packet Filter Bitmap. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER)( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value + ); + +/** + This request is used to retrieve a statistic based on the feature select= or. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_PR= OTOCOL instance. + @param[in] FeatureSelector Value of the feature selector. + @param[out] Statistic A pointer to the 32 bit unsigned integ= er. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_STATISTIC)( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 FeatureSelector, + OUT VOID *Statistic + ); + +typedef struct { + EDKII_USB_ETHERNET_UNDI_GET_STATE UsbEthUndiGetState; + EDKII_USB_ETHERNET_UNDI_START UsbEthUndiStart; + EDKII_USB_ETHERNET_UNDI_STOP UsbEthUndiStop; + EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO UsbEthUndiGetInitInfo; + EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO UsbEthUndiGetConfigInfo; + EDKII_USB_ETHERNET_UNDI_INITIALIZE UsbEthUndiInitialize; + EDKII_USB_ETHERNET_UNDI_RESET UsbEthUndiReset; + EDKII_USB_ETHERNET_UNDI_SHUTDOWN UsbEthUndiShutdown; + EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE UsbEthUndiInterruptEnable; + EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER UsbEthUndiReceiveFilter; + EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS UsbEthUndiStationAddress; + EDKII_USB_ETHERNET_UNDI_STATISTICS UsbEthUndiStatistics; + EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC UsbEthUndiMcastIp2Mac; + EDKII_USB_ETHERNET_UNDI_NV_DATA UsbEthUndiNvData; + EDKII_USB_ETHERNET_UNDI_GET_STATUS UsbEthUndiGetStatus; + EDKII_USB_ETHERNET_UNDI_FILL_HEADER UsbEthUndiFillHeader; + EDKII_USB_ETHERNET_UNDI_TRANSMIT UsbEthUndiTransmit; + EDKII_USB_ETHERNET_UNDI_RECEIVE UsbEthUndiReceive; +} EDKII_USB_ETHERNET_UNDI; + +// The EDKII_USB_ETHERNET_PROTOCOL provides some basic USB Ethernet device= relevant +// descriptor and specific requests. +struct _EDKII_USB_ETHERNET_PROTOCOL { + EDKII_USB_ETHERNET_UNDI UsbEthUndi; + // for calling the UNDI child functions + EDKII_USB_ETHERNET_INITIALIZE UsbEthInitiali= ze; + EDKII_USB_ETHERNET_STATISTICS UsbEthStatisti= cs; + EDKII_USB_ETHERNET_RECEIVE UsbEthReceive; + EDKII_USB_ETHERNET_TRANSMIT UsbEthTransmit= ; + EDKII_USB_ETHERNET_INTERRUPT UsbEthInterrup= t; + EDKII_USB_GET_ETH_MAC_ADDRESS UsbEthMacAddre= ss; + EDKII_USB_ETH_MAX_BULK_SIZE UsbEthMaxBulkS= ize; + EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR UsbHeaderFunDe= scriptor; + EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR UsbUnionFunDes= criptor; + EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR UsbEthFunDescr= iptor; + EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS SetUsbEthMcast= Filter; + EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER SetUsbEthPower= PatternFilter; + EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER GetUsbEthPower= PatternFilter; + EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER SetUsbEthPacke= tFilter; + EDKII_USB_ETHERNET_GET_ETH_STATISTIC GetUsbEthStati= stic; +}; + +extern EFI_GUID gEdkIIUsbEthProtocolGuid; + +#endif diff --git a/UsbNetworkPkg/NetworkCommon/ComponentName.c b/UsbNetworkPkg/Ne= tworkCommon/ComponentName.c new file mode 100644 index 0000000000..e83469e130 --- /dev/null +++ b/UsbNetworkPkg/NetworkCommon/ComponentName.c @@ -0,0 +1,263 @@ +/** @file + This file contains code for USB network common driver + component name definitions + + Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "DriverBinding.h" + +extern EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gNetworkCommonDriv= erNameTable[] =3D { + { + "eng;en", + L"Network Common Driver" + }, + { + NULL, + NULL + } +}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gNetworkCommonCon= trollerNameTable =3D NULL; + +EFI_STATUS +EFIAPI +NetworkCommonComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +NetworkCommonComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gNetworkCommonC= omponentName =3D { + NetworkCommonComponentNameGetDriverName, + NetworkCommonComponentNameGetControllerName, + "eng" +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommon= ComponentName2 =3D { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)NetworkCommonComponentNameGetDriver= Name, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)NetworkCommonComponentNameGetCo= ntrollerName, + "en" +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form o= f a + Unicode string. If the driver specified by This has a user readable name= in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver speci= fied + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param[in] Language A pointer to a Null-terminated ASCII strin= g + array indicating the language. This is the + language of the driver name that the calle= r is + requesting, and it must match one of the + languages specified in SupportedLanguages.= The + number of languages supported by a driver = is up + to the driver writer. Language is specifie= d + in RFC 4646 or ISO 639-2 language code for= mat. + @param[out] DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specifie= d by + This and the language specified by Languag= e was + returned in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +NetworkCommonComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + gNetworkCommonDriverNameTable, + DriverName, + (BOOLEAN)(This =3D=3D &gNetworkCommonComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the control= ler + that is being managed by a driver. + + This function retrieves the user readable name of the controller specifi= ed by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specif= ied by + Language, then a pointer to the controller name is returned in Controlle= rName, + and EFI_SUCCESS is returned. If the driver specified by This is not cur= rently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does = not + support the language specified by Language, then EFI_UNSUPPORTED is retu= rned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param[in] Controller The handle of a controller that the driver + specified by This is managing. This handl= e + specifies the controller whose name is to = be + returned. + @param[in] ChildHandle The handle of the child controller to retr= ieve + the name of. This is an optional paramete= r that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus d= rivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of= a + child controller. + @param[in] Language A pointer to a Null-terminated ASCII strin= g + array indicating the language. This is th= e + language of the driver name that the calle= r is + requesting, and it must match one of the + languages specified in SupportedLanguages.= The + number of languages supported by a driver = is up + to the driver writer. Language is specifie= d in + RFC 4646 or ISO 639-2 language code format= . + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle a= nd + ChildHandle in the language specified by + Language from the point of view of the dri= ver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable n= ame in + the language specified by Language for the + driver specified by This was returned in + DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE= . + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a va= lid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not curren= tly + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +NetworkCommonComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + CHAR16 *HandleName; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_DEVICE_DESCRIPTOR DevDesc; + + if (!Language || !ControllerName) { + return EFI_INVALID_PARAMETER; + } + + if (ChildHandle =3D=3D NULL) { + return EFI_UNSUPPORTED; + } + + // + // Make sure this driver is currently managing ControllerHandle + // + Status =3D EfiTestManagedDevice ( + Controller, + gNetworkCommonDriverBinding.DriverBindingHandle, + &gEdkIIUsbEthProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Make sure this driver produced ChildHandle + // + Status =3D EfiTestChildHandle ( + Controller, + ChildHandle, + &gEdkIIUsbEthProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gBS->HandleProtocol (Controller, &gEfiUsbIoProtocolGuid, (VOI= D **)&UsbIo); + + if (!EFI_ERROR (Status)) { + Status =3D UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D UsbIo->UsbGetStringDescriptor (UsbIo, 0x409, DevDesc.StrMan= ufacturer, &HandleName); + if (EFI_ERROR (Status)) { + return Status; + } + + *ControllerName =3D HandleName; + + if (gNetworkCommonControllerNameTable !=3D NULL) { + FreeUnicodeStringTable (gNetworkCommonControllerNameTable); + gNetworkCommonControllerNameTable =3D NULL; + } + + Status =3D AddUnicodeString2 ( + "eng", + gNetworkCommonComponentName.SupportedLanguages, + &gNetworkCommonControllerNameTable, + HandleName, + TRUE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D AddUnicodeString2 ( + "en", + gNetworkCommonComponentName2.SupportedLanguages, + &gNetworkCommonControllerNameTable, + HandleName, + FALSE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + gNetworkCommonControllerNameTable, + ControllerName, + (BOOLEAN)(This =3D=3D &gNetworkCommonComponentName) + ); + } + + return EFI_UNSUPPORTED; +} diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.c b/UsbNetworkPkg/Ne= tworkCommon/DriverBinding.c new file mode 100644 index 0000000000..23b7913620 --- /dev/null +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.c @@ -0,0 +1,595 @@ +/** @file + This file contains code for USB network binding driver + + Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "DriverBinding.h" + +PXE_SW_UNDI *gPxe =3D NULL; +NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE]; +UINT32 gRateLimitingCredit; +UINT32 gRateLimitingPollTimer; +BOOLEAN gRateLimitingEnable; + +EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding =3D { + NetworkCommonSupported, + NetworkCommonDriverStart, + NetworkCommonDriverStop, + NETWORK_COMMON_DRIVER_VERSION, + NULL, + NULL +}; + +/** + Create MAC Device Path + + @param[in, out] Dev A pointer to the EFI_DEVICE_PATH_PROTOCO= L instance. + @param[in] BaseDev A pointer to the EFI_DEVICE_PATH_PROTOCO= L instance. + @param[in] Nic A pointer to the Network interface contr= oller data. + + @retval EFI_OUT_OF_RESOURCES The device path could not be created suc= cessfully due to a lack of resources. + @retval EFI_SUCCESS MAC device path created successfully. + +**/ +EFI_STATUS +CreateMacDevicePath ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **Dev, + IN EFI_DEVICE_PATH_PROTOCOL *BaseDev, + IN NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + MAC_ADDR_DEVICE_PATH MacAddrNode; + EFI_DEVICE_PATH_PROTOCOL *EndNode; + UINT8 *DevicePath; + UINT16 TotalLength; + UINT16 BaseLength; + + ZeroMem (&MacAddrNode, sizeof (MAC_ADDR_DEVICE_PATH)); + CopyMem (&MacAddrNode.MacAddress, &Nic->MacAddr, sizeof (EFI_MAC_ADDRESS= )); + + MacAddrNode.Header.Type =3D MESSAGING_DEVICE_PATH; + MacAddrNode.Header.SubType =3D MSG_MAC_ADDR_DP; + MacAddrNode.Header.Length[0] =3D (UINT8)sizeof (MacAddrNode); + MacAddrNode.Header.Length[1] =3D 0; + + EndNode =3D BaseDev; + + while (!IsDevicePathEnd (EndNode)) { + EndNode =3D NextDevicePathNode (EndNode); + } + + BaseLength =3D (UINT16)((UINTN)(EndNode) - (UINTN)(BaseDev)); + TotalLength =3D (UINT16)(BaseLength + sizeof (MacAddrNode) + sizeof (EFI= _DEVICE_PATH_PROTOCOL)); + + Status =3D gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID **= )&DevicePath); + if (EFI_ERROR (Status)) { + return Status; + } + + *Dev =3D (EFI_DEVICE_PATH_PROTOCOL *)DevicePath; + CopyMem (DevicePath, (CHAR8 *)BaseDev, BaseLength); + DevicePath +=3D BaseLength; + CopyMem (DevicePath, (CHAR8 *)&MacAddrNode, sizeof (MacAddrNode)); + DevicePath +=3D sizeof (MacAddrNode); + CopyMem (DevicePath, (CHAR8 *)EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL)= ); + + return EFI_SUCCESS; +} + +/** + Network Common Driver Binding Support. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to test. + @param[in] RemainingDevicePath Optional parameter use to pick a spe= cific child + device to start. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_ALREADY_STARTED This driver is already running on th= is device. + @retval other This driver does not support this de= vice. + +**/ +EFI_STATUS +EFIAPI +NetworkCommonSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EDKII_USB_ETHERNET_PROTOCOL *UsbEth; + + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + (VOID **)&UsbEth, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; +} + +/** + Network Common Driver Binding Start. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to bind driver to. + @param[in] RemainingDevicePath Optional parameter use to pick a spe= cific child + device to start. + + @retval EFI_SUCCESS This driver is added to ControllerHa= ndle + @retval EFI_DEVICE_ERROR This driver could not be started due= to a device error + @retval EFI_OUT_OF_RESOURCES The driver could not install success= fully due to a lack of resources. + @retval other This driver does not support this de= vice + +**/ +EFI_STATUS +EFIAPI +NetworkCommonDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath; + EDKII_USB_ETHERNET_PROTOCOL *UsbEth; + EFI_MAC_ADDRESS MacAddress; + UINTN BulkDataSize; + NIC_DEVICE *NicDevice; + UINT8 *TmpPxePointer; + + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + (VOID **)&UsbEth, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **)&UsbEthPath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + + ZeroMem (&MacAddress, sizeof (EFI_MAC_ADDRESS)); + + Status =3D UsbEth->UsbEthMacAddress (UsbEth, &MacAddress); + ASSERT_EFI_ERROR (Status); + Status =3D UsbEth->UsbEthMaxBulkSize (UsbEth, &BulkDataSize); + + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + + NicDevice =3D AllocateZeroPool (sizeof (NIC_DEVICE) + BulkDataSize + 409= 6); + if (!NicDevice) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return EFI_OUT_OF_RESOURCES; + } + + // for alignment adjustment + if (gPxe =3D=3D NULL) { + TmpPxePointer =3D NULL; + TmpPxePointer =3D AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16); + if (!TmpPxePointer) { + if (NicDevice !=3D NULL) { + FreePool (NicDevice); + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return EFI_OUT_OF_RESOURCES; + } else { + // check for paragraph alignment here + if (((UINTN)TmpPxePointer & 0x0F) !=3D 0) { + gPxe =3D (PXE_SW_UNDI *)(TmpPxePointer + 8); + } else { + gPxe =3D (PXE_SW_UNDI *)TmpPxePointer; + } + + if (!gPxe) { + if (NicDevice !=3D NULL) { + FreePool (NicDevice); + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return EFI_OUT_OF_RESOURCES; + } + + PxeStructInit (gPxe); + } + } + + NicDevice->NiiProtocol.Id =3D (UINT64)(UINTN)(gPxe); + NicDevice->NiiProtocol.IfNum =3D gPxe->IFcnt | gPxe->IFcntExt << 8; + + UpdateNicNum (&NicDevice->NicInfo, gPxe); + + NicDevice->NicInfo.Signature =3D NIC_DATA_SIGNATURE; + + NicDevice->NicInfo.UsbEth =3D UsbEth; + NicDevice->NicInfo.MaxSegmentSize =3D (UINT16)BulkDataSize; + NicDevice->NicInfo.CableDetect =3D 0; + NicDevice->ReceiveBuffer =3D ALIGN_POINTER ((VOID *)NicDevice, = 4096); + + CopyMem ((CHAR8 *)&(NicDevice->NicInfo.MacAddr), (CHAR8 *)&MacAddress, s= izeof (MacAddress)); + + NicDevice->NicInfo.TxBufferCount =3D 0; + + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) { + gLanDeviceList[NicDevice->NiiProtocol.IfNum] =3D NicDevice; + } else { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + if (TmpPxePointer !=3D NULL) { + FreePool (TmpPxePointer); + } + + if (NicDevice !=3D NULL) { + FreePool (NicDevice); + } + + return EFI_DEVICE_ERROR; + } + + Status =3D CreateMacDevicePath ( + &NicDevice->DevPath, + UsbEthPath, + &NicDevice->NicInfo + ); + + if (EFI_ERROR (Status)) { + UpdateNicNum (NULL, gPxe); + if (TmpPxePointer !=3D NULL) { + FreePool (TmpPxePointer); + } + } + + NicDevice->Signature =3D UNDI_DEV_SIGNATURE; + NicDevice->NiiProtocol.Revision =3D EFI_NETWORK_INTERFACE_IDENTIFIE= R_PROTOCOL_REVISION; + NicDevice->NiiProtocol.Type =3D EfiNetworkInterfaceUndi; + NicDevice->NiiProtocol.MajorVer =3D PXE_ROMID_MAJORVER; + NicDevice->NiiProtocol.MinorVer =3D PXE_ROMID_MINORVER; + NicDevice->NiiProtocol.ImageSize =3D 0; + NicDevice->NiiProtocol.ImageAddr =3D 0; + NicDevice->NiiProtocol.Ipv6Supported =3D TRUE; + + NicDevice->NiiProtocol.StringId[0] =3D 'U'; + NicDevice->NiiProtocol.StringId[1] =3D 'N'; + NicDevice->NiiProtocol.StringId[2] =3D 'D'; + NicDevice->NiiProtocol.StringId[3] =3D 'I'; + NicDevice->DeviceHandle =3D NULL; + + NicDevice->NicInfo.RateLimitingEnable =3D gRateLimitingEnable; + NicDevice->NicInfo.RateLimitingCreditCount =3D 0; + NicDevice->NicInfo.RateLimitingCredit =3D gRateLimitingCredit; + NicDevice->NicInfo.RateLimitingPollTimer =3D gRateLimitingPollTimer; + NicDevice->NicInfo.RateLimiter =3D NULL; + + ZeroMem (&NicDevice->NicInfo.Request, sizeof (EFI_USB_DEVICE_REQUEST)); + + Status =3D UsbEth->UsbEthInterrupt (UsbEth, TRUE, NETWORK_COMMON_POLLING= _INTERVAL, &NicDevice->NicInfo.Request); + ASSERT_EFI_ERROR (Status); + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &NicDevice->DeviceHandle, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + &NicDevice->NiiProtocol, + &gEfiDevicePathProtocolGuid, + NicDevice->DevPath, + NULL + ); + + if (EFI_ERROR (Status)) { + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) { + gLanDeviceList[NicDevice->NiiProtocol.IfNum] =3D NULL; + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + if (TmpPxePointer !=3D NULL) { + FreePool (TmpPxePointer); + } + + if (NicDevice->DevPath !=3D NULL) { + FreePool (NicDevice->DevPath); + } + + if (NicDevice !=3D NULL) { + FreePool (NicDevice); + } + + return EFI_DEVICE_ERROR; + } + + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + (VOID **)&UsbEth, + This->DriverBindingHandle, + NicDevice->DeviceHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + return Status; +} + +/** + Network Common Driver Binding Stop. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop driver on + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer= . If number of + children is zero stop the entire bus d= river. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandl= e + @retval other This driver was not removed from this = device + +**/ +EFI_STATUS +EFIAPI +NetworkCommonDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + BOOLEAN AllChildrenStopped; + UINTN Index; + EDKII_USB_ETHERNET_PROTOCOL *UsbEth; + NIC_DEVICE *NicDevice; + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol; + + if (NumberOfChildren =3D=3D 0) { + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + (VOID **)&NiiProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return EFI_SUCCESS; + } + + NicDevice =3D UNDI_DEV_FROM_THIS (NiiProtocol); + Status =3D gBS->UninstallMultipleProtocolInterfaces ( + ControllerHandle, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + &NicDevice->NiiProtocol, + &gEfiDevicePathProtocolGuid, + NicDevice->DevPath, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FreePool (NicDevice->DevPath); + FreePool (NicDevice); + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return EFI_SUCCESS; + } + + AllChildrenStopped =3D TRUE; + + for (Index =3D 0; Index < NumberOfChildren; Index++) { + Status =3D gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + (VOID **)&NiiProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + AllChildrenStopped =3D FALSE; + continue; + } + + NicDevice =3D UNDI_DEV_FROM_THIS (NiiProtocol); + + gBS->CloseProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index] + ); + + Status =3D gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + &NicDevice->NiiProtocol, + &gEfiDevicePathProtocolGuid, + NicDevice->DevPath, + NULL + ); + if (EFI_ERROR (Status)) { + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + (VOID **)&UsbEth, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + FreePool (NicDevice->DevPath); + FreePool (NicDevice); + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return Status; +} + +/** + Entrypoint of Network Common Driver. + + This function is the entrypoint of Network Common Driver. It installs Dr= iver Binding + Protocols together with Component Name Protocols. + + @param[in] ImageHandle The firmware allocated handle for the EFI = image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +NetworkCommonEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + gNetworkCommonDriverBinding.DriverBindingHandle =3D ImageHandle; + gNetworkCommonDriverBinding.ImageHandle =3D ImageHandle; + gRateLimitingEnable =3D PcdGetBool (EnableRa= teLimiting); + gRateLimitingCredit =3D PcdGet32 (RateLimiti= ngCredit); + gRateLimitingPollTimer =3D PcdGet32 (RateLimiti= ngFactor); + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &gNetworkCommonDriverBinding.DriverBindingHandle, + &gEfiDriverBindingProtocolGuid, + &gNetworkCommonDriverBinding, + &gEfiComponentName2ProtocolGuid, + &gNetworkCommonComponentName2, + NULL + ); + return Status; +} diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h b/UsbNetworkPkg/Ne= tworkCommon/DriverBinding.h new file mode 100644 index 0000000000..0416ce1323 --- /dev/null +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h @@ -0,0 +1,266 @@ +/** @file + Header file for for USB network common driver + + Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _DRIVER_BINDING_H_ +#define _DRIVER_BINDING_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NETWORK_COMMON_DRIVER_VERSION 1 +#define NETWORK_COMMON_POLLING_INTERVAL 0x10 +#define RX_BUFFER_COUNT 32 +#define TX_BUFFER_COUNT 32 +#define MEMORY_REQUIRE 0 + +#define UNDI_DEV_SIGNATURE SIGNATURE_32('u','n','d','i') +#define UNDI_DEV_FROM_THIS(a) CR(a, NIC_DEVICE, NiiProtocol, UNDI_DEV_SIG= NATURE) +#define UNDI_DEV_FROM_NIC(a) CR(a, NIC_DEVICE, NicInfo, UNDI_DEV_SIGNATU= RE) + +#pragma pack(1) +typedef struct { + UINT8 DestAddr[PXE_HWADDR_LEN_ETHER]; + UINT8 SrcAddr[PXE_HWADDR_LEN_ETHER]; + UINT16 Protocol; +} EthernetHeader; +#pragma pack() + +typedef struct { + UINTN Signature; + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NiiProtocol; + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *BaseDevPath; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + NIC_DATA NicInfo; + VOID *ReceiveBuffer; +} NIC_DEVICE; + +typedef VOID (*API_FUNC)( + PXE_CDB *, + NIC_DATA * + ); + +extern PXE_SW_UNDI *gPxe; +extern NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE]; +extern EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2; + +EFI_STATUS +EFIAPI +NetworkCommonSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +NetworkCommonDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +NetworkCommonDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +VOID +PxeStructInit ( + OUT PXE_SW_UNDI *PxeSw + ); + +VOID +UpdateNicNum ( + IN NIC_DATA *Nic, + IN OUT PXE_SW_UNDI *PxeSw + ); + +EFI_STATUS +EFIAPI +UndiApiEntry ( + IN UINT64 Cdb + ); + +UINTN +MapIt ( + IN NIC_DATA *Nic, + IN UINT64 MemAddr, + IN UINT32 Size, + IN UINT32 Direction, + OUT UINT64 MappedAddr + ); + +VOID +UnMapIt ( + IN NIC_DATA *Nic, + IN UINT64 MemAddr, + IN UINT32 Size, + IN UINT32 Direction, + IN UINT64 MappedAddr + ); + +VOID +UndiGetState ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiStart ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiStop ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiGetInitInfo ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiGetConfigInfo ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiInitialize ( + IN PXE_CDB *Cdb, + IN OUT NIC_DATA *Nic + ); + +VOID +UndiReset ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiShutdown ( + IN PXE_CDB *Cdb, + IN OUT NIC_DATA *Nic + ); + +VOID +UndiInterruptEnable ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiReceiveFilter ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiStationAddress ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiStatistics ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiMcastIp2Mac ( + IN OUT PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiNvData ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiGetStatus ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiFillHeader ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiTransmit ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +VOID +UndiReceive ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +UINT16 +Initialize ( + IN PXE_CDB *Cdb, + IN OUT NIC_DATA *Nic + ); + +UINT16 +Transmit ( + IN PXE_CDB *Cdb, + IN OUT NIC_DATA *Nic, + IN UINT64 CpbAddr, + IN UINT16 OpFlags + ); + +UINT16 +Receive ( + IN PXE_CDB *Cdb, + IN OUT NIC_DATA *Nic, + IN UINT64 CpbAddr, + IN OUT UINT64 DbAddr + ); + +UINT16 +SetFilter ( + IN NIC_DATA *Nic, + IN UINT16 SetFilter, + IN UINT64 CpbAddr, + IN UINT32 CpbSize + ); + +UINT16 +Statistics ( + IN NIC_DATA *Nic, + IN UINT64 DbAddr, + IN UINT16 DbSize + ); + +#endif diff --git a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf b/UsbNetworkPkg/= NetworkCommon/NetworkCommon.inf new file mode 100644 index 0000000000..8923102bc3 --- /dev/null +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf @@ -0,0 +1,49 @@ +## @file +# This is Usb Network Common driver for DXE phase. +# +# Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D NetworkCommon + FILE_GUID =3D ca6eb4f4-f1d6-4375-97d6-18856871e1bf + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D NetworkCommonEntry + +[Sources] + DriverBinding.c + DriverBinding.h + ComponentName.c + PxeFunction.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UsbNetworkPkg/UsbNetworkPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiLib + DebugLib + UefiUsbLib + MemoryAllocationLib + BaseMemoryLib + +[Protocols] + gEfiNetworkInterfaceIdentifierProtocolGuid_31 + gEfiUsbIoProtocolGuid + gEfiDevicePathProtocolGuid + gEfiDriverBindingProtocolGuid + gEdkIIUsbEthProtocolGuid + +[Pcd] + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor + +[Depex] + TRUE diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c b/UsbNetworkPkg/Netw= orkCommon/PxeFunction.c new file mode 100644 index 0000000000..687cabca4c --- /dev/null +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c @@ -0,0 +1,1803 @@ +/** @file + This file contains code for UNDI command based on UEFI specification. + + Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "DriverBinding.h" + +// API table, defined in UEFI specification +API_FUNC gUndiApiTable[] =3D { + UndiGetState, + UndiStart, + UndiStop, + UndiGetInitInfo, + UndiGetConfigInfo, + UndiInitialize, + UndiReset, + UndiShutdown, + UndiInterruptEnable, + UndiReceiveFilter, + UndiStationAddress, + UndiStatistics, + UndiMcastIp2Mac, + UndiNvData, + UndiGetStatus, + UndiFillHeader, + UndiTransmit, + UndiReceive +}; + +/** + Callback function for enable Rate Limiter + + @param[in] Event Event whose notification function is being i= nvoked + @param[in] Context Pointer to the notification function's conte= xt + +**/ +VOID +EFIAPI +UndiRateLimiterCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + NIC_DATA *Nic =3D Context; + + if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) { + Nic->RateLimitingCreditCount++; + } +} + +/** + This command is used to determine the operational state of the UNDI. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiGetState ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_GET_STATE) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D PXE_CPBSIZE_NOT_USED) || + (Cdb->CPBaddr !=3D PXE_CPBADDR_NOT_USED) || + (Cdb->DBsize !=3D PXE_DBSIZE_NOT_USED) || + (Cdb->DBaddr !=3D PXE_DBADDR_NOT_USED) || + (Cdb->OpFlags !=3D PXE_OPFLAGS_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + Cdb->StatFlags =3D Cdb->StatFlags | Nic->State; + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + This command is used to change the UNDI operational state from stopped t= o started. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiStart ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + PXE_CPB_START_31 *Cpb; + EFI_STATUS Status; + BOOLEAN EventError; + + if ((Cdb->OpCode !=3D PXE_OPCODE_START) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D sizeof (PXE_CPB_START_31)) || + (Cdb->DBsize !=3D PXE_DBSIZE_NOT_USED) || + (Cdb->DBaddr !=3D PXE_DBADDR_NOT_USED) || + (Cdb->OpFlags !=3D PXE_OPFLAGS_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } + + if (Nic->State !=3D PXE_STATFLAGS_GET_STATE_STOPPED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_ALREADY_STARTED; + return; + } + + Cpb =3D (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr; + + Nic->PxeStart.Delay =3D Cpb->Delay; + Nic->PxeStart.Virt2Phys =3D Cpb->Virt2Phys; + Nic->PxeStart.Block =3D Cpb->Block; + Nic->PxeStart.Map_Mem =3D 0; + Nic->PxeStart.UnMap_Mem =3D 0; + Nic->PxeStart.Sync_Mem =3D Cpb->Sync_Mem; + Nic->PxeStart.Unique_ID =3D Cpb->Unique_ID; + EventError =3D FALSE; + Status =3D EFI_SUCCESS; + if (Nic->RateLimitingEnable =3D=3D TRUE) { + Status =3D gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + UndiRateLimiterCallback, + Nic, + &Nic->RateLimiter + ); + if (!EFI_ERROR (Status)) { + Status =3D gBS->SetTimer ( + Nic->RateLimiter, + TimerPeriodic, + Nic->RateLimitingPollTimer * 10000 + ); + if (EFI_ERROR (Status)) { + EventError =3D TRUE; + } + } + } + + if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart !=3D NULL) && (EventError = =3D=3D FALSE)) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic); + } + + if (!EFI_ERROR (Status)) { + // Initial the state for UNDI start. + Nic->State =3D PXE_STATFLAGS_GET_STATE_STARTED; + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } else { + if (Nic->RateLimitingEnable =3D=3D TRUE) { + if (!EventError) { + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0); + } + + if (Nic->RateLimiter) { + gBS->CloseEvent (&Nic->RateLimiter); + Nic->RateLimiter =3D 0; + } + } + + // Initial the state when UNDI start is fail + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_DEVICE_FAILURE; + } +} + +/** + This command is used to change the UNDI operational state from started t= o stopped. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiStop ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_STOP) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D PXE_CPBSIZE_NOT_USED) || + (Cdb->CPBaddr !=3D PXE_CPBADDR_NOT_USED) || + (Cdb->DBsize !=3D PXE_DBSIZE_NOT_USED) || + (Cdb->DBaddr !=3D PXE_DBADDR_NOT_USED) || + (Cdb->OpFlags !=3D PXE_OPFLAGS_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State =3D=3D PXE_STATFLAGS_GET_STATE_STOPPED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_NOT_STARTED; + return; + } + + if (Nic->State =3D=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_NOT_SHUTDOWN; + return; + } + + Nic->PxeStart.Delay =3D 0; + Nic->PxeStart.Virt2Phys =3D 0; + Nic->PxeStart.Block =3D 0; + Nic->PxeStart.Map_Mem =3D 0; + Nic->PxeStart.UnMap_Mem =3D 0; + Nic->PxeStart.Sync_Mem =3D 0; + Nic->State =3D PXE_STATFLAGS_GET_STATE_STOPPED; + + if (Nic->RateLimitingEnable =3D=3D TRUE) { + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0); + gBS->CloseEvent (&Nic->RateLimiter); + } + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + This command is used to retrieve initialization information that is + needed by drivers and applications to initialized UNDI. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiGetInitInfo ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + PXE_DB_GET_INIT_INFO *Db; + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_GET_INIT_INFO) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D PXE_CPBSIZE_NOT_USED) || + (Cdb->CPBaddr !=3D PXE_CPBADDR_NOT_USED) || + (Cdb->DBsize !=3D sizeof (PXE_DB_GET_INIT_INFO)) || + (Cdb->OpFlags !=3D PXE_OPFLAGS_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State =3D=3D PXE_STATFLAGS_GET_STATE_STOPPED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_NOT_STARTED; + return; + } + + Db =3D (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr; + + Db->MemoryRequired =3D MEMORY_REQUIRE; + Db->FrameDataLen =3D PXE_MAX_TXRX_UNIT_ETHER; + Db->LinkSpeeds[0] =3D 10; + Db->LinkSpeeds[1] =3D 100; + Db->LinkSpeeds[2] =3D 1000; + Db->LinkSpeeds[3] =3D 0; + Db->MediaHeaderLen =3D PXE_MAC_HEADER_LEN_ETHER; + Db->HWaddrLen =3D PXE_HWADDR_LEN_ETHER; + Db->MCastFilterCnt =3D MAX_MCAST_ADDRESS_CNT; + Db->TxBufCnt =3D Nic->PxeInit.TxBufCnt; + Db->TxBufSize =3D Nic->PxeInit.TxBufSize; + Db->RxBufCnt =3D Nic->PxeInit.RxBufCnt; + Db->RxBufSize =3D Nic->PxeInit.RxBufSize; + Db->IFtype =3D PXE_IFTYPE_ETHERNET; + Db->SupportedDuplexModes =3D PXE_DUPLEX_DEFAULT; + Db->SupportedLoopBackModes =3D LOOPBACK_NORMAL; + + Cdb->StatFlags |=3D (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED | + PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED); + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + This command is used to retrieve configuration information about + the NIC being controlled by the UNDI. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiGetConfigInfo ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + PXE_DB_GET_CONFIG_INFO *Db; + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_GET_CONFIG_INFO) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D PXE_CPBSIZE_NOT_USED) || + (Cdb->CPBaddr !=3D PXE_CPBADDR_NOT_USED) || + (Cdb->DBsize !=3D sizeof (PXE_DB_GET_CONFIG_INFO)) || + (Cdb->OpFlags !=3D PXE_OPFLAGS_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State =3D=3D PXE_STATFLAGS_GET_STATE_STOPPED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_NOT_STARTED; + return; + } + + Db =3D (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr; + + Db->pci.BusType =3D PXE_BUSTYPE_USB; + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + This command resets the network adapter and initializes UNDI using + the parameters supplied in the CPB. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in, out] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiInitialize ( + IN PXE_CDB *Cdb, + IN OUT NIC_DATA *Nic + ) +{ + PXE_CPB_INITIALIZE *Cpb; + PXE_DB_INITIALIZE *Db; + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_INITIALIZE) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D sizeof (PXE_CPB_INITIALIZE))) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + } + + if (Nic->State =3D=3D PXE_STATFLAGS_GET_STATE_STOPPED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_NOT_STARTED; + return; + } + + if ((Cdb->OpFlags !=3D PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) && + (Cdb->OpFlags !=3D PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } + + if (Nic->State =3D=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_ALREADY_INITIALIZED; + return; + } + + Cpb =3D (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr; + Db =3D (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr; + + Nic->PxeInit.LinkSpeed =3D Cpb->LinkSpeed; + Nic->PxeInit.DuplexMode =3D Cpb->DuplexMode; + Nic->PxeInit.LoopBackMode =3D Cpb->LoopBackMode; + Nic->PxeInit.MemoryAddr =3D Cpb->MemoryAddr; + Nic->PxeInit.MemoryLength =3D Cpb->MemoryLength; + Nic->PxeInit.TxBufCnt =3D TX_BUFFER_COUNT; + Nic->PxeInit.TxBufSize =3D Nic->MaxSegmentSize; + Nic->PxeInit.RxBufCnt =3D RX_BUFFER_COUNT; + Nic->PxeInit.RxBufSize =3D Nic->MaxSegmentSize; + + Cdb->StatCode =3D Initialize (Cdb, Nic); + + Db->MemoryUsed =3D MEMORY_REQUIRE; + Db->TxBufCnt =3D Nic->PxeInit.TxBufCnt; + Db->TxBufSize =3D Nic->PxeInit.TxBufSize; + Db->RxBufCnt =3D Nic->PxeInit.RxBufCnt; + Db->RxBufSize =3D Nic->PxeInit.RxBufSize; + + Nic->RxFilter =3D PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST; + Nic->CanTransmit =3D FALSE; + + if (Cdb->OpFlags =3D=3D PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) { + if ((Nic->Request.Request =3D=3D USB_CDC_NETWORK_CONNECTION) && (Nic->= Request.Value =3D=3D NETWORK_DISCONNECT)) { + Nic->CableDetect =3D 0; + } else if ((Nic->Request.Request =3D=3D USB_CDC_NETWORK_CONNECTION) &&= (Nic->Request.Value =3D=3D NETWORK_CONNECTED)) { + Nic->CableDetect =3D 1; + } + + if (Nic->CableDetect =3D=3D 0) { + Cdb->StatFlags |=3D PXE_STATFLAGS_INITIALIZED_NO_MEDIA; + } + } + + if (Cdb->StatCode !=3D PXE_STATCODE_SUCCESS) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } else { + Nic->State =3D PXE_STATFLAGS_GET_STATE_INITIALIZED; + } + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + Initialize Network interface controller data. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in, out] Nic A pointer to the Network interface controller da= ta. + + @retval Status A value of Pxe statcode. + +**/ +UINT16 +Initialize ( + IN PXE_CDB *Cdb, + IN OUT NIC_DATA *Nic + ) +{ + UINTN Status; + UINT32 Index; + EFI_STATUS EfiStatus; + + Status =3D MapIt ( + Nic, + Nic->PxeInit.MemoryAddr, + Nic->PxeInit.MemoryLength, + TO_AND_FROM_DEVICE, + (UINT64)(UINTN)&Nic->MappedAddr + ); + + if (Status !=3D 0) { + return (UINT16)Status; + } + + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + Nic->PermNodeAddress[Index] =3D Nic->MacAddr.Addr[Index]; + } + + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + Nic->CurrentNodeAddress[Index] =3D Nic->PermNodeAddress[Index]; + } + + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + Nic->BroadcastNodeAddress[Index] =3D 0xFF; + } + + for (Index =3D PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) { + Nic->CurrentNodeAddress[Index] =3D 0; + Nic->PermNodeAddress[Index] =3D 0; + Nic->BroadcastNodeAddress[Index] =3D 0; + } + + if (Nic->UsbEth->UsbEthInitialize !=3D NULL) { + EfiStatus =3D Nic->UsbEth->UsbEthInitialize (Cdb, Nic); + if (EFI_ERROR (EfiStatus)) { + return PXE_STATFLAGS_COMMAND_FAILED; + } + } + + return (UINT16)Status; +} + +/** + This command resets the network adapter and reinitializes the UNDI + with the same parameters provided in the Initialize command. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiReset ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_RESET) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D PXE_CPBSIZE_NOT_USED) || + (Cdb->CPBaddr !=3D PXE_CPBADDR_NOT_USED) || + (Cdb->DBsize !=3D PXE_DBSIZE_NOT_USED) || + (Cdb->DBaddr !=3D PXE_DBADDR_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State !=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + return; + } + + if ((Cdb->OpFlags !=3D PXE_OPFLAGS_NOT_USED) && + (Cdb->OpFlags !=3D PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) && + (Cdb->OpFlags !=3D PXE_OPFLAGS_RESET_DISABLE_FILTERS)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } + + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) =3D=3D 0) { + Nic->RxFilter =3D PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST; + } + + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) !=3D 0) { + Nic->InterrupOpFlag =3D 0; + } + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + The Shutdown command resets the network adapter and leaves it in a + safe state for another driver to initialize. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in, out] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiShutdown ( + IN PXE_CDB *Cdb, + IN OUT NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_SHUTDOWN) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D PXE_CPBSIZE_NOT_USED) || + (Cdb->CPBaddr !=3D PXE_CPBADDR_NOT_USED) || + (Cdb->DBsize !=3D PXE_DBSIZE_NOT_USED) || + (Cdb->DBaddr !=3D PXE_DBADDR_NOT_USED) || + (Cdb->OpFlags !=3D PXE_OPFLAGS_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State !=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + return; + } + + Nic->CanTransmit =3D FALSE; + + Nic->State =3D PXE_STATFLAGS_GET_STATE_STARTED; + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + The Interrupt Enables command can be used to read and/or change + the current external interrupt enable settings. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiInterruptEnable ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + + Cdb->StatCode =3D PXE_STATCODE_UNSUPPORTED; + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb, Nic= ); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + } +} + +/** + This command is used to read and change receive filters and, + if supported, read and change the multicast MAC address filter list. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiReceiveFilter ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + UINT16 NewFilter; + PXE_DB_RECEIVE_FILTERS *Db; + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_RECEIVE_FILTERS) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8))) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State !=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + return; + } + + NewFilter =3D (UINT16)(Cdb->OpFlags & 0x1F); + + switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) { + case PXE_OPFLAGS_RECEIVE_FILTER_READ: + if (Cdb->CPBsize !=3D PXE_CPBSIZE_NOT_USED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + } + + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) =3D=3D= 0) { + if ((Cdb->DBsize !=3D 0)) { + Db =3D (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr; + CopyMem (Db, &Nic->McastList, Nic->McastCount); + } + } + + break; + + case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE: + if (NewFilter =3D=3D 0) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + + if (Cdb->CPBsize !=3D 0) { + if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) = =3D=3D 0) || + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != =3D 0) || + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) !=3D 0= ) || + ((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) !=3D 0)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } + + if ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != =3D 0) { + if (((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) = !=3D 0) || + ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != =3D 0)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + + if ((Cdb->CPBsize =3D=3D 0)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } + + Cdb->StatCode =3D SetFilter (Nic, NewFilter, Cdb->CPBaddr, Cdb->CPBs= ize); + break; + + case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE: + if (Cdb->CPBsize !=3D PXE_CPBSIZE_NOT_USED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + } + + break; + + default: + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + } + + Cdb->StatFlags =3D (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter); + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + Set PXE receive filter. + + @param[in] Nic A pointer to the Network interface controller da= ta. + @param[in] SetFilter PXE receive filter + @param[in] CpbAddr Command Parameter Block Address + @param[in] CpbSize Command Parameter Block Size + +**/ +UINT16 +SetFilter ( + IN NIC_DATA *Nic, + IN UINT16 SetFilter, + IN UINT64 CpbAddr, + IN UINT32 CpbSize + ) +{ + EFI_STATUS Status; + UINT8 *McastList; + UINT8 Count; + UINT8 Index1; + UINT8 Index2; + PXE_CPB_RECEIVE_FILTERS *Cpb; + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor; + + Count =3D 0; + Cpb =3D (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr; + + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED) + Nic->RxFilter =3D (UINT8)SetFilter; + + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) !=3D 0)= || (Cpb !=3D NULL)) { + if (Cpb !=3D NULL) { + Nic->McastCount =3D (UINT8)(CpbSize / PXE_MAC_LENGTH); + CopyMem (&Nic->McastList, Cpb, Nic->McastCount); + } + + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor); + if ((UsbEthFunDescriptor.NumberMcFilters << 1) =3D=3D 0) { + Nic->RxFilter |=3D PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST; + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter); + } else { + Status =3D gBS->AllocatePool (EfiBootServicesData, Nic->McastCount *= 6, (VOID **)&McastList); + if (EFI_ERROR (Status)) { + return PXE_STATCODE_INVALID_PARAMETER; + } + + if (Cpb !=3D NULL) { + for (Index1 =3D 0; Index1 < Nic->McastCount; Index1++) { + for (Index2 =3D 0; Index2 < 6; Index2++) { + McastList[Count++] =3D Cpb->MCastList[Index1][Index2]; + } + } + } + + Nic->RxFilter |=3D PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST; + if (Cpb !=3D NULL) { + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, M= castList); + } + + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter); + FreePool (McastList); + } + } + + return PXE_STATCODE_SUCCESS; +} + +/** + This command is used to get current station and broadcast MAC addresses + and, if supported, to change the current station MAC address. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiStationAddress ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + PXE_CPB_STATION_ADDRESS *Cpb; + PXE_DB_STATION_ADDRESS *Db; + UINT16 Index; + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_STATION_ADDRESS) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->DBsize !=3D sizeof (PXE_DB_STATION_ADDRESS))) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State !=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + return; + } + + if (Cdb->OpFlags =3D=3D PXE_OPFLAGS_STATION_ADDRESS_RESET) { + if (CompareMem (&Nic->CurrentNodeAddress[0], &Nic->PermNodeAddress[0],= PXE_MAC_LENGTH) !=3D 0) { + for (Index =3D 0; Index < PXE_MAC_LENGTH; Index++) { + Nic->CurrentNodeAddress[Index] =3D Nic->PermNodeAddress[Index]; + } + } + } + + if (Cdb->CPBaddr !=3D 0) { + Cpb =3D (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr; + for (Index =3D 0; Index < PXE_MAC_LENGTH; Index++) { + Nic->CurrentNodeAddress[Index] =3D Cpb->StationAddr[Index]; + } + } + + if (Cdb->DBaddr !=3D 0) { + Db =3D (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr; + for (Index =3D 0; Index < PXE_MAC_LENGTH; Index++) { + Db->StationAddr[Index] =3D Nic->CurrentNodeAddress[Index]; + Db->BroadcastAddr[Index] =3D Nic->BroadcastNodeAddress[Index]; + Db->PermanentAddr[Index] =3D Nic->PermNodeAddress[Index]; + } + } + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb, Nic)= ; + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + This command is used to read and clear the NIC traffic statistics. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiStatistics ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_STATISTICS) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D PXE_CPBSIZE_NOT_USED) || + (Cdb->CPBaddr !=3D PXE_CPBADDR_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + } + + if (Nic->State !=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + return; + } + + if ((Cdb->OpFlags !=3D PXE_OPFLAGS_STATISTICS_RESET) && + (Cdb->OpFlags !=3D PXE_OPFLAGS_STATISTICS_READ)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } + + Cdb->StatCode =3D Statistics (Nic, Cdb->DBaddr, Cdb->DBsize); + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + Return data for DB data. + + @param[in] Nic A pointer to the Network interface controller data. + @param[in] DbAddr Data Block Address. + @param[in] DbSize Data Block Size. + +**/ +UINT16 +Statistics ( + IN NIC_DATA *Nic, + IN UINT64 DbAddr, + IN UINT16 DbSize + ) +{ + PXE_DB_STATISTICS *DbStatistic; + EFI_STATUS Status; + + DbStatistic =3D (PXE_DB_STATISTICS *)(UINTN)DbAddr; + + if (DbSize =3D=3D 0) { + return PXE_STATCODE_SUCCESS; + } + + DbStatistic->Supported =3D 0x802; + DbStatistic->Data[0x01] =3D Nic->RxFrame; + DbStatistic->Data[0x0B] =3D Nic->TxFrame; + + if (Nic->UsbEth->UsbEthStatistics !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize); + if (EFI_ERROR (Status)) { + return PXE_STATFLAGS_COMMAND_FAILED; + } + } + + return PXE_STATCODE_SUCCESS; +} + +/** + Translate a multicast IPv4 or IPv6 address to a multicast MAC address. + + @param[in, out] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiMcastIp2Mac ( + IN OUT PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + PXE_CPB_MCAST_IP_TO_MAC *Cpb; + PXE_DB_MCAST_IP_TO_MAC *Db; + UINT8 *Tmp; + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_MCAST_IP_TO_MAC) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D sizeof (PXE_CPB_MCAST_IP_TO_MAC)) || + (Cdb->DBsize !=3D sizeof (PXE_DB_MCAST_IP_TO_MAC))) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State !=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + return; + } + + Cpb =3D (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr; + Db =3D (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr; + + if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) !=3D 0) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_UNSUPPORTED; + return; + } + + Tmp =3D (UINT8 *)(&Cpb->IP.IPv4); + + if ((Tmp[0] & 0xF0) !=3D 0xE0) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CPB; + } + + Db->MAC[0] =3D 0x01; + Db->MAC[1] =3D 0x00; + Db->MAC[2] =3D 0x5E; + Db->MAC[3] =3D Tmp[1] & 0x7F; + Db->MAC[4] =3D Tmp[2]; + Db->MAC[5] =3D Tmp[3]; + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + This command is used to read and write (if supported by NIC H/W) + nonvolatile storage on the NIC. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiNvData ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + + Cdb->StatCode =3D PXE_STATCODE_UNSUPPORTED; + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + } +} + +/** + This command returns the current interrupt status and/or the + transmitted buffer addresses and the current media status. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiGetStatus ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + PXE_DB_GET_STATUS *Db; + PXE_DB_GET_STATUS TmpGetStatus; + UINT16 NumEntries; + UINTN Index; + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_GET_STATUS) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D PXE_CPBSIZE_NOT_USED) || + (Cdb->CPBaddr !=3D PXE_CPBADDR_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State !=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + return; + } + + TmpGetStatus.RxFrameLen =3D 0; + TmpGetStatus.reserved =3D 0; + Db =3D (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr; + + if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) { + CopyMem (Db, &TmpGetStatus, Cdb->DBsize); + } else { + CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2); + } + + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) !=3D 0) { + if (Cdb->DBsize =3D=3D 0) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } + + NumEntries =3D Cdb->DBsize - sizeof (UINT64); + Cdb->DBsize =3D sizeof (UINT32) * 2; + + for (Index =3D 0; NumEntries >=3D sizeof (UINT64); Index++, NumEntries= -=3D sizeof (UINT64)) { + if (Nic->TxBufferCount > 0) { + Nic->TxBufferCount--; + Db->TxBuffer[Index] =3D Nic->MediaHeader[Nic->TxBufferCount]; + } + } + } + + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) !=3D 0) { + if (Nic->ReceiveStatus !=3D 0) { + Cdb->StatFlags |=3D PXE_STATFLAGS_GET_STATUS_RECEIVE; + } + } + + if ((Nic->Request.Request =3D=3D USB_CDC_NETWORK_CONNECTION) && (Nic->Re= quest.Value =3D=3D NETWORK_DISCONNECT)) { + Nic->CableDetect =3D 0; + } else if ((Nic->Request.Request =3D=3D USB_CDC_NETWORK_CONNECTION) && (= Nic->Request.Value =3D=3D NETWORK_CONNECTED)) { + Nic->CableDetect =3D 1; + } + + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) !=3D 0) { + if (Nic->CableDetect =3D=3D 0) { + Cdb->StatFlags |=3D PXE_STATFLAGS_GET_STATUS_NO_MEDIA; + } + } + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + This command is used to fill the media header(s) in transmit packet(s). + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiFillHeader ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + PXE_CPB_FILL_HEADER *CpbFillHeader; + PXE_CPB_FILL_HEADER_FRAGMENTED *CpbFill; + EthernetHeader *MacHeader; + UINTN Index; + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_FILL_HEADER) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) || + (Cdb->DBsize !=3D PXE_DBSIZE_NOT_USED) || + (Cdb->DBaddr !=3D PXE_DBADDR_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State !=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + return; + } + + if (Cdb->CPBsize =3D=3D PXE_CPBSIZE_NOT_USED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } + + if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) !=3D 0) { + CpbFill =3D (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb->CPBaddr; + + if ((CpbFill->FragCnt =3D=3D 0) || (CpbFill->FragDesc[0].FragLen < PXE= _MAC_HEADER_LEN_ETHER)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } + + MacHeader =3D (EthernetHeader *)(UINTN)CpbFill->FragDesc[0].= FragAddr; + MacHeader->Protocol =3D CpbFill->Protocol; + + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + MacHeader->DestAddr[Index] =3D CpbFill->DestAddr[Index]; + MacHeader->SrcAddr[Index] =3D CpbFill->SrcAddr[Index]; + } + } else { + CpbFillHeader =3D (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr; + + MacHeader =3D (EthernetHeader *)(UINTN)CpbFillHeader->MediaH= eader; + MacHeader->Protocol =3D CpbFillHeader->Protocol; + + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + MacHeader->DestAddr[Index] =3D CpbFillHeader->DestAddr[Index]; + MacHeader->SrcAddr[Index] =3D CpbFillHeader->SrcAddr[Index]; + } + } + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + } +} + +/** + The Transmit command is used to place a packet into the transmit queue. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiTransmit ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_TRANSMIT) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D sizeof (PXE_CPB_TRANSMIT)) || + (Cdb->DBsize !=3D PXE_DBSIZE_NOT_USED) || + (Cdb->DBaddr !=3D PXE_DBADDR_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State !=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; + return; + } + + if (Cdb->CPBsize =3D=3D PXE_CPBSIZE_NOT_USED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + + return; + } + + Cdb->StatCode =3D Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags); + + if (Cdb->StatCode !=3D PXE_STATCODE_SUCCESS) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } +} + +/** + Use USB Ethernet Protocol Bulk out command to transmit data. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in, out] Nic A pointer to the Network interface controller d= ata. + @param[in] CpbAddr Command Parameter Block Address. + @param[in] OpFlags Operation Flags. + +**/ +UINT16 +Transmit ( + IN PXE_CDB *Cdb, + IN OUT NIC_DATA *Nic, + IN UINT64 CpbAddr, + IN UINT16 OpFlags + ) +{ + EFI_STATUS Status; + PXE_CPB_TRANSMIT *Cpb; + UINT64 BulkOutData; + UINTN DataLength; + UINTN TransmitLength; + UINTN Map; + UINT32 Counter; + UINT16 StatCode; + + BulkOutData =3D 0; + Counter =3D 0; + Cpb =3D (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr; + + if (Nic->CanTransmit) { + return PXE_STATCODE_BUSY; + } + + Nic->CanTransmit =3D TRUE; + + if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) !=3D 0) { + return PXE_STATCODE_INVALID_PARAMETER; + } + + Map =3D MapIt ( + Nic, + Cpb->FrameAddr, + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen, + TO_DEVICE, + (UINT64)(UINTN)&BulkOutData + ); + + if (Map !=3D 0) { + Nic->CanTransmit =3D FALSE; + return PXE_STATCODE_INVALID_PARAMETER; + } + + if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) { + Nic->MediaHeader[Nic->TxBufferCount] =3D Cpb->FrameAddr; + Nic->TxBufferCount++; + } + + DataLength =3D (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen); + + while (1) { + if (Counter >=3D 3) { + StatCode =3D PXE_STATCODE_BUSY; + break; + } + + TransmitLength =3D DataLength; + + Status =3D Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID *)(UIN= TN)BulkOutData, &TransmitLength); + if (EFI_ERROR (Status)) { + StatCode =3D PXE_STATFLAGS_COMMAND_FAILED; + } + + if (Status =3D=3D EFI_INVALID_PARAMETER) { + StatCode =3D PXE_STATCODE_INVALID_PARAMETER; + break; + } + + if (Status =3D=3D EFI_DEVICE_ERROR) { + StatCode =3D PXE_STATCODE_DEVICE_FAILURE; + break; + } + + if (!EFI_ERROR (Status)) { + Nic->TxFrame++; + StatCode =3D PXE_STATCODE_SUCCESS; + break; + } + + Counter++; + } + + UnMapIt ( + Nic, + Cpb->FrameAddr, + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen, + TO_DEVICE, + BulkOutData + ); + + Nic->CanTransmit =3D FALSE; + + return StatCode; +} + +/** + When the network adapter has received a frame, this command is used + to copy the frame into driver/application storage. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + +**/ +VOID +UndiReceive ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + + if ((Cdb->OpCode !=3D PXE_OPCODE_RECEIVE) || + (Cdb->StatCode !=3D PXE_STATCODE_INITIALIZE) || + (Cdb->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || + (Cdb->IFnum >=3D (gPxe->IFcnt | gPxe->IFcntExt << 8)) || + (Cdb->CPBsize !=3D sizeof (PXE_CPB_RECEIVE)) || + (Cdb->DBsize !=3D sizeof (PXE_DB_RECEIVE)) || + (Cdb->OpFlags !=3D PXE_OPFLAGS_NOT_USED)) + { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_INVALID_CDB; + return; + } else { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode =3D PXE_STATCODE_SUCCESS; + } + + if (Nic->State !=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; + return; + } + + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive !=3D NULL) { + Status =3D Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic); + if (EFI_ERROR (Status)) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } + + return; + } + + Cdb->StatCode =3D Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr); + + if (Cdb->StatCode !=3D PXE_STATCODE_SUCCESS) { + Cdb->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; + } +} + +/** + Use USB Ethernet Protocol Bulk in command to receive data. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in, out] Nic A pointer to the Network interface controller d= ata. + @param[in] CpbAddr Command Parameter Block Address. + @param[in, out] DbAddr Data Block Address. + +**/ +UINT16 +Receive ( + IN PXE_CDB *Cdb, + IN OUT NIC_DATA *Nic, + IN UINT64 CpbAddr, + IN OUT UINT64 DbAddr + ) +{ + EFI_STATUS Status; + UINTN Index; + PXE_FRAME_TYPE FrameType; + PXE_CPB_RECEIVE *Cpb; + PXE_DB_RECEIVE *Db; + NIC_DEVICE *NicDevice; + UINT8 *BulkInData; + UINTN DataLength; + EthernetHeader *Header; + EFI_TPL OriginalTpl; + + FrameType =3D PXE_FRAME_TYPE_NONE; + NicDevice =3D UNDI_DEV_FROM_NIC (Nic); + BulkInData =3D NicDevice->ReceiveBuffer; + DataLength =3D (UINTN)Nic->MaxSegmentSize; + Cpb =3D (PXE_CPB_RECEIVE *)(UINTN)CpbAddr; + Db =3D (PXE_DB_RECEIVE *)(UINTN)DbAddr; + + if (!BulkInData) { + return PXE_STATCODE_INVALID_PARAMETER; + } + + if ((Nic->RateLimitingCreditCount =3D=3D 0) && (Nic->RateLimitingEnable = =3D=3D TRUE)) { + return PXE_STATCODE_NO_DATA; + } + + Status =3D Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID *)BulkInD= ata, &DataLength); + if (EFI_ERROR (Status)) { + Nic->ReceiveStatus =3D 0; + if (Nic->RateLimitingEnable =3D=3D TRUE) { + OriginalTpl =3D gBS->RaiseTPL (TPL_NOTIFY); + if (Nic->RateLimitingCreditCount !=3D 0) { + Nic->RateLimitingCreditCount--; + } + + gBS->RestoreTPL (OriginalTpl); + } + + return PXE_STATCODE_NO_DATA; + } + + Nic->RxFrame++; + + if (DataLength !=3D 0) { + if (DataLength > Cpb->BufferLen) { + DataLength =3D (UINTN)Cpb->BufferLen; + } + + CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData, DataLen= gth); + + Header =3D (EthernetHeader *)BulkInData; + + Db->FrameLen =3D (UINT32)DataLength; + Db->MediaHeaderLen =3D PXE_MAC_HEADER_LEN_ETHER; + + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + if (Header->DestAddr[Index] !=3D Nic->CurrentNodeAddress[Index]) { + break; + } + } + + if (Index >=3D PXE_HWADDR_LEN_ETHER) { + FrameType =3D PXE_FRAME_TYPE_UNICAST; + } else { + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + if (Header->DestAddr[Index] !=3D Nic->BroadcastNodeAddress[Index])= { + break; + } + } + + if (Index >=3D PXE_HWADDR_LEN_ETHER) { + FrameType =3D PXE_FRAME_TYPE_BROADCAST; + } else { + if ((Header->DestAddr[0] & 1) =3D=3D 1) { + FrameType =3D PXE_FRAME_TYPE_FILTERED_MULTICAST; + } else { + FrameType =3D PXE_FRAME_TYPE_PROMISCUOUS; + } + } + } + + Db->Type =3D FrameType; + Db->Protocol =3D Header->Protocol; + + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + Db->SrcAddr[Index] =3D Header->SrcAddr[Index]; + Db->DestAddr[Index] =3D Header->DestAddr[Index]; + } + } + + if (FrameType =3D=3D PXE_FRAME_TYPE_NONE) { + Nic->ReceiveStatus =3D 0; + } else { + Nic->ReceiveStatus =3D 1; + } + + return PXE_STATCODE_SUCCESS; +} + +/** + Fill out PXE SW UNDI structure. + + @param[out] PxeSw A pointer to the PXE SW UNDI structure. + +**/ +VOID +PxeStructInit ( + OUT PXE_SW_UNDI *PxeSw + ) +{ + PxeSw->Signature =3D PXE_ROMID_SIGNATURE; + PxeSw->Len =3D (UINT8)sizeof (PXE_SW_UNDI); + PxeSw->Fudge =3D 0; + PxeSw->IFcnt =3D 0; + PxeSw->IFcntExt =3D 0; + PxeSw->Rev =3D PXE_ROMID_REV; + PxeSw->MajorVer =3D PXE_ROMID_MAJORVER; + PxeSw->MinorVer =3D PXE_ROMID_MINORVER; + PxeSw->reserved1 =3D 0; + + PxeSw->Implementation =3D PXE_ROMID_IMP_SW_VIRT_ADDR | + PXE_ROMID_IMP_FRAG_SUPPORTED | + PXE_ROMID_IMP_CMD_LINK_SUPPORTED | + PXE_ROMID_IMP_STATION_ADDR_SETTABLE | + PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED= | + PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED | + PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED | + PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED; + + PxeSw->EntryPoint =3D (UINT64)(UINTN)UndiApiEntry; + PxeSw->reserved2[0] =3D 0; + PxeSw->reserved2[1] =3D 0; + PxeSw->reserved2[2] =3D 0; + PxeSw->BusCnt =3D 1; + PxeSw->BusType[0] =3D PXE_BUSTYPE_USB; + PxeSw->Fudge =3D PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, Pxe= Sw->Len); +} + +/** + Update NIC number. + + @param[in] Nic A pointer to the Network interface controller = data. + @param[in, out] PxeSw A pointer to the PXE SW UNDI structure. + +**/ +VOID +UpdateNicNum ( + IN NIC_DATA *Nic, + IN OUT PXE_SW_UNDI *PxeSw + ) +{ + UINT16 NicNum; + + NicNum =3D (PxeSw->IFcnt | PxeSw->IFcntExt << 8); + + if (Nic =3D=3D NULL) { + if (NicNum > 0) { + NicNum--; + } + + PxeSw->IFcnt =3D (UINT8)(NicNum & 0xFF); // Get lower byte + PxeSw->IFcntExt =3D (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte + PxeSw->Fudge =3D (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeS= w, PxeSw->Len)); + return; + } + + NicNum++; + + PxeSw->IFcnt =3D (UINT8)(NicNum & 0xFF); // Get lower byte + PxeSw->IFcntExt =3D (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte + PxeSw->Fudge =3D (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw,= PxeSw->Len)); +} + +/** + UNDI API table entry. + + @param[in] Cdb A pointer to the command descriptor block. + +**/ +EFI_STATUS +EFIAPI +UndiApiEntry ( + IN UINT64 Cdb + ) +{ + PXE_CDB *CdbPtr; + NIC_DATA *Nic; + + if (Cdb =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + + CdbPtr =3D (PXE_CDB *)(UINTN)Cdb; + Nic =3D &(gLanDeviceList[CdbPtr->IFnum]->NicInfo); + gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic); + return EFI_SUCCESS; +} + +/** + Map virtual memory address for DMA. This field can be set to + zero if there is no mapping service. + + @param[in] Nic A pointer to the Network interface controller = data. + @param[in] MemAddr Virtual address to be mapped. + @param[in] Size Size of memory to be mapped. + @param[in] Direction Direction of data flow for this memory's usage= : + cpu->device, device->cpu or both ways. + @param[out] MappedAddr Pointer to return the mapped device address. + +**/ +UINTN +MapIt ( + IN NIC_DATA *Nic, + IN UINT64 MemAddr, + IN UINT32 Size, + IN UINT32 Direction, + OUT UINT64 MappedAddr + ) +{ + UINT64 *PhyAddr; + + PhyAddr =3D (UINT64 *)(UINTN)MappedAddr; + + if (Nic->PxeStart.Map_Mem =3D=3D 0) { + *PhyAddr =3D MemAddr; + } else { + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeSta= rt.Map_Mem)( + Nic->PxeStart.Unique_ID, + MemAddr, + Size, + Direction, + MappedAddr + ); + } + + return PXE_STATCODE_SUCCESS; +} + +/** + Un-map previously mapped virtual memory address. This field can be set + to zero only if the Map_Mem() service is also set to zero. + + @param[in] Nic A pointer to the Network interface controller = data. + @param[in] MemAddr Virtual address to be mapped. + @param[in] Size Size of memory to be mapped. + @param[in] Direction Direction of data flow for this memory's usage= : + cpu->device, device->cpu or both ways. + @param[in] MappedAddr Pointer to return the mapped device address. + +**/ +VOID +UnMapIt ( + IN NIC_DATA *Nic, + IN UINT64 MemAddr, + IN UINT32 Size, + IN UINT32 Direction, + IN UINT64 MappedAddr + ) +{ + if (Nic->PxeStart.UnMap_Mem !=3D 0) { + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeSta= rt.UnMap_Mem)( + Nic->PxeStart.Unique_ID, + MemAddr, + Size, + Direction, + MappedAddr + ); + } + + return; +} diff --git a/UsbNetworkPkg/ReadMe.md b/UsbNetworkPkg/ReadMe.md new file mode 100644 index 0000000000..cb70684f0b --- /dev/null +++ b/UsbNetworkPkg/ReadMe.md @@ -0,0 +1,65 @@ +# UsbNetworkPkg + +This document is intend to provide package information, include the interf= ace details. + +# INDEX + * [Introduction](#introduction) + * [Components](#components) + * [[NetworkCommon]](#networkcommon) + * [[UsbCdcEcm]](#usbcdcecm) + * [[UsbCdcNcm]](#usbcdcncm) + * [[UsbRndis]](#usbrndis) + +# Introduction +UsbNetworkPkg provides network functions for USB LAN devices. + +# Components +Below module is included in this package:
+- NetworkCommon +- UsbCdcEcm +- UsbCdcNcm +- UsbRndis + +## [NetworkCommon] +Provides a LAN driver based on UEFI specification(UNDI). It supports USB c= ommunication class subclass devices and USB Rndis devices, depending on the= UsbEthernetProtocol. + +## Required Components +- NetworkPkg + +## [UsbCdcEcm] +This driver provides a communication interface for USB Ethernet devices th= at follows the ECM protocol. The driver installs UsbEthernetProtocol with E= CM functions which are consumed by the NetworkCommon driver. + +The driver is compatible with the following USB class codes: +|Class Code|SubClass Code|Protocol Code| +|:--------:|:-----------:|:-----------:| +|0x02|0x06|0x00| + +## Required Components +- NetworkCommon +- MdeModulePkg(USB bus driver) + +## [UsbCdcNcm] +This driver provides a communication interface for USB Ethernet devices th= at follows the NCM protocol. The driver installs UsbEthernetProtocol with N= CM functions which are consumed by the NetworkCommon driver. + +The driver is compatible with the following USB class codes: +|Class Code|SubClass Code|Protocol Code| +|:--------:|:-----------:|:-----------:| +|0x02|0x0D|0x00| + +## Required Components +- NetworkCommon +- MdeModulePkg(USB bus driver) + +## [UsbRndis] +This driver provides a communication interface for USB Ethernet devices th= at follows the RNDIS protocol. The driver installs UsbEthernetProtocol with= RNDIS functions which are consumed by the NetworkCommon driver. + +The driver is compatible with the following USB class codes: +|Class Code|SubClass Code|Protocol Code| +|:--------:|:-----------:|:-----------:| +|0x02|0x02|0xFF| +|0xEF|0x04|0x01| + +## Required Components +- NetworkCommon +- MdeModulePkg(USB bus driver) + diff --git a/UsbNetworkPkg/UsbNetworkPkg.ci.yaml b/UsbNetworkPkg/UsbNetwork= Pkg.ci.yaml new file mode 100644 index 0000000000..7ee1ef3cf0 --- /dev/null +++ b/UsbNetworkPkg/UsbNetworkPkg.ci.yaml @@ -0,0 +1,65 @@ +## @file +# CI configuration for UsbNetworkPkg +# +# Copyright (c) Microsoft Corporation +# Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + ## options defined .pytool/Plugin/LicenseCheck + "LicenseCheck": { + "IgnoreFiles": [] + }, + "EccCheck": { + ## Exception sample looks like below: + ## "ExceptionList": [ + ## "", "" + ## ] + "ExceptionList": [ + ], + ## Both file path and directory path are accepted. + "IgnoreFiles": [ + ] + }, + "CompilerPlugin": { + "DscPath": "UsbNetworkPkg.dsc" + }, + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "MdeModulePkg/MdeModulePkg.dec", + "NetworkPkg/NetworkPkg.dec" + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[], + "IgnoreInf": [] + }, + "DscCompleteCheck": { + "DscPath": "UsbNetworkPkg.dsc", + "IgnoreInf": [] + }, + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [] + }, + + ## options defined .pytool/Plugin/LibraryClassCheck + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + + ## options defined .pytool/Plugin/SpellCheck + "SpellCheck": { + "AuditOnly": True, # Fails test but run in AuditOnly mod= e to collect log + "IgnoreFiles": [], # use gitignore syntax to ignore erro= rs in matching files + "ExtendWords": [], # words to extend to the dictionary f= or this package + "IgnoreStandardPaths": [], # Standard Plugin defined paths that = should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wi= ldcards supported) + } +} diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec b/UsbNetworkPkg/UsbNetworkPkg.= dec new file mode 100644 index 0000000000..30e4e4c8aa --- /dev/null +++ b/UsbNetworkPkg/UsbNetworkPkg.dec @@ -0,0 +1,46 @@ +## @file +# This package defines Usb network specific interfaces and library classe= s +# as well as configuration for standard edk2 packages. +# +# Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + DEC_SPECIFICATION =3D 0x00010005 + PACKAGE_NAME =3D UsbNetworkPkg + PACKAGE_GUID =3D abfab91e-37ea-4cb4-80a6-563dbb0bcec6 + PACKAGE_VERSION =3D 0.1 + +[Includes] + Include + +[Protocols] + ## Include/Protocol/EdkIIUsbEthernet.h + gEdkIIUsbEthProtocolGuid =3D { 0x8d8969cc, 0xfeb0, 0x4303, { 0xb2, 0x1a,= 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43 } } + +[Guids] + ## Usb Network package token space GUID + gUsbNetworkPkgTokenSpaceGuid =3D { 0xA1231E82, 0x21B8, 0x4204, { 0x92, = 0xBB, 0x37, 0x3A, 0xFB, 0x01, 0xC6, 0xA1 } } + +[PcdsFeatureFlag] + + ## Set the PCD 'UsbCdcEcmSupport' to 'TRUE' if 'Usb Cdc Ecm device' need= to be enabled. + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE|BOOLEAN|0x00000001 + + ## Set the PCD 'UsbCdcNcmSupport' to 'TRUE' if 'Usb Cdc Ncm device' need= to be enabled. + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE|BOOLEAN|0x00000002 + + ## Set the PCD 'UsbRndisSupport' to 'TRUE' if 'Usb Rndis device' need to= be enabled. + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE|BOOLEAN|0x00000003 + +[PcdsFixedAtBuild, PcdsPatchableInModule] + ## Support rate limiting + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting|FALSE|BOOLEAN|0x00010001 + + ## The rate limiting Credit value is check in rate limiter event. + # It is to control the RateLimitingCreditCount max value. + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit|10|UINT32|0x00010002 + + ## The value of rate limiter event for timeout check. Default value is 1= 00(unit 1ms). + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor|100|UINT32|0x00010003 diff --git a/UsbNetworkPkg/UsbNetworkPkg.dsc b/UsbNetworkPkg/UsbNetworkPkg.= dsc new file mode 100644 index 0000000000..c2bbfcb2db --- /dev/null +++ b/UsbNetworkPkg/UsbNetworkPkg.dsc @@ -0,0 +1,50 @@ +## @file +# Global DSC definitions to be included into project DSC file. +# +# Copyright (c) 1985 - 2023, AMI. All rights reserved.
+# Subject to AMI licensing agreement. +## + +[Defines] + PLATFORM_NAME =3D NetworkPkg + PLATFORM_GUID =3D C5995C1C-1E5C-43F9-826D-27E43A7243B8 + PLATFORM_VERSION =3D 1 + DSC_SPECIFICATION =3D 0x00010005 + OUTPUT_DIRECTORY =3D Build/UsbNetworkPkg + SUPPORTED_ARCHITECTURES =3D IA32|X64|EBC|ARM|AARCH64|RISCV64|LOON= GARCH64 + BUILD_TARGETS =3D DEBUG|RELEASE|NOOPT + SKUID_IDENTIFIER =3D DEFAULT + +[PcdsFeatureFlag] + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|TRUE + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|TRUE + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE + +!include MdePkg/MdeLibs.dsc.inc + +[LibraryClasses] + # + # Entry Point Libraries + # + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntry= Point.inf + # + # Common Libraries + # + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAll= ocationLib.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBoo= tServicesTableLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/U= efiRuntimeServicesTableLib.inf + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseD= ebugPrintErrorLevelLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf + +[Components] +!include UsbNetworkPkg/UsbNetworkPkg.dsc.inc + +[BuildOptions] + *_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/UsbNetworkPkg/UsbNetworkPkg.dsc.inc b/UsbNetworkPkg/UsbNetwork= Pkg.dsc.inc new file mode 100644 index 0000000000..f5df11ace6 --- /dev/null +++ b/UsbNetworkPkg/UsbNetworkPkg.dsc.inc @@ -0,0 +1,27 @@ +## @file +# Global DSC definitions to be included into project DSC file. +# +# Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + +!ifndef PLATFORMX64_ENABLE + # + # PLATFORMX64_ENABLE is set to TRUE when PEI is IA32 and DXE is X64 plat= form + # + DEFINE PLATFORMX64_ENABLE =3D FALSE +!endif + +!include UsbNetworkPkg/UsbNetworkPkgPcds.dsc.inc + +!if $(PLATFORMX64_ENABLE) =3D=3D TRUE +[Components.X64] +!include UsbNetworkPkg/UsbNetworkPkgComponentsDxe.dsc.inc + +!else +[Components.IA32, Components.X64, Components.ARM, Components.AARCH64, Comp= onents.RISCV64, Components.LOONGARCH64] +!include UsbNetworkPkg/UsbNetworkPkgComponentsDxe.dsc.inc + +!endif diff --git a/UsbNetworkPkg/UsbNetworkPkgComponentsDxe.dsc.inc b/UsbNetworkP= kg/UsbNetworkPkgComponentsDxe.dsc.inc new file mode 100644 index 0000000000..544df8404c --- /dev/null +++ b/UsbNetworkPkg/UsbNetworkPkgComponentsDxe.dsc.inc @@ -0,0 +1,20 @@ +## @file +# List of Core Components. +# +# Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + UsbNetworkPkg/NetworkCommon/NetworkCommon.inf + +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport + UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf +!endif + +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport + UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf +!endif + +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport + UsbNetworkPkg/UsbRndis/UsbRndis.inf +!endif diff --git a/UsbNetworkPkg/UsbNetworkPkgComponentsDxe.fdf.inc b/UsbNetworkP= kg/UsbNetworkPkgComponentsDxe.fdf.inc new file mode 100644 index 0000000000..10616d97ed --- /dev/null +++ b/UsbNetworkPkg/UsbNetworkPkgComponentsDxe.fdf.inc @@ -0,0 +1,20 @@ +## @file +# List of Core Components. +# +# Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + INF UsbNetworkPkg/NetworkCommon/NetworkCommon.inf + +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport + INF UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf +!endif + +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport + INF UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf +!endif + +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport + INF UsbNetworkPkg/UsbRndis/UsbRndis.inf +!endif diff --git a/UsbNetworkPkg/UsbNetworkPkgPcds.dsc.inc b/UsbNetworkPkg/UsbNet= workPkgPcds.dsc.inc new file mode 100644 index 0000000000..51382d18d3 --- /dev/null +++ b/UsbNetworkPkg/UsbNetworkPkgPcds.dsc.inc @@ -0,0 +1,14 @@ +## @file +# Global switches enable/disable project features. +# +# Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Packages] + UsbNetworkPkg/UsbNetworkPkg.dec + +[PcdsFeatureFlag] + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE diff --git a/UsbNetworkPkg/UsbRndis/ComponentName.c b/UsbNetworkPkg/UsbRndi= s/ComponentName.c new file mode 100644 index 0000000000..b9ba170c13 --- /dev/null +++ b/UsbNetworkPkg/UsbRndis/ComponentName.c @@ -0,0 +1,172 @@ +/** @file + This file contains code for USB RNDIS Driver Component + Name definitions + + Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "UsbRndis.h" + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gUsbRndisDriverNam= eTable[] =3D { + { + "eng;en", + L"USB RNDIS Driver" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +UsbRndisComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +UsbRndisComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbRndisCompon= entName =3D { + UsbRndisComponentNameGetDriverName, + UsbRndisComponentNameGetControllerName, + "eng" +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisCompo= nentName2 =3D { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbRndisComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbRndisComponentNameGetControl= lerName, + "en" +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form o= f a + Unicode string. If the driver specified by This has a user readable name= in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver speci= fied + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param[in] Language A pointer to a Null-terminated ASCII strin= g + array indicating the language. This is the + language of the driver name that the calle= r is + requesting, and it must match one of the + languages specified in SupportedLanguages.= The + number of languages supported by a driver = is up + to the driver writer. Language is specifie= d + in RFC 4646 or ISO 639-2 language code for= mat. + @param[out] DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specifie= d by + This and the language specified by Languag= e was + returned in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UsbRndisComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + gUsbRndisDriverNameTable, + DriverName, + (BOOLEAN)(This =3D=3D &gUsbRndisComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the control= ler + that is being managed by a driver. + + This function retrieves the user readable name of the controller specifi= ed by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specif= ied by + Language, then a pointer to the controller name is returned in Controlle= rName, + and EFI_SUCCESS is returned. If the driver specified by This is not cur= rently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does = not + support the language specified by Language, then EFI_UNSUPPORTED is retu= rned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param[in] Controller The handle of a controller that the driver + specified by This is managing. This handl= e + specifies the controller whose name is to = be + returned. + @param[in] ChildHandle The handle of the child controller to retr= ieve + the name of. This is an optional paramete= r that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus d= rivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of= a + child controller. + @param[in] Language A pointer to a Null-terminated ASCII strin= g + array indicating the language. This is th= e + language of the driver name that the calle= r is + requesting, and it must match one of the + languages specified in SupportedLanguages.= The + number of languages supported by a driver = is up + to the driver writer. Language is specifie= d in + RFC 4646 or ISO 639-2 language code format= . + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle a= nd + ChildHandle in the language specified by + Language from the point of view of the dri= ver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable n= ame in + the language specified by Language for the + driver specified by This was returned in + DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE= . + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a va= lid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not curren= tly + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UsbRndisComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.c b/UsbNetworkPkg/UsbRndis/Usb= Rndis.c new file mode 100644 index 0000000000..92830771e4 --- /dev/null +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.c @@ -0,0 +1,886 @@ +/** @file + This file contains code for USB Remote Network Driver + Interface Spec. Driver Binding + + Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "UsbRndis.h" + +EFI_DRIVER_BINDING_PROTOCOL gUsbRndisDriverBinding =3D { + UsbRndisDriverSupported, + UsbRndisDriverStart, + UsbRndisDriverStop, + USB_RNDIS_DRIVER_VERSION, + NULL, + NULL +}; + +/** + Check if this interface is USB Rndis SubType + + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance. + + @retval TRUE USB Rndis SubType. + @retval FALSE Not USB Rndis SubType. + +**/ +BOOLEAN +IsSupportedDevice ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ) +{ + EFI_STATUS Status; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + Status =3D UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor= ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + // Check specific device/RNDIS and CDC-DATA + if (((InterfaceDescriptor.InterfaceClass =3D=3D 0x2) && + (InterfaceDescriptor.InterfaceSubClass =3D=3D 0x2) && + (InterfaceDescriptor.InterfaceProtocol =3D=3D 0xFF)) || \ + ((InterfaceDescriptor.InterfaceClass =3D=3D 0xEF) && + (InterfaceDescriptor.InterfaceSubClass =3D=3D 0x4) && + (InterfaceDescriptor.InterfaceProtocol =3D=3D 0x1)) || \ + ((InterfaceDescriptor.InterfaceClass =3D=3D 0xA) && + (InterfaceDescriptor.InterfaceSubClass =3D=3D 0x0) && + (InterfaceDescriptor.InterfaceProtocol =3D=3D 0x00)) + ) + { + return TRUE; + } + + return FALSE; +} + +/** + Check if this interface is USB Rndis SubType but not CDC Data interface + + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance. + + @retval TRUE USB Rndis SubType. + @retval FALSE Not USB Rndis SubType. +**/ +BOOLEAN +IsRndisInterface ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ) +{ + EFI_STATUS Status; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + Status =3D UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor= ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + // Check for specific device/RNDIS and CDC-DATA + if (((InterfaceDescriptor.InterfaceClass =3D=3D 0x2) && + (InterfaceDescriptor.InterfaceSubClass =3D=3D 0x2) && + (InterfaceDescriptor.InterfaceProtocol =3D=3D 0xFF)) || \ + ((InterfaceDescriptor.InterfaceClass =3D=3D 0xEF) && + (InterfaceDescriptor.InterfaceSubClass =3D=3D 0x4) && + (InterfaceDescriptor.InterfaceProtocol =3D=3D 0x1)) + ) + { + return TRUE; + } + + return FALSE; +} + +/** + Check if the USB RNDIS and USB CDC Data interfaces are from the same dev= ice. + + @param[in] UsbRndisDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL = instance. + @param[in] UsbCdcDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL = instance. + + @retval EFI_SUCCESS Is the same device. + @retval EFI_UNSUPPORTED Is not the same device. + +**/ +EFI_STATUS +IsSameDevice ( + IN EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath, + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath + ) +{ + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Entry \n")); + while (1) { + if (IsDevicePathEnd (NextDevicePathNode (UsbRndisDataPath))) { + if (((USB_DEVICE_PATH *)UsbRndisDataPath)->ParentPortNumber =3D=3D + ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber) + { + return EFI_SUCCESS; + } else { + return EFI_UNSUPPORTED; + } + } else { + if (CompareMem (UsbCdcDataPath, UsbRndisDataPath, sizeof (EFI_DEVICE= _PATH_PROTOCOL)) !=3D 0) { + return EFI_UNSUPPORTED; + } + + UsbRndisDataPath =3D NextDevicePathNode (UsbRndisDataPath); + UsbCdcDataPath =3D NextDevicePathNode (UsbCdcDataPath); + } + } + + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Exit \n")); +} + +/** + Check if the USB CDC Data(UsbIo) installed and return USB CDC Data Handl= e. + + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance. + + @retval TRUE USB CDC Data(UsbIo) installed. + @retval FALSE USB CDC Data(UsbIo) did not installed. + +**/ +BOOLEAN +IsUsbCdcData ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ) +{ + EFI_STATUS Status; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + Status =3D UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor= ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + // Check for CDC-DATA + if ((InterfaceDescriptor.InterfaceClass =3D=3D 0xA) && + (InterfaceDescriptor.InterfaceSubClass =3D=3D 0x0) && + (InterfaceDescriptor.InterfaceProtocol =3D=3D 0x0)) + { + return TRUE; + } + + return FALSE; +} + +/** + Check if the USB Rndis(UsbIo) installed + + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance. + + @retval TRUE USB Rndis(UsbIo) installed. + @retval FALSE USB Rndis(UsbIo) did not installed. + +**/ +BOOLEAN +IsUsbRndis ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ) +{ + EFI_STATUS Status; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + Status =3D UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor= ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + // Check for Rndis + if ((InterfaceDescriptor.InterfaceClass =3D=3D 0x2) && + (InterfaceDescriptor.InterfaceSubClass =3D=3D 0x2) && + (InterfaceDescriptor.InterfaceProtocol =3D=3D 0xFF)) + { + return TRUE; + } + + return FALSE; +} + +/** + Control comes here when a CDC device is found.Check if a RNDIS interface= is already found for this device or not. + For one device two USBIO will be installed each for CDC and RNDIS interf= ace. + + @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL = instance. + @param[out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE Data. + + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC D= ata is found. + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC D= ata is not found. + +**/ +EFI_STATUS +UpdateRndisDevice ( + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath, + OUT USB_RNDIS_DEVICE **UsbRndisDevice + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice; + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath; + EFI_USB_IO_PROTOCOL *UsbIo; + BOOLEAN IsRndisInterfaceFlag; + + IsRndisInterfaceFlag =3D FALSE; + + Status =3D gBS->LocateHandleBuffer ( + ByProtocol, + &gEdkIIUsbEthProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index =3D 0; Index < HandleCount; Index++) { + Status =3D gBS->HandleProtocol ( + HandleBuffer[Index], + &gEdkIIUsbEthProtocolGuid, + (VOID **)&UsbEthDevice + ); + if (EFI_ERROR (Status)) { + continue; + } + + Status =3D gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiUsbIoProtocolGuid, + (VOID **)&UsbIo + ); + if (EFI_ERROR (Status)) { + continue; + } + + IsRndisInterfaceFlag =3D IsRndisInterface (UsbIo); + if (IsRndisInterfaceFlag =3D=3D FALSE) { + continue; + } + + Status =3D gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + (VOID **)&UsbRndisDataPath + ); + if (EFI_ERROR (Status)) { + continue; + } + + Status =3D IsSameDevice (UsbRndisDataPath, UsbCdcDataPath); + + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status)); + + if (!EFI_ERROR (Status)) { + *UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice); + FreePool (HandleBuffer); + return EFI_SUCCESS; + } + } // End of For loop + + FreePool (HandleBuffer); + return EFI_NOT_FOUND; +} + +/** + + For the given Rndis Device, find a matching CDC device already exists or= not. If found update the handle + and UsbIO protocol. + + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE data= . + +**/ +VOID +FindMatchingCdcData ( + IN USB_RNDIS_DEVICE *UsbRndisDevice + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath; + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath; + + // Find the parent RNDIS and update the UsbIo for the CDC device + Status =3D gBS->HandleProtocol ( + UsbRndisDevice->UsbRndisHandle, + &gEfiDevicePathProtocolGuid, + (VOID **)&UsbRndisDataPath + ); + + if (EFI_ERROR (Status)) { + return; + } + + Status =3D gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiUsbIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return; + } + + for (Index =3D 0; Index < HandleCount; Index++) { + Status =3D gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiUsbIoProtocolGuid, + (VOID **)&UsbIo + ); + ASSERT_EFI_ERROR (Status); + + if (IsUsbCdcData (UsbIo)) { + DEBUG ((DEBUG_VERBOSE, "Rndis FindMatchingCdcData CDCData interface = found\n")); + + Status =3D gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + (VOID **)&UsbCdcDataPath + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "Rndis CDCData DevicePath not found\n")); + FreePool (HandleBuffer); + return; + } + + Status =3D IsSameDevice (UsbRndisDataPath, UsbCdcDataPath); + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status)); + if (!EFI_ERROR (Status)) { + UsbRndisDevice->UsbCdcDataHandle =3D HandleBuffer[Index]; + UsbRndisDevice->UsbIoCdcData =3D UsbIo; + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice); + FreePool (HandleBuffer); + return; + } + } + } // End of For loop + + FreePool (HandleBuffer); +} + +/** + + For the given UsbIo CdcData, find a matching RNDIS device already exists= or not. + + @param[in] CdcHandle A pointer to the EFI_HANDLE for USB CDC Data= . + @param[out] CdcUsbIo A pointer for retrieve the EFI_USB_IO_PROTOC= OL instance. + @param[out] RndisHandle A pointer for retrieve the handle of RNDIS d= evice. + + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC D= ata is found. + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC D= ata is not found. + +**/ +EFI_STATUS +EFIAPI +FindMatchingRndisDev ( + IN EFI_HANDLE CdcHandle, + OUT EFI_USB_IO_PROTOCOL **CdcUsbIo, + OUT EFI_HANDLE *RndisHandle + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath; + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath; + + // Find the parent RNDIS and update the UsbIo for the CDC device + Status =3D gBS->HandleProtocol ( + CdcHandle, + &gEfiDevicePathProtocolGuid, + (VOID **)&UsbCdcDataPath + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiUsbIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index =3D 0; Index < HandleCount; Index++) { + Status =3D gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiUsbIoProtocolGuid, + (VOID **)&UsbIo + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsUsbRndis (UsbIo)) { + Status =3D gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + (VOID **)&UsbRndisDataPath + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Usb Rndis DevicePath not found\n")); + break; + } + + Status =3D IsSameDevice (UsbRndisDataPath, UsbCdcDataPath); + + if (!EFI_ERROR (Status)) { + *RndisHandle =3D HandleBuffer[Index]; + *CdcUsbIo =3D UsbIo; + FreePool (HandleBuffer); + return Status; + } + } + } // End of For loop + + FreePool (HandleBuffer); + + return EFI_NOT_FOUND; +} + +/** + USB Rndis Driver Binding Support. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to test. + @param[in] RemainingDevicePath Optional parameter use to pick a spe= cific child + device to start. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_ALREADY_STARTED This driver is already running on th= is device. + @retval other This driver does not support this de= vice. + +**/ +EFI_STATUS +EFIAPI +UsbRndisDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **)&UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED; + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; +} + +/** + USB RNDIS Driver Binding Start. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to bind driver to. + @param[in] RemainingDevicePath Optional parameter use to pick a spe= cific child + device to start. + + @retval EFI_SUCCESS This driver is added to ControllerHa= ndle + @retval EFI_DEVICE_ERROR This driver could not be started due= to a device error + @retval EFI_OUT_OF_RESOURCES The driver could not install success= fully due to a lack of resources. + @retval other This driver does not support this de= vice + +**/ +EFI_STATUS +EFIAPI +UsbRndisDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + USB_RNDIS_DEVICE *UsbRndisDevice; + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR Interface; + EFI_HANDLE RndisHandle; + + RndisHandle =3D ControllerHandle; + + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **)&UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **)&UsbEthPath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + // Controls come here for RNDIS and CDC. If it is CDC, check whether RND= IS is present on the same controller or not. + if (IsUsbCdcData (UsbIo)) { + DEBUG ((DEBUG_INFO, "Rndis CDCData interface found\n")); + + // Find the parent RNDIS and update the UsbIo for the CDC device + Status =3D UpdateRndisDevice ( + UsbEthPath, + &UsbRndisDevice + ); + + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Rndis Matching interface found\n")); + UsbRndisDevice->UsbCdcDataHandle =3D ControllerHandle; + UsbRndisDevice->UsbIoCdcData =3D UsbIo; + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice); + return Status; + } else { + // Check if RnDis exist + Status =3D FindMatchingRndisDev ( + ControllerHandle, + &UsbIo, + &RndisHandle + ); + + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + } + } + + UsbRndisDevice =3D AllocateZeroPool (sizeof (USB_RNDIS_DEVICE)); + + if (!UsbRndisDevice) { + DEBUG ((DEBUG_ERROR, "AllocateZeroPool Fail\n")); + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return EFI_OUT_OF_RESOURCES; + } + + Status =3D LoadAllDescriptor ( + UsbIo, + &UsbRndisDevice->Config + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:LoadAllDescriptor status =3D %r\n", __FUNCTIO= N__, Status)); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + FreePool (UsbRndisDevice); + return Status; + } + + Status =3D UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &Interface + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status =3D %r\n", _= _FUNCTION__, Status)); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + FreePool (UsbRndisDevice->Config); + FreePool (UsbRndisDevice); + return Status; + } + + UsbRndisDevice->Signature =3D USB_RNDIS_SIGNATU= RE; + UsbRndisDevice->NumOfInterface =3D Interface.Interfa= ceNumber; + UsbRndisDevice->UsbRndisHandle =3D RndisHandle; + UsbRndisDevice->UsbCdcDataHandle =3D 0; + UsbRndisDevice->UsbIo =3D UsbIo; + UsbRndisDevice->UsbEth.UsbEthReceive =3D RndisUndiReceive; + UsbRndisDevice->UsbEth.UsbEthTransmit =3D RndisUndiTransmit= ; + UsbRndisDevice->UsbEth.UsbEthInterrupt =3D UsbRndisInterrupt= ; + UsbRndisDevice->UsbEth.UsbEthMacAddress =3D GetUsbEthMacAddre= ss; + UsbRndisDevice->UsbEth.UsbEthMaxBulkSize =3D UsbEthBulkSize; + UsbRndisDevice->UsbEth.UsbHeaderFunDescriptor =3D GetUsbHeaderFunDe= scriptor; + UsbRndisDevice->UsbEth.UsbUnionFunDescriptor =3D GetUsbUnionFunDes= criptor; + UsbRndisDevice->UsbEth.UsbEthFunDescriptor =3D GetUsbRndisFunDes= criptor; + UsbRndisDevice->UsbEth.SetUsbEthMcastFilter =3D SetUsbRndisMcastF= ilter; + UsbRndisDevice->UsbEth.SetUsbEthPowerPatternFilter =3D SetUsbRndisPowerF= ilter; + UsbRndisDevice->UsbEth.GetUsbEthPowerPatternFilter =3D GetUsbRndisPowerF= ilter; + UsbRndisDevice->UsbEth.SetUsbEthPacketFilter =3D SetUsbRndisPacket= Filter; + UsbRndisDevice->UsbEth.GetUsbEthStatistic =3D GetRndisStatistic= ; + + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetState =3D RndisDum= myReturn; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStart =3D RndisUnd= iStart; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStop =3D RndisUnd= iStop; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetInitInfo =3D RndisUnd= iGetInitInfo; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetConfigInfo =3D RndisUnd= iGetConfigInfo; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInitialize =3D RndisUnd= iInitialize; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReset =3D RndisUnd= iReset; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiShutdown =3D RndisUnd= iShutdown; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInterruptEnable =3D RndisDum= myReturn; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceiveFilter =3D RndisUnd= iReceiveFilter; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStationAddress =3D RndisDum= myReturn; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStatistics =3D NULL; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiMcastIp2Mac =3D RndisDum= myReturn; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiNvData =3D RndisDum= myReturn; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetStatus =3D RndisUnd= iGetStatus; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiFillHeader =3D RndisDum= myReturn; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiTransmit =3D NULL; + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceive =3D NULL; + + UsbRndisDevice->MaxTransferSize =3D RNDIS_MAX_TRANSFER_SIZE; + UsbRndisDevice->MaxPacketsPerTransfer =3D 1; + UsbRndisDevice->PacketAlignmentFactor =3D 0; + + InitializeListHead (&UsbRndisDevice->ReceivePacketList); + + // This is a RNDIS interface. See whether CDC-DATA interface has already= been connected or not + FindMatchingCdcData (UsbRndisDevice); + + if (UsbRndisDevice->UsbIoCdcData) { + Status =3D gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + EFI_NATIVE_INTERFACE, + &(UsbRndisDevice->UsbEth) + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + FreePool (UsbRndisDevice->Config); + FreePool (UsbRndisDevice); + return Status; + } + + GetEndpoint (UsbRndisDevice->UsbIo, UsbRndisDevice); + + DEBUG ((DEBUG_INFO, "Rndis DeviceHandle %r\n", UsbRndisDevice->UsbRndi= sHandle)); + DEBUG ((DEBUG_INFO, "CDC DeviceHandle %r\n", UsbRndisDevice->UsbCdcDat= aHandle)); + return EFI_SUCCESS; + } + + FreePool (UsbRndisDevice->Config); + FreePool (UsbRndisDevice); + + return EFI_SUCCESS; +} + +/** + CheckandStopRndisDevice + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to bind driver to. + + @retval EFI_SUCCESS This driver is added to ControllerHandle + @retval EFI_DEVICE_ERROR This driver could not be started due to a d= evice error + @retval other This driver does not support this device + +**/ +EFI_STATUS +EFIAPI +CheckandStopRndisDevice ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle + ) +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **)&UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsUsbRndis (UsbIo)) { + Status =3D gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + DEBUG ((DEBUG_ERROR, "Rndis ControllerHandle Stop %r\n", Status)); + return Status; + } + + return EFI_UNSUPPORTED; +} + +/** + USB Rndis Driver Binding Stop. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop driver on + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer= . If number of + children is zero stop the entire bus d= river. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandl= e + @retval other This driver was not removed from this = device + +**/ +EFI_STATUS +EFIAPI +UsbRndisDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol; + USB_RNDIS_DEVICE *UsbRndisDevice; + + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop ControllerHandle %lx\n", Control= lerHandle)); + + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + (VOID **)&UsbEthProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + Status =3D CheckandStopRndisDevice (This, ControllerHandle); + return Status; + } + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (UsbEthProtocol); + + Status =3D gBS->CloseProtocol ( + UsbRndisDevice->UsbCdcDataHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + UsbRndisDevice->UsbCdcDataHandle + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:CloseProtocol status =3D %r\n", __FUNCTION__,= Status)); + } + + Status =3D gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEdkIIUsbEthProtocolGuid, + UsbEthProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + FreePool (UsbRndisDevice->Config); + FreePool (UsbRndisDevice); + + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop %r\n", Status)); + return Status; +} + +/** + Entrypoint of RNDIS Driver. + + This function is the entrypoint of RNDIS Driver. It installs Driver Bind= ing + Protocols together with Component Name Protocols. + + @param[in] ImageHandle The firmware allocated handle for the EFI = image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +UsbRndisEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + gUsbRndisDriverBinding.DriverBindingHandle =3D ImageHandle; + gUsbRndisDriverBinding.ImageHandle =3D ImageHandle; + + return gBS->InstallMultipleProtocolInterfaces ( + &gUsbRndisDriverBinding.DriverBindingHandle, + &gEfiDriverBindingProtocolGuid, + &gUsbRndisDriverBinding, + &gEfiComponentName2ProtocolGuid, + &gUsbRndisComponentName2, + NULL + ); +} diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.h b/UsbNetworkPkg/UsbRndis/Usb= Rndis.h new file mode 100644 index 0000000000..7758070424 --- /dev/null +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.h @@ -0,0 +1,586 @@ +/** @file + Header file for for USB Rndis driver + + Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _USB_RNDIS_H_ +#define _USB_RNDIS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct _REMOTE_NDIS_MSG_HEADER REMOTE_NDIS_MSG_HEADER; + +typedef struct { + UINT32 Signature; + EDKII_USB_ETHERNET_PROTOCOL UsbEth; + EFI_HANDLE UsbCdcDataHandle; + EFI_HANDLE UsbRndisHandle; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_IO_PROTOCOL *UsbIoCdcData; + EFI_USB_CONFIG_DESCRIPTOR *Config; + UINT8 NumOfInterface; + UINT8 BulkInEndpoint; + UINT8 BulkOutEndpoint; + UINT8 InterrupEndpoint; + EFI_MAC_ADDRESS MacAddress; + UINT32 RequestId; + UINT32 Medium; + UINT32 MaxPacketsPerTransfer; + UINT32 MaxTransferSize; + UINT32 PacketAlignmentFactor; + LIST_ENTRY ReceivePacketList; +} USB_RNDIS_DEVICE; + +#define USB_RNDIS_DRIVER_VERSION 1 +#define USB_TX_ETHERNET_BULK_TIMEOUT 3000 +#define USB_RX_ETHERNET_BULK_TIMEOUT 3 +#define USB_ETHERNET_TRANSFER_TIMEOUT 200 + +#define LAN_BULKIN_CMD_CONTROL 1 +#define MAXIMUM_STOPBULKIN_CNT 300 // Indicating maximum count= s for waiting bulk in command +#define MINIMUM_STOPBULKIN_CNT 3 // Indicating minimum count= s for waiting bulk in command +#define BULKIN_CMD_POLLING_CNT 300 // Indicating the waiting c= ounts for send bulk in command when system pending +#define RNDIS_RESERVED_BYTE_LENGTH 8 + +#define USB_RNDIS_SIGNATURE SIGNATURE_32('r', 'n', 'd', 's') +#define USB_RNDIS_DEVICE_FROM_THIS(a) CR (a, USB_RNDIS_DEVICE, UsbEth, US= B_RNDIS_SIGNATURE) + +extern EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2; + +struct BIT_MAP { + unsigned int Src; + unsigned int Dst; +}; + +EFI_STATUS +EFIAPI +UsbRndisDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +UsbRndisDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +UsbRndisDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +EFI_STATUS +LoadAllDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc + ); + +BOOLEAN +NextDescriptor ( + IN EFI_USB_CONFIG_DESCRIPTOR *Desc, + IN OUT UINTN *Offset + ); + +EFI_STATUS +GetFunctionalDescriptor ( + IN EFI_USB_CONFIG_DESCRIPTOR *Config, + IN UINT8 FunDescriptorType, + OUT VOID *DataBuffer + ); + +VOID +GetEndpoint ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice + ); + +EFI_STATUS +EFIAPI +UsbRndisInterrupt ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN BOOLEAN IsNewTransfer, + IN UINTN PollingInterval, + IN EFI_USB_DEVICE_REQUEST *Requst + ); + +EFI_STATUS +EFIAPI +InterruptCallback ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Status + ); + +EFI_STATUS +EFIAPI +GetUsbEthMacAddress ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT EFI_MAC_ADDRESS *MacAddress + ); + +EFI_STATUS +EFIAPI +UsbEthBulkSize ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT UINTN *BulkSize + ); + +EFI_STATUS +EFIAPI +RndisDummyReturn ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +EFI_STATUS +EFIAPI +RndisUndiStart ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +EFI_STATUS +EFIAPI +RndisUndiStop ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +EFI_STATUS +EFIAPI +RndisUndiGetInitInfo ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +EFI_STATUS +EFIAPI +RndisUndiGetConfigInfo ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +EFI_STATUS +EFIAPI +RndisUndiInitialize ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +EFI_STATUS +EFIAPI +RndisUndiTransmit ( + IN PXE_CDB *Cdb, + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN VOID *BulkOutData, + IN OUT UINTN *DataLength + ); + +EFI_STATUS +EFIAPI +RndisUndiReceive ( + IN PXE_CDB *Cdb, + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN OUT VOID *BulkInData, + IN OUT UINTN *DataLength + ); + +EFI_STATUS +EFIAPI +RndisUndiReset ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +EFI_STATUS +EFIAPI +RndisUndiShutdown ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +EFI_STATUS +EFIAPI +RndisUndiReceiveFilter ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +EFI_STATUS +EFIAPI +RndisUndiGetStatus ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ); + +EFI_STATUS +EFIAPI +GetUsbHeaderFunDescriptor ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor + ); + +EFI_STATUS +EFIAPI +GetUsbUnionFunDescriptor ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor + ); + +EFI_STATUS +EFIAPI +GetUsbRndisFunDescriptor ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor + ); + +EFI_STATUS +EFIAPI +SetUsbRndisMcastFilter ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value, + IN VOID *McastAddr + ); + +EFI_STATUS +EFIAPI +SetUsbRndisPowerFilter ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value, + IN UINT16 Length, + IN VOID *PatternFilter + ); + +EFI_STATUS +EFIAPI +GetUsbRndisPowerFilter ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value, + IN BOOLEAN *PatternActive + ); + +EFI_STATUS +EFIAPI +SetUsbRndisPacketFilter ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value + ); + +EFI_STATUS +EFIAPI +GetRndisStatistic ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value, + IN VOID *Statistic + ); + +EFI_STATUS +RndisControlMsg ( + IN USB_RNDIS_DEVICE *UsbRndisDevice, + IN REMOTE_NDIS_MSG_HEADER *RndisMsg, + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse + ); + +EFI_STATUS +RndisTransmitDataMsg ( + IN USB_RNDIS_DEVICE *UsbRndisDevice, + IN REMOTE_NDIS_MSG_HEADER *RndisMsg, + UINTN *TransferLength + ); + +EFI_STATUS +RndisReceiveDataMsg ( + IN USB_RNDIS_DEVICE *UsbRndisDevice, + IN REMOTE_NDIS_MSG_HEADER *RndisMsg, + UINTN *TransferLength + ); + +VOID +PrintRndisMsg ( + IN REMOTE_NDIS_MSG_HEADER *RndisMsg + ); + +#define RNDIS_MAJOR_VERSION 0x00000001 +#define RNDIS_MINOR_VERSION 0x00000000 +#define RNDIS_MAX_TRANSFER_SIZE 0x4000 + +#define RNDIS_PACKET_MSG 0x00000001 +#define RNDIS_INITIALIZE_MSG 0x00000002 +#define RNDIS_INITIALIZE_CMPLT 0x80000002 +#define RNDIS_HLT_MSG 0x00000003 +#define RNDIS_QUERY_MSG 0x00000004 +#define RNDIS_QUERY_CMPLT 0x80000004 +#define RNDIS_SET_MSG 0x00000005 +#define RNDIS_SET_CMPLT 0x80000005 +#define RNDIS_RESET_MSG 0x00000006 +#define RNDIS_RESET_CMPLT 0x80000006 +#define RNDIS_INDICATE_STATUS_MSG 0x00000007 +#define RNDIS_KEEPALIVE_MSG 0x00000008 +#define RNDIS_KEEPALIVE_CMPLT 0x80000008 + +#define RNDIS_STATUS_SUCCESS 0x00000000 +#define RNDIS_STATUS_FAILURE 0xC0000001 +#define RNDIS_STATUS_INVALID_DATA 0xC0010015 +#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BB +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000B +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000C + +#define RNDIS_CONTROL_TIMEOUT 10000 // 10sec +#define RNDIS_KEEPALIVE_TIMEOUT 5000 // 5sec + +#define SEND_ENCAPSULATED_COMMAND 0x00000000 +#define GET_ENCAPSULATED_RESPONSE 0x00000001 + +// +// General Objects +// +// Taken from NTDDNDIS.H +#define OID_GEN_SUPPORTED_LIST 0x00010101 +#define OID_GEN_HARDWARE_STATUS 0x00010102 +#define OID_GEN_MEDIA_SUPPORTED 0x00010103 +#define OID_GEN_MEDIA_IN_USE 0x00010104 +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 +#define OID_GEN_LINK_SPEED 0x00010107 +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B +#define OID_GEN_VENDOR_ID 0x0001010C +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F +#define OID_GEN_DRIVER_VERSION 0x00010110 +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 +#define OID_GEN_MAC_OPTIONS 0x00010113 +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 + +#define OID_GEN_XMIT_OK 0x00020101 +#define OID_GEN_RCV_OK 0x00020102 +#define OID_GEN_XMIT_ERROR 0x00020103 +#define OID_GEN_RCV_ERROR 0x00020104 +#define OID_GEN_RCV_NO_BUFFER 0x00020105 + +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C +#define OID_GEN_RCV_CRC_ERROR 0x0002020D +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E + +#define OID_802_3_CURRENT_ADDRESS 0x01010102 +// +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER). +// +#define NDIS_PACKET_TYPE_DIRECTED 0x0001 +#define NDIS_PACKET_TYPE_MULTICAST 0x0002 +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004 +#define NDIS_PACKET_TYPE_BROADCAST 0x0008 +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010 +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020 +#define NDIS_PACKET_TYPE_SMT 0x0040 +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080 +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000 +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000 +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000 +#define NDIS_PACKET_TYPE_GROUP 0x1000 + +#pragma pack(1) + +typedef struct _REMOTE_NDIS_MSG_HEADER { + UINT32 MessageType; + UINT32 MessageLength; +} REMOTE_NDIS_MSG_HEADER; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 RequestID; + UINT32 MajorVersion; + UINT32 MinorVersion; + UINT32 MaxTransferSize; +} REMOTE_NDIS_INITIALIZE_MSG; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 RequestID; +} REMOTE_NDIS_HALT_MSG; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 RequestID; + UINT32 Oid; + UINT32 InformationBufferLength; + UINT32 InformationBufferOffset; + UINT32 Reserved; +} REMOTE_NDIS_QUERY_MSG; + +typedef struct { + REMOTE_NDIS_QUERY_MSG QueryMsg; + UINT8 Addr[6]; +} REMOTE_NDIS_QUERY_MAC_MSG; + +typedef struct { + REMOTE_NDIS_QUERY_MSG QueryMsg; + UINT32 MaxTotalSize; +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 RequestID; + UINT32 Oid; + UINT32 InformationBufferLength; + UINT32 InformationBufferOffset; + UINT32 Reserved; +} REMOTE_NDIS_SET_MSG; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 Reserved; +} REMOTE_NDIS_RESET_MSG; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 Status; + UINT32 StatusBufferLength; + UINT32 StatusBufferOffset; +} REMOTE_NDIS_INDICATE_STATUS_MSG; + +typedef struct { + UINT32 DiagStatus; + UINT32 ErrorOffset; +} RNDIS_DIAGNOSTIC_INFO; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 RequestID; +} REMOTE_NDIS_KEEPALIVE_MSG; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 RequestID; + UINT32 Status; + UINT32 MajorVersion; + UINT32 MinorVersion; + UINT32 DeviceFlags; + UINT32 Medium; + UINT32 MaxPacketsPerTransfer; + UINT32 MaxTransferSize; + UINT32 PacketAlignmentFactor; + UINT64 Reserved; +} REMOTE_NDIS_INITIALIZE_CMPLT; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 RequestID; + UINT32 Status; + UINT32 InformationBufferLength; + UINT32 InformationBufferOffset; +} REMOTE_NDIS_QUERY_CMPLT; + +typedef struct { + REMOTE_NDIS_QUERY_CMPLT QueryCmplt; + UINT8 Addr[6]; +} REMOTE_NDIS_QUERY_MAC_CMPLT; + +typedef struct { + REMOTE_NDIS_QUERY_CMPLT QueryCmplt; + UINT32 MaxTotalSize; +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 RequestID; + UINT32 Status; +} REMOTE_NDIS_SET_CMPLT; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 Status; + UINT32 AddressingReset; +} REMOTE_NDIS_RESET_CMPLT; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 RequestID; + UINT32 Status; +} REMOTE_NDIS_KEEPALIVE_CMPLT; + +typedef struct { + UINT32 MessageType; + UINT32 MessageLength; + UINT32 DataOffset; + UINT32 DataLength; + UINT32 OutOfBandDataOffset; + UINT32 OutOfBandDataLength; + UINT32 NumOutOfBandDataElements; + UINT32 PerPacketInfoOffset; + UINT32 PerPacketInfoLength; + UINT32 Reserved1; + UINT32 Reserved2; +} REMOTE_NDIS_PACKET_MSG; + +typedef struct { + UINT32 Size; + UINT32 Type; + UINT32 ClassInformationOffset; +} OUT_OF_BAND_DATA_RECORD; + +typedef struct { + UINT32 Size; + UINT32 Type; + UINT32 ClassInformationOffset; +} PER_PACKET_INFO_DATA_RECORD; + +typedef struct { + LIST_ENTRY PacketList; + UINT8 *OrgBuffer; + UINTN RemainingLength; + UINT8 *PacketStartBuffer; // Variable size data to follow +} PACKET_LIST; + +#pragma pack() + +#endif diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.inf b/UsbNetworkPkg/UsbRndis/U= sbRndis.inf new file mode 100644 index 0000000000..64205e4277 --- /dev/null +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.inf @@ -0,0 +1,42 @@ +## @file +# This is Usb Rndis driver for DXE phase. +# +# Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D UsbRndis + FILE_GUID =3D 11E32C34-60B5-4991-8DEA-63D3E8C876DE + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D UsbRndisEntry + +[Sources] + UsbRndis.c + UsbRndis.h + UsbRndisFunction.c + ComponentName.c + +[Packages] + MdePkg/MdePkg.dec + UsbNetworkPkg/UsbNetworkPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiLib + DebugLib + UefiUsbLib + MemoryAllocationLib + BaseMemoryLib + +[Protocols] + gEfiUsbIoProtocolGuid + gEfiDevicePathProtocolGuid + gEfiDriverBindingProtocolGuid + gEdkIIUsbEthProtocolGuid + +[Depex] + TRUE diff --git a/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c b/UsbNetworkPkg/UsbR= ndis/UsbRndisFunction.c new file mode 100644 index 0000000000..e3fe737cde --- /dev/null +++ b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c @@ -0,0 +1,1718 @@ +/** @file + This file contains code for USB Ethernet descriptor + and specific requests implement. + + Copyright (c) 2023, American Megatrends International LLC. All rights re= served.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "UsbRndis.h" + +UINT16 gStopBulkInCnt =3D 0; +UINT16 gBlockBulkInCnt =3D 0; + +/** + Load All of device descriptor. + + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL i= nstance. + @param[out] ConfigDesc A pointer to the configuration descrip= tor. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_OUT_OF_RESOURCES The request could not be completed because= the + buffer specified by DescriptorLength and D= escriptor + is not large enough to hold the result of = the request. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. = The transfer + status is returned in Status. +**/ +EFI_STATUS +LoadAllDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc + ) +{ + EFI_STATUS Status; + UINT32 TransStatus; + EFI_USB_CONFIG_DESCRIPTOR Tmp; + + Status =3D UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:UsbGetConfigDescriptor status =3D %r\n", __FU= NCTION__, Status)); + return Status; + } + + Status =3D gBS->AllocatePool ( + EfiBootServicesData, + Tmp.TotalLength, + (VOID **)ConfigDesc + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: AllocatePool status =3D %r\n", __FUNCTION__,= Status)); + return Status; + } + + Status =3D UsbGetDescriptor ( + UsbIo, + USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1), = // zero based + 0, + Tmp.TotalLength, + *ConfigDesc, + &TransStatus + ); + return Status; +} + +/** + Returns pointer to the next descriptor for the pack of USB descriptors + located in continues memory segment + + @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance. + @param[in, out] Offset A pointer to the sum of descriptor length. + + @retval TRUE The request executed successfully. + @retval FALSE No next descriptor. + +**/ +BOOLEAN +NextDescriptor ( + IN EFI_USB_CONFIG_DESCRIPTOR *Desc, + IN OUT UINTN *Offset + ) +{ + if ((Desc =3D=3D NULL) || (*Offset >=3D Desc->TotalLength)) { + return FALSE; + } + + if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length =3D=3D= 0) { + return FALSE; + } + + *Offset +=3D ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Leng= th; + if ( *Offset >=3D Desc->TotalLength ) { + return FALSE; + } + + return TRUE; +} + +/** + Read Function descriptor + + @param[in] Config A pointer to all of configuration. + @param[in] FunDescriptorType USB CDC class descriptor SubType. + @param[out] DataBuffer A pointer to the Data of corresponding to= device capability. + + @retval EFI_SUCCESS The device capability descriptor was retrieve= d + successfully. + @retval EFI_UNSUPPORTED No supported. + @retval EFI_NOT_FOUND The device capability descriptor was not foun= d. + +**/ +EFI_STATUS +GetFunctionalDescriptor ( + IN EFI_USB_CONFIG_DESCRIPTOR *Config, + IN UINT8 FunDescriptorType, + OUT VOID *DataBuffer + ) +{ + EFI_STATUS Status; + UINTN Offset; + EFI_USB_INTERFACE_DESCRIPTOR *Interface; + + Status =3D EFI_NOT_FOUND; + + for (Offset =3D 0; NextDescriptor (Config, &Offset);) { + Interface =3D (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config + Offse= t); + if (Interface->DescriptorType =3D=3D CS_INTERFACE) { + if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype =3D= =3D FunDescriptorType) { + switch (FunDescriptorType) { + case HEADER_FUN_DESCRIPTOR: + CopyMem ( + DataBuffer, + (USB_HEADER_FUN_DESCRIPTOR *)Interface, + sizeof (USB_HEADER_FUN_DESCRIPTOR) + ); + return EFI_SUCCESS; + case UNION_FUN_DESCRIPTOR: + CopyMem ( + DataBuffer, + (USB_UNION_FUN_DESCRIPTOR *)Interface, + ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength + ); + return EFI_SUCCESS; + case ETHERNET_FUN_DESCRIPTOR: + CopyMem ( + DataBuffer, + (USB_ETHERNET_FUN_DESCRIPTOR *)Interface, + sizeof (USB_ETHERNET_FUN_DESCRIPTOR) + ); + return EFI_SUCCESS; + default: + Status =3D EFI_UNSUPPORTED; + break; + } + } + } + } + + return Status; +} + +/** + Get USB Ethernet IO endpoint and USB CDC data IO endpoint. + + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL ins= tance. + @param[in, out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instan= ce. + +**/ +VOID +GetEndpoint ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice + ) +{ + EFI_STATUS Status; + UINT8 Index; + UINT32 Result; + EFI_USB_INTERFACE_DESCRIPTOR Interface; + EFI_USB_ENDPOINT_DESCRIPTOR Endpoint; + + Status =3D UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status =3D %r\n", _= _FUNCTION__, Status)); + return; + } + + if (Interface.NumEndpoints =3D=3D 0 ) { + Status =3D UsbSetInterface (UsbIo, 1, 0, &Result); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status =3D %r\n", __FUNCTIO= N__, Status)); + return; + } + + Status =3D UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status =3D %r\n",= __FUNCTION__, Status)); + return; + } + } + + for (Index =3D 0; Index < Interface.NumEndpoints; Index++) { + Status =3D UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:UsbGetEndpointDescriptor status =3D %r\n", = __FUNCTION__, Status)); + return; + } + + switch ((Endpoint.Attributes & (BIT0 | BIT1))) { + case USB_ENDPOINT_BULK: + if (Endpoint.EndpointAddress & BIT7) { + UsbRndisDevice->BulkInEndpoint =3D Endpoint.EndpointAddress; + } else { + UsbRndisDevice->BulkOutEndpoint =3D Endpoint.EndpointAddress; + } + + break; + case USB_ENDPOINT_INTERRUPT: + UsbRndisDevice->InterrupEndpoint =3D Endpoint.EndpointAddress; + break; + } + } +} + +/** + Async USB transfer callback routine. + + @param[in] Data Data received or sent via the USB Asynchrono= us Transfer, if the + transfer completed successfully. + @param[in] DataLength The length of Data received or sent via the = Asynchronous + Transfer, if transfer successfully completes= . + @param[in] Context Data passed from UsbAsyncInterruptTransfer()= request. + @param[in] Status Indicates the result of the asynchronous tra= nsfer. + + @retval EFI_SUCCESS The asynchronous USB transfer request has = been successfully executed. + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request fail= ed. + +**/ +EFI_STATUS +EFIAPI +InterruptCallback ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Status + ) +{ + if ((Data =3D=3D NULL) || (Context =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (((EFI_USB_DEVICE_REQUEST *)Data)->Request =3D=3D 0) { + CopyMem ( + (EFI_USB_DEVICE_REQUEST *)Context, + (EFI_USB_DEVICE_REQUEST *)Data, + sizeof (EFI_USB_DEVICE_REQUEST) + ); + } + + return EFI_SUCCESS; +} + +/** + This function is used to manage a USB device with an interrupt transfer = pipe. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOC= OL instance. + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted = to USB controller. If + FALSE, the interrupt transfer is deleted f= rom the device's interrupt + transfer queue. + @param[in] PollingInterval Indicates the periodic rate, in millisecon= ds, that the transfer is to be + executed.This parameter is required when I= sNewTransfer is TRUE. The + value must be between 1 to 255, otherwise = EFI_INVALID_PARAMETER is returned. + The units are in milliseconds. + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST da= ta. + + @retval EFI_SUCCESS The asynchronous USB transfer request tran= sfer has been successfully executed. + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request fail= ed. + +**/ +EFI_STATUS +EFIAPI +UsbRndisInterrupt ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN BOOLEAN IsNewTransfer, + IN UINTN PollingInterval, + IN EFI_USB_DEVICE_REQUEST *Requst + ) +{ + EFI_STATUS Status; + USB_RNDIS_DEVICE *UsbRndisDevice; + UINTN DataLength; + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (This); + DataLength =3D 0; + + if (IsNewTransfer =3D=3D TRUE) { + DataLength =3D sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_S= PEED_CHANGE); + Status =3D UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer ( + UsbRndisDevice->UsbIo, + UsbRndisDevice->InterrupEndpoint= , + IsNewTransfer, + PollingInterval, + DataLength, + InterruptCallback, + Requst + ); + + if (Status =3D=3D EFI_INVALID_PARAMETER) { + // Because of Stacked AsyncInterrupt request are not supported + Status =3D UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer ( + UsbRndisDevice->UsbIo, + UsbRndisDevice->InterrupEndpoint, + 0, + 0, + 0, + NULL, + NULL + ); + } + } else { + Status =3D UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer ( + UsbRndisDevice->UsbIo, + UsbRndisDevice->InterrupEndpoint, + IsNewTransfer, + 0, + 0, + NULL, + NULL + ); + } + + return Status; +} + +/** + This function is used to read USB interrupt transfer before the response= RNDIS message. + + @param[in] This A pointer to the USB_RNDIS_DEVICE instance= . + + @retval EFI_SUCCESS The USB interrupt transfer has been succes= sfully executed. + @retval EFI_DEVICE_ERROR The USB interrupt transfer failed. + +**/ +EFI_STATUS +EFIAPI +ReadRndisResponseInterrupt ( + IN USB_RNDIS_DEVICE *UsbRndisDevice + ) +{ + EFI_STATUS Status; + UINT32 Data[2]; + UINT32 UsbStatus; + UINTN DataLength; + + DataLength =3D 8; + + ZeroMem (Data, sizeof (Data)); + + Status =3D UsbRndisDevice->UsbIo->UsbSyncInterruptTransfer ( + UsbRndisDevice->UsbIo, + UsbRndisDevice->InterrupEndpoint, + &Data, + &DataLength, + 0x20, + &UsbStatus + ); + + return Status; +} + +/** + Retrieves the USB Ethernet Mac Address. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL i= nstance. + @param[out] MacAddress A pointer to the caller allocated USB Ethernet= Mac Address. + + @retval EFI_SUCCESS The USB Header Functional descriptor was r= etrieved successfully. + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL. + @retval EFI_NOT_FOUND The USB Header Functional descriptor was n= ot found. + +**/ +EFI_STATUS +EFIAPI +GetUsbEthMacAddress ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT EFI_MAC_ADDRESS *MacAddress + ) +{ + EFI_STATUS Status; + USB_RNDIS_DEVICE *UsbRndisDevice; + USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor; + CHAR16 *Data; + CHAR16 *DataPtr; + CHAR16 TmpStr[1]; + UINT8 Index; + UINT8 Hi; + UINT8 Low; + + REMOTE_NDIS_QUERY_MAC_MSG RndisQueryMsg; + REMOTE_NDIS_QUERY_MAC_CMPLT RndisQueryMsgCmplt; + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (This); + + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAC_MSG)); + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT)); + + RndisQueryMsg.QueryMsg.MessageType =3D RNDIS_QUERY_MSG; + RndisQueryMsg.QueryMsg.MessageLength =3D sizeof (REMOTE_NDIS_QUERY_MAC_M= SG); + RndisQueryMsg.QueryMsg.RequestID =3D UsbRndisDevice->RequestId; + RndisQueryMsg.QueryMsg.Oid =3D OID_802_3_CURRENT_ADDRESS; + + RndisQueryMsgCmplt.QueryCmplt.MessageType =3D RNDIS_QUERY_CMPLT; + RndisQueryMsgCmplt.QueryCmplt.MessageLength =3D sizeof (REMOTE_NDIS_QUER= Y_MAC_CMPLT); + + Status =3D RndisControlMsg ( + UsbRndisDevice, + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg, + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt + ); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Success to get Mac address from RNDIS message.\n"= )); + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + MacAddress->Addr[Index] =3D RndisQueryMsgCmplt.Addr[Index]; + } + + UsbRndisDevice->RequestId++; + return Status; + } + + // If it is not support the OID_802_3_CURRENT_ADDRESS. + // To check USB Ethernet functional Descriptor + Status =3D This->UsbEthFunDescriptor (This, &UsbEthDescriptor); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status =3D %r\n", __FUNCT= ION__, Status)); + return Status; + } + + Status =3D UsbRndisDevice->UsbIo->UsbGetStringDescriptor ( + UsbRndisDevice->UsbIo, + 0x409, // Englis= h-US Language ID + UsbEthDescriptor.MacAddress, + &Data + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status =3D %r\n", __FU= NCTION__, Status)); + return Status; + } + + DataPtr =3D Data; + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { + CopyMem (TmpStr, DataPtr, sizeof (CHAR16)); + DataPtr++; + Hi =3D (UINT8)StrHexToUintn (TmpStr); + CopyMem (TmpStr, DataPtr, sizeof (CHAR16)); + DataPtr++; + Low =3D (UINT8)StrHexToUintn (TmpStr); + MacAddress->Addr[Index] =3D (Hi << 4) | Low; + } + + return Status; +} + +/** + Retrieves the USB Ethernet Bulk transfer data size. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL i= nstance. + @param[out] BulkSize A pointer to the Bulk transfer data size. + + @retval EFI_SUCCESS The bulk transfer data size was retrieved succ= essfully. + @retval other Failed to retrieve the bulk transfer data size= . + +**/ +EFI_STATUS +EFIAPI +UsbEthBulkSize ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT UINTN *BulkSize + ) +{ + EFI_STATUS Status; + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor; + USB_RNDIS_DEVICE *UsbRndisDevice; + + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG RndisQueryMsg; + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT RndisQueryMsgCmplt; + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (This); + + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG)); + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_C= MPLT)); + + RndisQueryMsg.QueryMsg.MessageType =3D RNDIS_QUERY_MSG; + RndisQueryMsg.QueryMsg.MessageLength =3D sizeof (REMOTE_NDIS_QUERY_MAX_T= OTAL_SIZE_MSG); + RndisQueryMsg.QueryMsg.RequestID =3D UsbRndisDevice->RequestId; + RndisQueryMsg.QueryMsg.Oid =3D OID_GEN_MAXIMUM_TOTAL_SIZE; + + RndisQueryMsgCmplt.QueryCmplt.MessageType =3D RNDIS_QUERY_CMPLT; + RndisQueryMsgCmplt.QueryCmplt.MessageLength =3D sizeof (REMOTE_NDIS_QUER= Y_MAX_TOTAL_SIZE_CMPLT); + + Status =3D RndisControlMsg ( + UsbRndisDevice, + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg, + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt + ); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Success to get Max Total size : %X \n", RndisQue= ryMsgCmplt.MaxTotalSize)); + *BulkSize =3D RndisQueryMsgCmplt.MaxTotalSize; + UsbRndisDevice->RequestId++; + return Status; + } + + Status =3D This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor); + if (EFI_ERROR (Status)) { + return Status; + } + + *BulkSize =3D (UINTN)UsbEthFunDescriptor.MaxSegmentSize; + return Status; +} + +/** + Retrieves the USB Header functional Descriptor. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_P= ROTOCOL instance. + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB= Header Functional Descriptor. + + @retval EFI_SUCCESS The USB Header Functional descriptor was r= etrieved successfully. + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL. + @retval EFI_NOT_FOUND The USB Header Functional descriptor was n= ot found. + +**/ +EFI_STATUS +EFIAPI +GetUsbHeaderFunDescriptor ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor + ) +{ + EFI_STATUS Status; + USB_RNDIS_DEVICE *UsbRndisDevice; + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (This); + + if (UsbHeaderFunDescriptor =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Status =3D GetFunctionalDescriptor ( + UsbRndisDevice->Config, + HEADER_FUN_DESCRIPTOR, + UsbHeaderFunDescriptor + ); + return Status; +} + +/** + Retrieves the USB Union functional Descriptor. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_P= ROTOCOL instance. + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB= Union Functional Descriptor. + + @retval EFI_SUCCESS The USB Union Functional descriptor was r= etrieved successfully. + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL. + @retval EFI_NOT_FOUND The USB Union Functional descriptor was n= ot found. + +**/ +EFI_STATUS +EFIAPI +GetUsbUnionFunDescriptor ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor + ) +{ + EFI_STATUS Status; + USB_RNDIS_DEVICE *UsbRndisDevice; + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (This); + + if (UsbUnionFunDescriptor =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Status =3D GetFunctionalDescriptor ( + UsbRndisDevice->Config, + UNION_FUN_DESCRIPTOR, + UsbUnionFunDescriptor + ); + return Status; +} + +/** + Retrieves the USB Ethernet functional Descriptor. + + This function get the Mac Address, Ethernet statistics, maximum segment = size, + number of multicast filters, and number of pattern filters from Ethernet + functional Descriptor. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_P= ROTOCOL instance. + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB= Ethernet Functional Descriptor. + + @retval EFI_SUCCESS The USB Ethernet Functional descriptor wa= s retrieved successfully. + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL. + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor wa= s not found. + +**/ +EFI_STATUS +EFIAPI +GetUsbRndisFunDescriptor ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor + ) +{ + EFI_STATUS Status; + USB_RNDIS_DEVICE *UsbRndisDevice; + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (This); + + if (UsbEthFunDescriptor =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Status =3D GetFunctionalDescriptor ( + UsbRndisDevice->Config, + ETHERNET_FUN_DESCRIPTOR, + UsbEthFunDescriptor + ); + return Status; +} + +/** + This request sets the Ethernet device multicast filters as specified in = the + sequential list of 48 bit Ethernet multicast addresses. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_P= ROTOCOL instance. + @param[in] Value Number of filters. + @param[in] McastAddr A pointer to the value of the multica= st addresses. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid valu= e. + @retval EFI_UNSUPPORTED Not supported. + +**/ +EFI_STATUS +EFIAPI +SetUsbRndisMcastFilter ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value, + IN VOID *McastAddr + ) +{ + EFI_STATUS Status; + EFI_USB_DEVICE_REQUEST Request; + UINT32 TransStatus; + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor; + USB_RNDIS_DEVICE *UsbRndisDevice; + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (This); + + Status =3D This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((UsbEthFunDescriptor.NumberMcFilters << 1) =3D=3D 0) { + return EFI_UNSUPPORTED; + } + + Request.RequestType =3D USB_ETHERNET_SET_REQ_TYPE; + Request.Request =3D SET_ETH_MULTICAST_FILTERS_REQ; + Request.Value =3D Value; + Request.Index =3D UsbRndisDevice->NumOfInterface; + Request.Length =3D Value * 6; + + return UsbRndisDevice->UsbIo->UsbControlTransfer ( + UsbRndisDevice->UsbIo, + &Request, + EfiUsbDataOut, + USB_ETHERNET_TRANSFER_TIMEOUT, + McastAddr, + Request.Length, + &TransStatus + ); +} + +/** + This request sets up the specified Ethernet power management pattern fil= ter as + described in the data structure. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_PR= OTOCOL instance. + @param[in] Value Number of filters. + @param[in] Length Size of the power management pattern f= ilter data. + @param[in] PatternFilter A pointer to the power management patt= ern filter structure. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid valu= e. + @retval EFI_UNSUPPORTED Not supported. + +**/ +EFI_STATUS +EFIAPI +SetUsbRndisPowerFilter ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value, + IN UINT16 Length, + IN VOID *PatternFilter + ) +{ + EFI_USB_DEVICE_REQUEST Request; + UINT32 TransStatus; + USB_RNDIS_DEVICE *UsbRndisDevice; + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (This); + + Request.RequestType =3D USB_ETHERNET_SET_REQ_TYPE; + Request.Request =3D SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ; + Request.Value =3D Value; + Request.Index =3D UsbRndisDevice->NumOfInterface; + Request.Length =3D Length; + + return UsbRndisDevice->UsbIo->UsbControlTransfer ( + UsbRndisDevice->UsbIo, + &Request, + EfiUsbDataOut, + USB_ETHERNET_TRANSFER_TIMEOUT, + PatternFilter, + Length, + &TransStatus + ); +} + +/** + This request retrieves the status of the specified Ethernet power manage= ment + pattern filter from the device. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_P= ROTOCOL instance. + @param[in] Value The filter number. + @param[out] PatternActive A pointer to the pattern active boole= an. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid valu= e. + @retval EFI_UNSUPPORTED Not supported. + +**/ +EFI_STATUS +EFIAPI +GetUsbRndisPowerFilter ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value, + OUT BOOLEAN *PatternActive + ) +{ + EFI_USB_DEVICE_REQUEST Request; + UINT32 TransStatus; + USB_RNDIS_DEVICE *UsbRndisDevice; + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (This); + + Request.RequestType =3D USB_ETHERNET_GET_REQ_TYPE; + Request.Request =3D GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ; + Request.Value =3D Value; + Request.Index =3D UsbRndisDevice->NumOfInterface; + Request.Length =3D USB_ETH_POWER_FILTER_LENGTH; + + return UsbRndisDevice->UsbIo->UsbControlTransfer ( + UsbRndisDevice->UsbIo, + &Request, + EfiUsbDataIn, + USB_ETHERNET_TRANSFER_TIMEOUT, + PatternActive, + USB_ETH_POWER_FILTER_LENGTH, + &TransStatus + ); +} + +/** + + Converts PXE filter settings to RNDIS values + + @param[in] Value PXE filter data. + @param[out] CdcFilter A pointer to the Ethernet Packet Filter Bitmap va= lue converted by PXE_OPFLAGS. + +**/ +VOID +ConvertFilter ( + IN UINT16 Value, + OUT UINT16 *CdcFilter + ) +{ + UINT32 Index; + UINT32 Count; + static struct BIT_MAP Table[] =3D { + { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST, NDIS_PACKET_TYPE_DIRE= CTED }, + { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST, NDIS_PACKET_TYPE_BROA= DCAST }, + { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, NDIS_PACKET_TYPE_MULT= ICAST }, + { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS, NDIS_PACKET_TYPE_PROM= ISCUOUS }, + { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST, NDIS_PACKET_TYPE_ALL_= MULTICAST }, + }; + + Count =3D sizeof (Table)/sizeof (Table[0]); + + for (Index =3D 0; (Table[Index].Src !=3D 0) && (Index < Count); Index++)= { + if (Table[Index].Src & Value) { + *CdcFilter |=3D Table[Index].Dst; + } + } +} + +/** + + Updates Filter settings on the device. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +RndisUndiReceiveFilter ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + UINT8 *McastList; + UINT8 Count; + UINT8 Index1; + UINT8 Index2; + UINT64 CpbAddr; + UINT32 CpbSize; + UINT16 SetFilter; + PXE_CPB_RECEIVE_FILTERS *Cpb; + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor; + + Count =3D 0; + CpbAddr =3D Cdb->CPBaddr; + CpbSize =3D Cdb->CPBsize; + SetFilter =3D (UINT16)(Cdb->OpFlags & 0x1F); + Cpb =3D (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr; + + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED) + Nic->RxFilter =3D (UINT8)SetFilter; + + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) !=3D 0)= || (Cpb !=3D NULL)) { + if (Cpb !=3D NULL) { + Nic->McastCount =3D (UINT8)(CpbSize / PXE_MAC_LENGTH); + CopyMem (&Nic->McastList, Cpb, Nic->McastCount); + } else { + Nic->McastCount =3D 0; + } + + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor); + if ((UsbEthFunDescriptor.NumberMcFilters << 1) =3D=3D 0) { + Nic->RxFilter |=3D PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST; + DEBUG ((DEBUG_INFO, "SetUsbEthPacketFilter Nic %lx Nic->UsbEth %lx "= , Nic, Nic->UsbEth)); + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter); + } else { + Status =3D gBS->AllocatePool (EfiBootServicesData, Nic->McastCount *= 6, (VOID **)&McastList); + if (EFI_ERROR (Status)) { + return PXE_STATCODE_INVALID_PARAMETER; + } + + if (Cpb !=3D NULL) { + for (Index1 =3D 0; Index1 < Nic->McastCount; Index1++) { + for (Index2 =3D 0; Index2 < 6; Index2++) { + McastList[Count++] =3D Cpb->MCastList[Index1][Index2]; + } + } + } + + Nic->RxFilter |=3D PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST; + if (Cpb !=3D NULL) { + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, M= castList); + } + + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter); + FreePool (McastList); + } + } + + return EFI_SUCCESS; +} + +/** + This request is used to configure device Ethernet packet filter settings= . + + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOC= OL instance. + @param[in] Value Packet Filter Bitmap. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. + +**/ +EFI_STATUS +EFIAPI +SetUsbRndisPacketFilter ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 Value + ) +{ + return EFI_SUCCESS; +} + +/** + This request is used to retrieve a statistic based on the feature select= or. + + @param[in] This A pointer to the EDKII_USB_ETHERNET_PR= OTOCOL instance. + @param[in] FeatureSelector Value of the feature selector. + @param[out] Statistic A pointer to the 32 bit unsigned integ= er. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_TIMEOUT A timeout occurred executing the request. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value= . + @retval EFI_UNSUPPORTED Not supported. + +**/ +EFI_STATUS +EFIAPI +GetRndisStatistic ( + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN UINT16 FeatureSelector, + OUT VOID *Statistic + ) +{ + return EFI_SUCCESS; +} + +/** + This function is called when UndiStart is invoked. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + +**/ +EFI_STATUS +EFIAPI +RndisUndiStart ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "RndisUndiStart Nic %lx Cdb %lx Nic State %x\n", Nic= , Cdb, Nic->State)); + + // Issue Rndis Reset and bring the device to RNDIS_BUS_INITIALIZED state + Status =3D RndisUndiReset (Cdb, Nic); + if (EFI_ERROR (Status)) { + RndisUndiReset (Cdb, Nic); + } + + Status =3D RndisUndiInitialize (Cdb, Nic); + if (EFI_ERROR (Status)) { + RndisUndiInitialize (Cdb, Nic); + } + + RndisUndiShutdown (Cdb, Nic); + + return EFI_SUCCESS; +} + +/** + This function is called when Undistop is invoked. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. +**/ +EFI_STATUS +EFIAPI +RndisUndiStop ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + DEBUG ((DEBUG_INFO, "RndisUndiStop State %x\n", Nic->State)); + return EFI_SUCCESS; +} + +/** + This function is called when UndiGetInitInfo is invoked. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + +**/ +EFI_STATUS +EFIAPI +RndisUndiGetInitInfo ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice; + USB_RNDIS_DEVICE *UsbRndisDevice; + PXE_DB_GET_INIT_INFO *Db; + + DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n")); + + UsbEthDevice =3D Nic->UsbEth; + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice); + + Db =3D (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr; + + Db->FrameDataLen =3D UsbRndisDevice->MaxTransferSize - sizeof (REMOTE_ND= IS_PACKET_MSG) - PXE_MAC_HEADER_LEN_ETHER; + // Limit Max MTU size to 1500 bytes as RNDIS spec. + if (Db->FrameDataLen > PXE_MAX_TXRX_UNIT_ETHER) { + Db->FrameDataLen =3D PXE_MAX_TXRX_UNIT_ETHER; + } + + DEBUG ((DEBUG_INFO, "Db->FrameDataLen %x\n", Db->FrameDataLen)); + + return EFI_SUCCESS; +} + +/** + This function is called when RndisUndiGetConfigInfo is invoked. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + +**/ +EFI_STATUS +EFIAPI +RndisUndiGetConfigInfo ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + DEBUG ((DEBUG_INFO, "RndisUndiGetConfigInfo\n")); + return EFI_SUCCESS; +} + +/** + This function is called when UndiInitialize is invoked. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_UNSUPPORTED Not supported. + +**/ +EFI_STATUS +EFIAPI +RndisUndiInitialize ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver; + USB_RNDIS_DEVICE *UsbRndisDevice; + REMOTE_NDIS_INITIALIZE_MSG RndisInitMsg; + REMOTE_NDIS_INITIALIZE_CMPLT RndisInitMsgCmplt; + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n")); + + UsbEthDriver =3D Nic->UsbEth; + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver); + + ZeroMem (&RndisInitMsg, sizeof (REMOTE_NDIS_INITIALIZE_MSG)); + ZeroMem (&RndisInitMsgCmplt, sizeof (REMOTE_NDIS_INITIALIZE_CMPLT)); + + RndisInitMsg.MessageType =3D RNDIS_INITIALIZE_MSG; + RndisInitMsg.MessageLength =3D sizeof (REMOTE_NDIS_INITIALIZE_MSG); + RndisInitMsg.RequestID =3D UsbRndisDevice->RequestId; + RndisInitMsg.MajorVersion =3D RNDIS_MAJOR_VERSION; + RndisInitMsg.MinorVersion =3D RNDIS_MINOR_VERSION; + RndisInitMsg.MaxTransferSize =3D RNDIS_MAX_TRANSFER_SIZE; + + RndisInitMsgCmplt.MessageType =3D RNDIS_INITIALIZE_CMPLT; + RndisInitMsgCmplt.MessageLength =3D sizeof (REMOTE_NDIS_INITIALIZE_CMPLT= ); + + Status =3D RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&R= ndisInitMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsgCmplt); + + UsbRndisDevice->RequestId++; + + if (EFI_ERROR (Status) || (RndisInitMsgCmplt.Status & 0x80000000)) { + return Status; + } + + // Only Wired Medium is supported + if (RndisInitMsgCmplt.Medium) { + return EFI_UNSUPPORTED; + } + + UsbRndisDevice->Medium =3D RndisInitMsgCmplt.Medium; + UsbRndisDevice->MaxPacketsPerTransfer =3D RndisInitMsgCmplt.MaxPacketsPe= rTransfer; + UsbRndisDevice->MaxTransferSize =3D RndisInitMsgCmplt.MaxTransferS= ize; + UsbRndisDevice->PacketAlignmentFactor =3D RndisInitMsgCmplt.PacketAlignm= entFactor; + + DEBUG ((DEBUG_INFO, "Medium : %x \n", RndisInitMsgCmplt.Medium)); + DEBUG ((DEBUG_INFO, "MaxPacketsPerTransfer : %x \n", RndisInitMsgCmplt.M= axPacketsPerTransfer)); + DEBUG ((DEBUG_INFO, "MaxTransferSize : %x\n", RndisInitMsgCmplt.MaxTrans= ferSize)); + DEBUG ((DEBUG_INFO, "PacketAlignmentFactor : %x\n", RndisInitMsgCmplt.Pa= cketAlignmentFactor)); + + return Status; +} + +/** + This function is called when UndiReset is invoked. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_DEVICE_ERROR The request failed due to a device error. + +**/ +EFI_STATUS +EFIAPI +RndisUndiReset ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver; + USB_RNDIS_DEVICE *UsbRndisDevice; + REMOTE_NDIS_RESET_MSG RndisResetMsg; + REMOTE_NDIS_RESET_CMPLT RndisResetCmplt; + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "RndisUndiReset\n")); + + UsbEthDriver =3D Nic->UsbEth; + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver); + + ZeroMem (&RndisResetMsg, sizeof (REMOTE_NDIS_RESET_MSG)); + ZeroMem (&RndisResetCmplt, sizeof (REMOTE_NDIS_RESET_CMPLT)); + + RndisResetMsg.MessageType =3D RNDIS_RESET_MSG; + RndisResetMsg.MessageLength =3D sizeof (REMOTE_NDIS_RESET_MSG); + + RndisResetCmplt.MessageType =3D RNDIS_RESET_CMPLT; + RndisResetCmplt.MessageLength =3D sizeof (REMOTE_NDIS_RESET_CMPLT); + + Status =3D RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&R= ndisResetMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisResetCmplt); + + UsbRndisDevice->RequestId =3D 1; // Let's start with 1 + + if (EFI_ERROR (Status) || (RndisResetCmplt.Status & 0x80000000)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + This function is called when UndiShutdown is invoked. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + +**/ +EFI_STATUS +EFIAPI +RndisUndiShutdown ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver; + USB_RNDIS_DEVICE *UsbRndisDevice; + REMOTE_NDIS_HALT_MSG RndisHltMsg; + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n")); + + UsbEthDriver =3D Nic->UsbEth; + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver); + + ZeroMem (&RndisHltMsg, sizeof (REMOTE_NDIS_HALT_MSG)); + + RndisHltMsg.MessageType =3D RNDIS_HLT_MSG; + RndisHltMsg.MessageLength =3D sizeof (REMOTE_NDIS_HALT_MSG); + + Status =3D RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&R= ndisHltMsg, NULL); + + if (Status =3D=3D EFI_DEVICE_ERROR) { + Status =3D EFI_SUCCESS; + } + + UsbRndisDevice->RequestId =3D 1; + return Status; +} + +/** + Update the Media connection. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + +**/ +EFI_STATUS +EFIAPI +RndisUndiGetStatus ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + Cdb->StatFlags &=3D ~(PXE_STATFLAGS_GET_STATUS_NO_MEDIA); + return EFI_SUCCESS; +} + +/** + Transmit the data after appending RNDIS header. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOC= OL instance. + @param[in] BulkOutData A pointer to the buffer of data that will = be transmitted to USB + device or received from USB device. + @param[in, out] DataLength A pointer to the PacketLength. + + @retval EFI_SUCCESS The request executed successfully. + +**/ +EFI_STATUS +EFIAPI +RndisUndiTransmit ( + IN PXE_CDB *Cdb, + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN VOID *BulkOutData, + IN OUT UINTN *DataLength + ) +{ + EFI_STATUS Status; + USB_RNDIS_DEVICE *UsbRndisDevice; + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg; + UINTN TransferLength; + + DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n", *DataLength))= ; + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (This); + + RndisPacketMsg =3D AllocateZeroPool (sizeof (REMOTE_NDIS_PACKET_MSG) + *= DataLength); + if (RndisPacketMsg =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + RndisPacketMsg->MessageType =3D RNDIS_PACKET_MSG; + RndisPacketMsg->MessageLength =3D sizeof (REMOTE_NDIS_PACKET_MSG) + (UIN= T32)*DataLength; + RndisPacketMsg->DataOffset =3D sizeof (REMOTE_NDIS_PACKET_MSG) - 8; + RndisPacketMsg->DataLength =3D (UINT32)*DataLength; + + CopyMem ( + ((UINT8 *)RndisPacketMsg) + sizeof (REMOTE_NDIS_PACKET_MSG), + BulkOutData, + *DataLength + ); + + TransferLength =3D RndisPacketMsg->MessageLength; + + Status =3D RndisTransmitDataMsg ( + UsbRndisDevice, + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg, + &TransferLength + ); + + DEBUG ((DEBUG_INFO, "\nRndisUndiTransmit TransferLength %lx\n", Transfer= Length)); + + FreePool (RndisPacketMsg); + + return Status; +} + +/** + Receives and removes RNDIS header and returns the raw data. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOC= OL instance. + @param[in, out] BulkInData A pointer to the buffer of data that will = be transmitted to USB + device or received from USB device. + @param[in, out] DataLength A pointer to the PacketLength. + + @retval EFI_SUCCESS The request executed successfully. + @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small + @retval EFI_NOT_FOUND No buffer was found in the list. + +**/ +EFI_STATUS +EFIAPI +RndisUndiReceive ( + IN PXE_CDB *Cdb, + IN EDKII_USB_ETHERNET_PROTOCOL *This, + IN OUT VOID *BulkInData, + IN OUT UINTN *DataLength + ) +{ + EFI_STATUS Status; + USB_RNDIS_DEVICE *UsbRndisDevice; + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg; + UINTN TransferLength; + VOID *Buffer; + PACKET_LIST *HeadPacket; + PACKET_LIST *PacketList; + + // Check if there is any outstanding packet to receive + // The buffer allocated has a linked List followed by the packet. + + UsbRndisDevice =3D USB_RNDIS_DEVICE_FROM_THIS (This); + Buffer =3D NULL; + HeadPacket =3D NULL; + + while (1) { + Buffer =3D AllocateZeroPool (sizeof (PACKET_LIST) + sizeof (REMOTE_NDI= S_PACKET_MSG) + UsbRndisDevice->MaxTransferSize); + if (Buffer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + RndisPacketMsg =3D (REMOTE_NDIS_PACKET_MSG *)(sizeof (P= ACKET_LIST) + (UINT8 *)Buffer); + PacketList =3D (PACKET_LIST *)Buffer; + PacketList->PacketStartBuffer =3D (UINT8 *)Buffer + sizeof (PACKET_LIS= T); + // Save the original address for freeing it up + PacketList->OrgBuffer =3D (UINT8 *)Buffer; + TransferLength =3D UsbRndisDevice->MaxTransferSize; + + Status =3D RndisReceiveDataMsg ( + UsbRndisDevice, + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg, + &TransferLength + ); + + if (EFI_ERROR (Status) || (TransferLength =3D=3D 0)) { + FreePool (Buffer); + break; + } + + // Collect all the RNDIS packet in Linked list. + if ((RndisPacketMsg->MessageType =3D=3D RNDIS_PACKET_MSG) && + (RndisPacketMsg->DataOffset =3D=3D sizeof (REMOTE_NDIS_PACKET_MSG)= - RNDIS_RESERVED_BYTE_LENGTH) && + (TransferLength >=3D RndisPacketMsg->MessageLength)) + { + // Insert Packet + PacketList->RemainingLength =3D TransferLength; + InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer); + } else { + FreePool (Buffer); + } + } + + while (!IsListEmpty (&UsbRndisDevice->ReceivePacketList)) { + HeadPacket =3D (PACKET_LIST *)GetFirstNode (&UsbRndisDevice->ReceivePa= cketList); + + RndisPacketMsg =3D (REMOTE_NDIS_PACKET_MSG *)(UINT8 *)HeadPacket->Pack= etStartBuffer; + + PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg); + + // Check whether the packet is valid RNDIS packet. + if ((HeadPacket->RemainingLength > sizeof (REMOTE_NDIS_PACKET_MSG)) &&= (RndisPacketMsg->MessageType =3D=3D RNDIS_PACKET_MSG) && + (RndisPacketMsg->DataOffset =3D=3D (sizeof (REMOTE_NDIS_PACKET_MSG= ) - RNDIS_RESERVED_BYTE_LENGTH)) && + (HeadPacket->RemainingLength >=3D RndisPacketMsg->MessageLength)) + { + if (*DataLength >=3D RndisPacketMsg->DataLength) { + CopyMem ( + BulkInData, + (UINT8 *)RndisPacketMsg + (RndisPacketMsg->DataOffset + RNDIS_RE= SERVED_BYTE_LENGTH), + RndisPacketMsg->DataLength + ); + + *DataLength =3D RndisPacketMsg->DataLength; + + HeadPacket->RemainingLength =3D HeadPacket->RemainingLength - Rn= disPacketMsg->MessageLength; + HeadPacket->PacketStartBuffer =3D (UINT8 *)RndisPacketMsg + RndisP= acketMsg->MessageLength; + + return EFI_SUCCESS; + } else { + *DataLength =3D RndisPacketMsg->DataLength; + return EFI_BUFFER_TOO_SMALL; + } + } + + RemoveEntryList (&HeadPacket->PacketList); + FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer); + } + + return EFI_NOT_FOUND; +} + +/** + This is a dummy function which just returns. Unimplemented EDKII_USB_ETH= ERNET_PROTOCOL functions + point to this function. + + @param[in] Cdb A pointer to the command descriptor block. + @param[in] Nic A pointer to the Network interface controller data. + + @retval EFI_SUCCESS The request executed successfully. + +**/ +EFI_STATUS +EFIAPI +RndisDummyReturn ( + IN PXE_CDB *Cdb, + IN NIC_DATA *Nic + ) +{ + DEBUG ((DEBUG_INFO, "RndisDummyReturn called\n")); + return EFI_SUCCESS; +} + +/** + This function send the RNDIS command through the device's control endpoi= nt + + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance= . + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER da= ta. + @param[out] RndisMsgResponse A pointer to the REMOTE_NDIS_MSG_HEADER da= ta for getting responses. + + @retval EFI_SUCCESS The bulk transfer has been successfully ex= ecuted. + +**/ +EFI_STATUS +RndisControlMsg ( + IN USB_RNDIS_DEVICE *UsbRndisDevice, + IN REMOTE_NDIS_MSG_HEADER *RndisMsg, + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse + ) +{ + EFI_USB_IO_PROTOCOL *UsbIo =3D UsbRndisDevice->UsbIo; + EFI_USB_DEVICE_REQUEST DevReq; + UINT32 UsbStatus; + EFI_STATUS Status; + UINT32 SaveResponseType; + UINT32 SaveResponseLength; + UINT32 Index; + REMOTE_NDIS_INITIALIZE_CMPLT *RndisInitCmplt; + + SaveResponseType =3D 0; + SaveResponseLength =3D 0; + RndisInitCmplt =3D (REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsgResponse; + + if (RndisMsgResponse) { + SaveResponseType =3D RndisMsgResponse->MessageType; + SaveResponseLength =3D RndisMsgResponse->MessageLength; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType =3D USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE; + DevReq.Request =3D SEND_ENCAPSULATED_COMMAND; + DevReq.Value =3D 0; + DevReq.Index =3D 0; + DevReq.Length =3D (UINT16)RndisMsg->MessageLength; + + PrintRndisMsg (RndisMsg); + + Status =3D UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataOut, + USB_ETHERNET_TRANSFER_TIMEOUT, + RndisMsg, + RndisMsg->MessageLength, + &UsbStatus + ); + + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r RndisMs= gResponse : %lx\n", UsbStatus, Status, RndisMsgResponse)); + + // Error or no response expected + if ((EFI_ERROR (Status)) || (RndisMsgResponse =3D=3D NULL)) { + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r\n", U= sbStatus, Status)); + return Status; + } + + for (Index =3D 0; Index < (RNDIS_CONTROL_TIMEOUT/100); Index++) { + ReadRndisResponseInterrupt (UsbRndisDevice); + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType =3D USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_CLASS | USB_= TARGET_INTERFACE; + DevReq.Request =3D GET_ENCAPSULATED_RESPONSE; + DevReq.Value =3D 0; + DevReq.Index =3D 0; + DevReq.Length =3D (UINT16)RndisMsgResponse->MessageLength; + + Status =3D UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataIn, + USB_ETHERNET_TRANSFER_TIMEOUT, + RndisMsgResponse, + RndisMsgResponse->MessageLength, + &UsbStatus + ); + + DEBUG ((DEBUG_INFO, "RndisControlMsg Response: UsbStatus : %x Status := %r \n", UsbStatus, Status)); + + PrintRndisMsg (RndisMsgResponse); + + if (!EFI_ERROR (Status)) { + if ((RndisInitCmplt->RequestID !=3D ((REMOTE_NDIS_INITIALIZE_CMPLT *= )RndisMsg)->RequestID) || (RndisInitCmplt->MessageType !=3D SaveResponseTyp= e)) { + DEBUG ((DEBUG_INFO, "Retry the response\n")); + + RndisMsgResponse->MessageType =3D SaveResponseType; + RndisMsgResponse->MessageLength =3D SaveResponseLength; + continue; + } + } + + return Status; + } + + DEBUG ((DEBUG_INFO, "RndisControlMsg: TimeOut\n")); + + return EFI_TIMEOUT; +} + +/** + This function send the RNDIS command through the device's Data endpoint + + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instan= ce. + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER = to send out. + @param[in, out] TransferLength The length of the RndisMsg data to trans= fer. + + @retval EFI_SUCCESS The request executed successfully. + +**/ +EFI_STATUS +RndisTransmitDataMsg ( + IN USB_RNDIS_DEVICE *UsbRndisDevice, + IN REMOTE_NDIS_MSG_HEADER *RndisMsg, + IN OUT UINTN *TransferLength + ) +{ + EFI_STATUS Status; + UINT32 UsbStatus; + + if (UsbRndisDevice->BulkInEndpoint =3D=3D 0) { + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice); + } + + PrintRndisMsg (RndisMsg); + + Status =3D UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer ( + UsbRndisDevice->UsbIoCdcData, + UsbRndisDevice->BulkOutEndpoint= , + RndisMsg, + TransferLength, + USB_TX_ETHERNET_BULK_TIMEOUT, + &UsbStatus + ); + + if (Status =3D=3D EFI_SUCCESS) { + gStopBulkInCnt =3D MAXIMUM_STOPBULKIN_CNT; // After sending cmd ,w= e will polling receive package for MAXIMUM_STOPBULKIN_CNT times + } + + return Status; +} + +/** + This function send the RNDIS command through the device's Data endpoint + + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE inst= ance. + @param[in, out] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADE= R to send out. + @param[in, out] TransferLength The length of the RndisMsg data to tra= nsfer. + + @retval EFI_SUCCESS The request executed successfully. + +**/ +EFI_STATUS +RndisReceiveDataMsg ( + IN USB_RNDIS_DEVICE *UsbRndisDevice, + IN OUT REMOTE_NDIS_MSG_HEADER *RndisMsg, + IN OUT UINTN *TransferLength + ) +{ + EFI_STATUS Status; + UINT32 UsbStatus; + + UsbStatus =3D 0; + + if (UsbRndisDevice->BulkInEndpoint =3D=3D 0) { + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice); + } + + // Use gStopBulkInCnt to stop BulkIn command + if (gStopBulkInCnt || LAN_BULKIN_CMD_CONTROL) { + Status =3D UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer ( + UsbRndisDevice->UsbIoCdcData, + UsbRndisDevice->BulkInEndpoin= t, + RndisMsg, + TransferLength, + USB_RX_ETHERNET_BULK_TIMEOUT, + &UsbStatus + ); + + if (!EFI_ERROR (Status)) { + gStopBulkInCnt =3D MINIMUM_STOPBULKIN_CNT; + } else { + gStopBulkInCnt--; + } + } else { + Status =3D EFI_TIMEOUT; + *TransferLength =3D 0; + gBlockBulkInCnt++; + } + + if (gBlockBulkInCnt > BULKIN_CMD_POLLING_CNT) { + gStopBulkInCnt =3D MINIMUM_STOPBULKIN_CNT; + gBlockBulkInCnt =3D 0; + } + + PrintRndisMsg (RndisMsg); + + return Status; +} + +/** + Prints RNDIS Header and Data + + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data. + +**/ +VOID +PrintRndisMsg ( + IN REMOTE_NDIS_MSG_HEADER *RndisMsg + ) +{ + UINTN Length; + REMOTE_NDIS_QUERY_CMPLT *RndisQueryCmplt; + + Length =3D 0; + + switch (RndisMsg->MessageType) { + case RNDIS_PACKET_MSG: + DEBUG ((DEBUG_INFO, "RNDIS_PACKET_MSG:\n")); + Length =3D sizeof (REMOTE_NDIS_PACKET_MSG) + 0x14; + break; + case RNDIS_INITIALIZE_MSG: + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_MSG:\n")); + Length =3D sizeof (REMOTE_NDIS_INITIALIZE_MSG); + break; + case RNDIS_INITIALIZE_CMPLT: + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_CMPLT:\n")); + Length =3D sizeof (REMOTE_NDIS_INITIALIZE_CMPLT); + break; + case RNDIS_HLT_MSG: + DEBUG ((DEBUG_INFO, "RNDIS_HLT_MSG:\n")); + Length =3D sizeof (REMOTE_NDIS_HALT_MSG); + break; + case RNDIS_QUERY_MSG: + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_MSG:\n")); + Length =3D sizeof (REMOTE_NDIS_QUERY_MSG); + break; + case RNDIS_QUERY_CMPLT: + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_CMPLT:\n")); + RndisQueryCmplt =3D (REMOTE_NDIS_QUERY_CMPLT *)RndisMsg; + Length =3D sizeof (REMOTE_NDIS_QUERY_CMPLT) + RndisQueryCmp= lt->InformationBufferLength; + break; + case RNDIS_SET_MSG: + DEBUG ((DEBUG_INFO, "RNDIS_SET_MSG:\n")); + Length =3D sizeof (REMOTE_NDIS_SET_MSG); + break; + case RNDIS_SET_CMPLT: + DEBUG ((DEBUG_INFO, "RNDIS_SET_CMPLT:\n")); + Length =3D sizeof (REMOTE_NDIS_SET_CMPLT); + break; + case RNDIS_RESET_MSG: + DEBUG ((DEBUG_INFO, "RNDIS_RESET_MSG:\n")); + Length =3D sizeof (REMOTE_NDIS_RESET_MSG); + break; + case RNDIS_RESET_CMPLT: + DEBUG ((DEBUG_INFO, "RNDIS_RESET_CMPLT:\n")); + Length =3D sizeof (REMOTE_NDIS_RESET_CMPLT); + break; + case RNDIS_INDICATE_STATUS_MSG: + DEBUG ((DEBUG_INFO, "RNDIS_INDICATE_STATUS_MSG:\n")); + Length =3D sizeof (REMOTE_NDIS_INDICATE_STATUS_MSG); + break; + case RNDIS_KEEPALIVE_MSG: + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_MSG:\n")); + Length =3D sizeof (REMOTE_NDIS_KEEPALIVE_MSG); + break; + case RNDIS_KEEPALIVE_CMPLT: + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_CMPLT:\n")); + Length =3D sizeof (REMOTE_NDIS_KEEPALIVE_CMPLT); + } + + if (Length) { + UINTN Index =3D 0; + for ( ; Length; Length -=3D 4, Index++) { + DEBUG ((DEBUG_INFO, "%8X\t", *((UINT32 *)RndisMsg + Index))); + if (((Index % 4) =3D=3D 3) && (Index !=3D 0)) { + DEBUG ((DEBUG_INFO, "\n")); + } + + if ((Length < 8) && (Length > 4)) { + UINT32 Data32; + Index++; + Data32 =3D *((UINT32 *)RndisMsg + Index); + DEBUG ((DEBUG_INFO, "%8X\t", Data32)); + break; + } + } + + if (Index % 4) { + DEBUG ((DEBUG_INFO, "\n")); + } + } +} -- 2.35.1.windows.2 -The information contained in this message may be confidential and propriet= ary to American Megatrends (AMI). This communication is intended to be read= only by the individual or entity to whom it is addressed or by their desig= nee. If the reader of this message is not the intended recipient, you are o= n notice that any distribution of this message, in any form, is strictly pr= ohibited. Please promptly notify the sender by reply e-mail or by telephone= at 770-246-8600, and then delete or destroy all copies of the transmission= .