From f2738fed3a0bca5b401ee1b90ea27c07c1ddc415 Mon Sep 17 00:00:00 2001 From: Tinh Nguyen Date: Tue, 7 Feb 2023 12:43:17 +0700 Subject: [PATCH] UsbNetworkPkg: Support rate limitting Signed-off-by: Tinh Nguyen --- .../Protocol/EdkIIUsbEthernetProtocol.h | 2 + UsbNetworkPkg/NetworkCommon/DriverBinding.h | 2 + UsbNetworkPkg/NetworkCommon/NetworkCommon.inf | 4 ++ UsbNetworkPkg/NetworkCommon/PxeFunction.c | 70 +++++++++++++++++-- UsbNetworkPkg/UsbNetworkPkg.dec | 5 ++ 5 files changed, 77 insertions(+), 6 deletions(-) diff --git a/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h index f1df1c4cbd..8c8397fc70 100644 --- a/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h +++ b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h @@ -159,6 +159,8 @@ typedef struct { UINT8 CurrentNodeAddress[PXE_MAC_LENGTH]; UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH]; EFI_USB_DEVICE_REQUEST Request; + EFI_EVENT RateLimiter; + UINTN RateLimitCredit; } NIC_DATA; #define NIC_DATA_SIGNATURE SIGNATURE_32('n', 'i', 'c', 'd') diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h b/UsbNetworkPkg/NetworkCommon/DriverBinding.h index 1aa4c86ff9..2fa41f4b74 100644 --- a/UsbNetworkPkg/NetworkCommon/DriverBinding.h +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #define RX_BUFFER_COUNT 32 #define TX_BUFFER_COUNT 32 #define MEMORY_REQUIRE 0 +#define RATE_LIMITER_INTERVAL 1000000 // 10Hz #define UNDI_DEV_SIGNATURE SIGNATURE_32('u','n','d','i') #define UNDI_DEV_FROM_THIS(a) CR(a, NIC_DEVICE, NiiProtocol, UNDI_DEV_SIGNATURE) diff --git a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf index 2691e8e70d..82e5771fb1 100644 --- a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf @@ -40,5 +40,9 @@ gEfiDriverBindingProtocolGuid gEdkIIUsbEthProtocolGuid +[Pcd] + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting + gUsbNetworkPkgTokenSpaceGuid.RateLimitingResumeTime + [Depex] TRUE diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c b/UsbNetworkPkg/NetworkCommon/PxeFunction.c index aae7d787db..d2b22e6738 100644 --- a/UsbNetworkPkg/NetworkCommon/PxeFunction.c +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c @@ -29,6 +29,20 @@ API_FUNC gUndiApiTable[] = { UndiReceive }; +VOID +EFIAPI +UndiRateLimiterCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + NIC_DATA *Nic = Context; + + if (Nic->RateLimitCredit < PcdGet32 (RateLimitingResumeTime)) { + Nic->RateLimitCredit++; + } +} + /** This command is used to determine the operational state of the UNDI. @@ -100,9 +114,6 @@ UndiStart ( Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; Cdb->StatCode = PXE_STATCODE_INVALID_CDB; return; - } else { - Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; - Cdb->StatCode = PXE_STATCODE_SUCCESS; } if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) { @@ -120,14 +131,46 @@ UndiStart ( Nic->PxeStart.UnMap_Mem = 0; Nic->PxeStart.Sync_Mem = Cpb->Sync_Mem; Nic->PxeStart.Unique_ID = Cpb->Unique_ID; - Nic->State = PXE_STATFLAGS_GET_STATE_STARTED; + + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + UndiRateLimiterCallback, + Nic, + &Nic->RateLimiter + ); + if (EFI_ERROR (Status)) { + goto ErrorCreateEvent; + } + + Status = gBS->SetTimer ( + Nic->RateLimiter, + TimerPeriodic, + RATE_LIMITER_INTERVAL + ); + if (EFI_ERROR (Status)) { + goto ErrorSetTimer; + } if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) { Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic); if (EFI_ERROR (Status)) { - Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + goto ErrorUndiStart; } } + + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED; + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; + Cdb->StatCode = PXE_STATCODE_SUCCESS; + return; + +ErrorUndiStart: + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0); +ErrorSetTimer: + gBS->CloseEvent (&Nic->RateLimiter); +ErrorCreateEvent: + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; + Cdb->StatCode = PXE_STATCODE_DEVICE_FAILURE; } /** @@ -183,6 +226,9 @@ UndiStop ( Nic->PxeStart.Sync_Mem = 0; Nic->State = PXE_STATFLAGS_GET_STATE_STOPPED; + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0); + gBS->CloseEvent (&Nic->RateLimiter); + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) { Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic); if (EFI_ERROR (Status)) { @@ -1476,6 +1522,7 @@ Receive ( UINT8 *BulkInData; UINTN DataLength; EthernetHeader *Header; + EFI_TPL OriginalTpl; FrameType = PXE_FRAME_TYPE_NONE; NicDevice = UNDI_DEV_FROM_NIC (Nic); @@ -1488,10 +1535,21 @@ Receive ( return PXE_STATCODE_INVALID_PARAMETER; } + if ((Nic->RateLimitCredit == 0) && (PcdGetBool (EnableRateLimiting))) { + return PXE_STATCODE_NO_DATA; + } + Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID *)BulkInData, &DataLength); - if (EFI_ERROR (Status)) { + if (EFI_ERROR (Status) && (Status != EFI_TIMEOUT)) { Nic->ReceiveStatus = 0; return PXE_STATCODE_NO_DATA; + } else { + OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY); + if (Nic->RateLimitCredit != 0) { + Nic->RateLimitCredit--; + } + + gBS->RestoreTPL (OriginalTpl); } Nic->RxFrame++; diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec b/UsbNetworkPkg/UsbNetworkPkg.dec index fa7c40b7ef..65b15f8000 100644 --- a/UsbNetworkPkg/UsbNetworkPkg.dec +++ b/UsbNetworkPkg/UsbNetworkPkg.dec @@ -34,3 +34,8 @@ ## Set the PCD 'UsbRndisSupport' to 'TRUE' if 'Usb Rndis device' need to be enabled. gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE|BOOLEAN|0x00000003 +[PcdsDynamic] + ## Support rate limitting + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting|FALSE|BOOLEAN|0x00000004 + gUsbNetworkPkgTokenSpaceGuid.RateLimitingResumeTime|10|UINT32|0x00000005 # unit 100ms + -- 2.25.1