From aba2edf27072fed2930411247eabd2e3bcc76c7e Mon Sep 17 00:00:00 2001 From: David Hall Date: Thu, 19 Oct 2023 19:53:09 -0600 Subject: [PATCH] Fixed and enhanced QoS structures. --- PInvoke/QoS/QoS.cs | 5 ++++- PInvoke/QoS/QoSSP.cs | 2 +- PInvoke/QoS/Traffic.cs | 26 +++++++++++++++++++++++--- PInvoke/Ws2_32/QoS.cs | 27 ++++++++++++++++++++++++--- UnitTests/PInvoke/QoS/QoSTests.cs | 10 ++++++---- 5 files changed, 58 insertions(+), 12 deletions(-) diff --git a/PInvoke/QoS/QoS.cs b/PInvoke/QoS/QoS.cs index 47857d4a..90a6d30f 100644 --- a/PInvoke/QoS/QoS.cs +++ b/PInvoke/QoS/QoS.cs @@ -118,7 +118,7 @@ public static partial class Qwave // QOS_OBJECT_HDR, *LPQOS_OBJECT_HDR; [PInvokeData("qos.h", MSDNShortId = "NS:qos.__unnamed_struct_0")] [StructLayout(LayoutKind.Sequential)] - public struct QOS_OBJECT_HDR + public struct QOS_OBJECT_HDR : IQoSObjectHdr { /// /// Specifies the type of object to which QOS_OBJECT_HDR is attached. The following values are valid for QOS_OBJECT_HDR: @@ -145,6 +145,9 @@ public static partial class Qwave var ot = CorrespondingTypeAttribute.CanGet(typeof(T), out var e) ? e : throw new ArgumentException(); return new() { ObjectType = ot, ObjectLength = (uint)Marshal.SizeOf(typeof(T)) }; } + + /// An instance of used for the end of a list. + public static readonly QOS_OBJECT_HDR EndOfList = Init(); } /// The QOS object QOS_SD_MODE defines the behavior of the traffic control-packet shaper component. diff --git a/PInvoke/QoS/QoSSP.cs b/PInvoke/QoS/QoSSP.cs index f1243bac..07cd74ee 100644 --- a/PInvoke/QoS/QoSSP.cs +++ b/PInvoke/QoS/QoSSP.cs @@ -228,7 +228,7 @@ public static partial class Qwave } ret.Write(native); - if (bufLen > 0) + if (bufLen > 0 && ParamBuffer.HasValue) { ret.Write(ParamBuffer.Value.Buffer, false, bufOffset); } diff --git a/PInvoke/QoS/Traffic.cs b/PInvoke/QoS/Traffic.cs index f0469f07..820738f6 100644 --- a/PInvoke/QoS/Traffic.cs +++ b/PInvoke/QoS/Traffic.cs @@ -1973,6 +1973,25 @@ public static partial class Traffic /// criteria). Note that the Mask member must be of the same type as the Pattern member. /// public IntPtr Mask; + + /// Creates a instance. + /// The type of the pattern. + /// The filter type to be applied with the filter. + /// Indicates the specific format of the pattern to be applied to the filter, such as IP_PATTERN. + /// A bitmask applied to the bits designated in the Pattern member. + /// The memory allocated too the and fields. + /// + /// A complete instance. Do not dispose the value returned in until this + /// structure is no longer needed. + /// + public static TC_GEN_FILTER Create(NDIS_PROTOCOL_ID AddressType, in T Pattern, in T Mask, out SafeHandle memAlloc) where T : struct + { + var sz = Marshal.SizeOf(typeof(T)); + SafeNativeArray parts = new(new T[] { Pattern, Mask }); + memAlloc = parts; + var ptrs = parts.GetPointers(); + return new TC_GEN_FILTER { AddressType = AddressType, PatternSize = (uint)sz, Pattern = ptrs[0], Mask = ptrs[1] }; + } } /// @@ -2086,14 +2105,15 @@ public static partial class Traffic if (managedObject is not TC_GEN_FLOW f) throw new ArgumentException("Only objects of type TC_GEN_FLOW can be marshaled."); int objLen = f.TcObjects?.Length ?? 0; - SafeCoTaskMemStruct pFlow = new(new INT_TC_GEN_FLOW() { SendingFlowspec = f.SendingFlowspec, ReceivingFlowspec = f.ReceivingFlowspec, TcObjectsLength = objLen }); - pFlow.Size += f.TcObjects?.Sum(o => Marshal.SizeOf(o.GetType())) ?? 0; + int objByteLen = f.TcObjects?.Sum(o => Marshal.SizeOf(o.GetType())) ?? 0; + SafeCoTaskMemStruct pFlow = new(new INT_TC_GEN_FLOW() { SendingFlowspec = f.SendingFlowspec, ReceivingFlowspec = f.ReceivingFlowspec, TcObjectsLength = objByteLen }); + pFlow.Size += objByteLen; if (objLen > 0) { var oPtr = pFlow.GetFieldAddress(nameof(TcObjects)); for (int i = 0; i < objLen; i++) { - oPtr.Write(f.TcObjects[i]); + oPtr.Write(f.TcObjects![i]); oPtr = oPtr.Offset(Marshal.SizeOf(f.TcObjects[i].GetType())); } } diff --git a/PInvoke/Ws2_32/QoS.cs b/PInvoke/Ws2_32/QoS.cs index 14e984fb..955bacb3 100644 --- a/PInvoke/Ws2_32/QoS.cs +++ b/PInvoke/Ws2_32/QoS.cs @@ -171,9 +171,30 @@ public static partial class Ws2_32 public struct FLOWSPEC { /// Represents a FLOWSPEC with all unspecified values. - public static readonly FLOWSPEC NotSpecified = new() { DelayVariation = QOS_NOT_SPECIFIED, Latency = QOS_NOT_SPECIFIED, MaxSduSize = QOS_NOT_SPECIFIED, - MinimumPolicedSize = QOS_NOT_SPECIFIED, PeakBandwidth = QOS_NOT_SPECIFIED, TokenBucketSize = QOS_NOT_SPECIFIED, TokenRate = QOS_NOT_SPECIFIED, - ServiceType = SERVICETYPE.SERVICETYPE_BESTEFFORT }; + public static readonly FLOWSPEC NotSpecified = new(SERVICETYPE.SERVICETYPE_BESTEFFORT); + + /// Initializes a new instance of the struct. + /// The delay variation. + /// The latency. + /// Maximum size of the sdu. + /// Minimum size of the policed. + /// The peak bandwidth. + /// Size of the token bucket. + /// The token rate. + /// Type of the service. + public FLOWSPEC(SERVICETYPE serviceType, uint tokenRate = QOS_NOT_SPECIFIED, uint delayVariation = QOS_NOT_SPECIFIED, + uint latency = QOS_NOT_SPECIFIED, uint maxSduSize = QOS_NOT_SPECIFIED, uint minimumPolicedSize = QOS_NOT_SPECIFIED, + uint peakBandwidth = QOS_NOT_SPECIFIED, uint tokenBucketSize = QOS_NOT_SPECIFIED) + { + DelayVariation = delayVariation; + Latency = latency; + MaxSduSize = maxSduSize; + MinimumPolicedSize = minimumPolicedSize; + PeakBandwidth = peakBandwidth; + TokenBucketSize = tokenBucketSize; + TokenRate = tokenRate; + ServiceType = serviceType; + } /// /// diff --git a/UnitTests/PInvoke/QoS/QoSTests.cs b/UnitTests/PInvoke/QoS/QoSTests.cs index bdb772d8..be25f35d 100644 --- a/UnitTests/PInvoke/QoS/QoSTests.cs +++ b/UnitTests/PInvoke/QoS/QoSTests.cs @@ -69,14 +69,16 @@ public class QoSTests { TC_GEN_FLOW flow = new() { - SendingFlowspec = FLOWSPEC.NotSpecified, - ReceivingFlowspec = FLOWSPEC.NotSpecified, - TcObjects = new IQoSObjectHdr[] { new QOS_DS_CLASS { ObjectHdr = QOS_OBJECT_HDR.Init(), DSField = 0x28 } } + SendingFlowspec = new FLOWSPEC(SERVICETYPE.SERVICETYPE_GUARANTEED, 10000, maxSduSize: 344, minimumPolicedSize: 12, peakBandwidth: 32000, tokenBucketSize: 680), + ReceivingFlowspec = new(SERVICETYPE.SERVICETYPE_GUARANTEED, 10000), + TcObjects = new IQoSObjectHdr[] { new QOS_DS_CLASS { ObjectHdr = QOS_OBJECT_HDR.Init(), DSField = 0x2E }, QOS_OBJECT_HDR.EndOfList } }; Assert.That(TcAddFlow(hIfc, default, default, flow, out var hFlow), ResultIs.Successful); try { - TC_GEN_FILTER filter = new() { }; + IP_PATTERN pattern = new() { ProtocolId = (byte)IPPROTO.IPPROTO_UDP, tcDstPort = 5000 }; + IP_PATTERN mask = new() { ProtocolId = 0xFF, tcDstPort = 0xFFFF }; + TC_GEN_FILTER filter = TC_GEN_FILTER.Create(NDIS_PROTOCOL_ID.NDIS_PROTOCOL_ID_TCP_IP, pattern, mask, out var mem); Assert.That(TcAddFilter(hFlow, filter, out SafeHFILTER hFilt), ResultIs.Successful); hFilt.Dispose(); }