Implemented parts of Docsis Annex C required for the Multipart Registration Response.

This commit is contained in:
feyris-tan 2025-05-21 22:23:54 +02:00
parent 0d0268509d
commit daa4ee87d4
20 changed files with 372 additions and 28 deletions

View File

@ -1,5 +1,6 @@
using skyscraper5;
using skyscraper5.Docsis.AnnexC;
using skyscraper5.Docsis.MacManagement;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Scraper;
using skyscraper5.Skyscraper.Scraper.Storage;
@ -11,6 +12,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using Xunit.Sdk;
@ -66,5 +68,25 @@ namespace skyscraper8.Tests
ModemCapabilitiesEncoding modemCapabilitiesEncoding = new ModemCapabilitiesEncoding(buffer);
Assert.True(modemCapabilitiesEncoding.Valid);
}
[Fact]
public void AAB_MultipartRegistrationResponseTest()
{
Random rng = new Random();
byte[] sourceBuffer = new byte[6];
rng.NextBytes(sourceBuffer);
PhysicalAddress source = new PhysicalAddress(sourceBuffer);
byte[] targetBuffer = new byte[6];
rng.NextBytes(targetBuffer);
PhysicalAddress target = new PhysicalAddress(targetBuffer);
byte[] buffer = Properties.Resources.MultipartRegistrationResponseTest;
T45_V4_MultipartRegistrationResponse test = new T45_V4_MultipartRegistrationResponse(source, target, buffer);
Assert.True(test.Valid);
}
}
}

View File

@ -70,6 +70,16 @@ namespace skyscraper8.Tests.Properties {
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
/// </summary>
internal static byte[] MultipartRegistrationResponseTest {
get {
object obj = ResourceManager.GetObject("MultipartRegistrationResponseTest", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
/// </summary>

View File

@ -121,6 +121,9 @@
<data name="ModemCapabilitiesEncodingTest" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ModemCapabilitiesEncodingTest.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="MultipartRegistrationResponseTest" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\T45_V4_MultipartRegistrationResponseTest.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="ranging_response_test" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ranging_response_test.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>

View File

@ -1,4 +1,6 @@
using skyscraper5.Skyscraper.IO;
using skyscraper5.Docsis.MacManagement;
using skyscraper5.Skyscraper.IO;
using skyscraper8.Docsis.AnnexC;
using skyscraper8.Docsis.DQoS;
using System;
using System.Collections.Generic;
@ -10,7 +12,7 @@ using System.Threading.Tasks;
namespace skyscraper5.Docsis.AnnexC
{
class CommonTlvEncodingObject
public class CommonTlvEncodingObject
{
public CommonTlvEncodingObject(MemoryStream ms)
{
@ -25,10 +27,14 @@ namespace skyscraper5.Docsis.AnnexC
ModemCapabilitiesEncoding = new ModemCapabilitiesEncoding(v);
break;
case 22:
UpstreamDropPacketClassificationEncoding = new GeneralPacketClassifierEncoding(v);
if (UpstreamDropPacketClassificationEncoding == null)
UpstreamDropPacketClassificationEncoding = new List<GeneralPacketClassifierEncoding>();
UpstreamDropPacketClassificationEncoding.Add(new GeneralPacketClassifierEncoding(v));
break;
case 23:
DownstreamPacketClassificationEncoding = new GeneralPacketClassifierEncoding(v);
if (DownstreamPacketClassificationEncoding == null)
DownstreamPacketClassificationEncoding = new List<GeneralPacketClassifierEncoding>();
DownstreamPacketClassificationEncoding.Add(new GeneralPacketClassifierEncoding(v));
break;
case 24:
if (UpstreamServiceFlows == null)
@ -50,7 +56,9 @@ namespace skyscraper5.Docsis.AnnexC
KeySequenceNumber = v[0];
break;
case 46:
TransmitChannelConfiguration = new TransmitChannelConfigurationObject(v);
if (TransmitChannelConfiguration == null)
TransmitChannelConfiguration = new List<TransmitChannelConfigurationObject>();
TransmitChannelConfiguration.Add(new TransmitChannelConfigurationObject(v));
break;
case 47:
ServiceFlowSidClusterAssignment = new ServiceFlowSidClusterAssignmentObject(v);
@ -58,6 +66,11 @@ namespace skyscraper5.Docsis.AnnexC
case 49:
RcpId = new RcpIdEncoding(v);
break;
case 50:
if (DsidEncodings == null)
DsidEncodings = new List<DsidEncoding>();
DsidEncodings.Add(new DsidEncoding(v));
break;
default:
//CM-SP-MULPIv4.0-I01-190815.pdf page 652
throw new NotImplementedException(string.Format("Common TLV Encodings Type {0}", type));
@ -67,11 +80,11 @@ namespace skyscraper5.Docsis.AnnexC
public ModemCapabilitiesEncoding ModemCapabilitiesEncoding { get; private set; }
public ServiceFlowSidClusterAssignmentObject ServiceFlowSidClusterAssignment { get; private set; }
public GeneralPacketClassifierEncoding DownstreamPacketClassificationEncoding { get; set; }
public List<GeneralPacketClassifierEncoding> DownstreamPacketClassificationEncoding { get; set; }
public GeneralPacketClassifierEncoding UpstreamDropPacketClassificationEncoding { get; set; }
public List<GeneralPacketClassifierEncoding> UpstreamDropPacketClassificationEncoding { get; set; }
public TransmitChannelConfigurationObject TransmitChannelConfiguration { get; set; }
public List<TransmitChannelConfigurationObject> TransmitChannelConfiguration { get; set; }
public class TransmitChannelConfigurationObject
{
public TransmitChannelConfigurationObject(byte[] buffer)
@ -93,10 +106,16 @@ namespace skyscraper5.Docsis.AnnexC
case 3:
UpstreamChannelId = v[0];
break;
case 5:
this.UpstreamChannelDescriptor = new UpstreamChannelDescriptor(null, null, v);
break;
case 6:
(v[0], v[1]) = (v[1], v[0]);
RangingSid = BitConverter.ToUInt16(v, 0);
break;
case 7:
InitializationTechnique = (InitalizationTechniqueEnum?)v[0];
break;
case 11:
ListOfIucs = v;
break;
@ -125,7 +144,9 @@ namespace skyscraper5.Docsis.AnnexC
}
public byte? TccReferenceId { get; set; }
}
public InitalizationTechniqueEnum? InitializationTechnique { get; }
public UpstreamChannelDescriptor UpstreamChannelDescriptor { get; }
}
public byte KeySequenceNumber { get; set; }
@ -136,5 +157,6 @@ namespace skyscraper5.Docsis.AnnexC
public List<GeneralServiceFlowEncoding> UpstreamServiceFlows { get; }
public RcpIdEncoding RcpId { get; private set; }
public AuthorizationBlock AuthorizationHint { get; }
public List<DsidEncoding> DsidEncodings { get; private set; }
}
}

View File

@ -0,0 +1,92 @@
using skyscraper5.Skyscraper.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Channels;
using System.Threading.Tasks;
namespace skyscraper8.Docsis.AnnexC
{
public class DsidEncoding
{
public DsidEncoding(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer, false);
while (ms.GetAvailableBytes() > 2)
{
byte type = ms.ReadUInt8();
byte length = ms.ReadUInt8();
byte[] v = ms.ReadBytes(length);
switch (type)
{
case 1:
byte[] uintBuffer = new byte[] { v[2], v[1], v[0], 0 };
DSID = BitConverter.ToUInt32(uintBuffer);
break;
case 2:
DownstreamServiceIdentifierAction = (DownstreamServiceIdentifierActionEnum)v[0];
break;
case 3:
DownstreamResequencingEncodings = new EncodedResequencingAttributes(v);
break;
case 4:
MulticastEncodings = new EncodedMulticastAttributes(v);
break;
default:
//CM-SP-MULPIv4.0-I01-190815.pdf, page 731
throw new NotImplementedException(String.Format("DSID Encoding 50.{0}", type));
}
}
}
public uint? DSID { get; }
public DownstreamServiceIdentifierActionEnum? DownstreamServiceIdentifierAction { get; }
public enum DownstreamServiceIdentifierActionEnum
{
Add = 0,
Change = 1,
Delete = 2
}
public EncodedResequencingAttributes DownstreamResequencingEncodings { get; }
internal EncodedMulticastAttributes MulticastEncodings { get; }
public class EncodedResequencingAttributes
{
public EncodedResequencingAttributes(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer, false);
while (ms.GetAvailableBytes() > 2)
{
byte type = ms.ReadUInt8();
byte length = ms.ReadUInt8();
byte[] v = ms.ReadBytes(length);
switch (type)
{
case 1:
IsResequencing = v[0] == 1;
break;
case 2:
DownstreamResequencingChannelList = v;
break;
case 3:
DsidResequencingWaitTime = v[0];
break;
default:
//CM-SP-MULPIv4.0-I01-190815.pdf, page 731
throw new NotImplementedException(String.Format("EncodedResequencingAttributes 50.3.{0}", type));
}
}
}
public bool? IsResequencing { get; }
public byte[] DownstreamResequencingChannelList { get; }
public byte DsidResequencingWaitTime { get; }
}
}
}

View File

@ -0,0 +1,31 @@
using skyscraper5.Skyscraper.IO;
using static skyscraper8.Docsis.AnnexC.DsidEncoding;
namespace skyscraper8.Docsis.AnnexC
{
internal class EncodedMulticastAttributes
{
public EncodedMulticastAttributes(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer, false);
while (ms.GetAvailableBytes() > 2)
{
byte type = ms.ReadUInt8();
byte length = ms.ReadUInt8();
byte[] v = ms.ReadBytes(length);
switch (type)
{
case 2:
this.MulticastCmInterfaceMask = new MulticastCmInterfaceMask(v);
break;
default:
//CM-SP-MULPIv4.0-I01-190815.pdf, page 732
throw new NotImplementedException(String.Format("DSID Encoding 50.4.{0}", type));
}
}
}
public MulticastCmInterfaceMask MulticastCmInterfaceMask { get; }
}
}

View File

@ -0,0 +1,36 @@
using skyscraper5.Skyscraper.IO;
using skyscraper8.Docsis.DQoS;
using System;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace skyscraper5.Docsis.AnnexC
{
public class EthernetLlcPacketClassificationEncoding
{
public EthernetLlcPacketClassificationEncoding(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer, false);
while (ms.GetAvailableBytes() > 3)
{
byte type = ms.ReadUInt8();
ushort length = ms.ReadUInt8();
byte[] v = ms.ReadBytes(length);
switch (type)
{
case 3:
(v[1], v[2]) = (v[2], v[1]);
this.Type = v[0];
this.EProt = BitConverter.ToUInt16(v, 1);
break;
default:
//CM-SP-MULPIv4.0-I01-190815.pdf, page 747
throw new NotImplementedException(string.Format("EthernetLlcPacketClassificationEncoding [22/23/60].10.{0}", type));
}
}
}
public byte Type { get; }
public ushort EProt { get; }
}
}

View File

@ -9,7 +9,7 @@ using skyscraper5.Skyscraper.IO;
namespace skyscraper5.Docsis.AnnexC
{
internal class GeneralPacketClassifierEncoding
public class GeneralPacketClassifierEncoding
{
public GeneralPacketClassifierEncoding(byte[] buffer)
{
@ -49,7 +49,13 @@ namespace skyscraper5.Docsis.AnnexC
case 9:
Ipv4PacketClassification = new Ipv4PacketClassificationEncodings(v);
break;
default:
case 10:
EthernetLlcPacketClassificationEncodings = new EthernetLlcPacketClassificationEncoding(v);
break;
case 12:
Ipv6PacketClassification = new Ipv6PacketClassificationEncoding(v);
break;
default:
//see CM-SP-MULPIv4.0-I01-190815.pdf page 742->743
throw new NotImplementedException(string.Format("{0} TLV Type {1}", nameof(GeneralPacketClassifierEncoding), type));
}
@ -87,10 +93,16 @@ namespace skyscraper5.Docsis.AnnexC
case 3:
Ipv4SourceAddress = new IPAddress(v);
break;
case 4:
Ipv4SourceMask = new IPAddress(v);
break;
case 5:
Ipv4DestinationAddress = new IPAddress(v);
break;
case 7:
case 6:
Ipv4DestinationMask = new IPAddress(v);
break;
case 7:
(v[0], v[1]) = (v[1], v[0]);
SourcePortStart = BitConverter.ToUInt16(v, 0);
break;
@ -126,7 +138,9 @@ namespace skyscraper5.Docsis.AnnexC
public ushort? SourcePortStart { get; set; }
public ushort? SourcePortEnd { get; set; }
}
public IPAddress Ipv4SourceMask { get; private set; }
public IPAddress Ipv4DestinationMask { get; private set; }
}
public ushort? ServiceFlowReference { get; set; }
public byte? ClassifierReference { get; set; }
@ -134,5 +148,7 @@ namespace skyscraper5.Docsis.AnnexC
public ushort? ClassifierIdentifier { get; set; }
public uint? ServiceFlowIdentifier { get; set; }
}
public EthernetLlcPacketClassificationEncoding EthernetLlcPacketClassificationEncodings { get; }
internal Ipv6PacketClassificationEncoding Ipv6PacketClassification { get; }
}
}

View File

@ -5,10 +5,11 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper.IO;
using static skyscraper5.Dvb.Descriptors.ServiceListDescriptor;
namespace skyscraper5.Docsis.AnnexC
{
internal class GeneralServiceFlowEncoding
public class GeneralServiceFlowEncoding
{
public GeneralServiceFlowEncoding(byte[] buffer)
{
@ -56,7 +57,11 @@ namespace skyscraper5.Docsis.AnnexC
(v[0], v[1]) = (v[1], v[0]);
TimeoutForActiveQosParameters = BitConverter.ToUInt16(v, 0);
break;
case 15:
case 14:
(v[0], v[1]) = (v[1], v[0]);
MaximumConcatenatedBurst = BitConverter.ToUInt16(v, 0);
break;
case 15:
ServiceFlowSchedulingType = (ServiceFlowSchedulingTypeEnum)v[0];
break;
case 16:
@ -98,11 +103,22 @@ namespace skyscraper5.Docsis.AnnexC
case 22:
GrantsPerInterval = v[0];
break;
case 23:
IpTypeOfServiceOverwrite = v;
break;
case 24:
(v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
CmtsTimestamp = BitConverter.ToUInt32(v, 0);
break;
default:
case 26:
MultiplierToNumberOfBytesRequested = v[0];
break;
case 32:
(v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
ServiceFlowForbiddenAttributeMask = BitConverter.ToUInt32(v);
break;
default:
//CM-SP-MULPIv4.0-I01-190815.pdf page 758
throw new NotImplementedException(string.Format("General Service Flow Encodings Type {0}", type));
}
@ -177,8 +193,12 @@ namespace skyscraper5.Docsis.AnnexC
public bool? AdmittedSet { get; set; }
public bool? ProvisionedSet { get; set; }
public byte[] IpTypeOfServiceOverwrite { get; }
public ushort MaximumConcatenatedBurst { get; }
public byte MultiplierToNumberOfBytesRequested { get; }
public uint ServiceFlowForbiddenAttributeMask { get; }
public override string ToString()
public override string ToString()
{
return $"{nameof(ServiceFlowIdentifier)}: {ServiceFlowIdentifier}";
}

View File

@ -0,0 +1,14 @@
namespace skyscraper5.Docsis.AnnexC
{
public enum InitalizationTechniqueEnum : byte
{
BroadcastInitialRanging = 1,
UnicastInitialRanging = 2,
EitherBroadcastOrUnicast = 3,
NewChannel = 4,
ProbeNewChannel = 5,
UnicastInitialRangingOnNewChannel = 6,
StationRanging = 7,
AssumeSucessful = 8
}
}

View File

@ -0,0 +1,39 @@
using skyscraper5.Skyscraper.IO;
using System.Net;
namespace skyscraper5.Docsis.AnnexC
{
internal class Ipv6PacketClassificationEncoding
{
public Ipv6PacketClassificationEncoding(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer, false);
while (ms.GetAvailableBytes() > 3)
{
byte type = ms.ReadUInt8();
ushort length = ms.ReadUInt8();
byte[] v = ms.ReadBytes(length);
switch (type)
{
case 3:
(v[0], v[1]) = (v[1], v[0]);
NextHeaderType = BitConverter.ToUInt16(v, 0);
break;
case 4:
Ipv6SourceAddress = new IPAddress(v);
break;
case 6:
Ipv6DestinationAddress = new IPAddress(v);
break;
default:
//CM-SP-MULPIv4.0-I01-190815.pdf, page 749
throw new NotImplementedException(string.Format("Ipv6PacketClassificationEncoding [22/23/60].12.{0}", type));
}
}
}
public ushort NextHeaderType { get; }
public IPAddress Ipv6DestinationAddress { get; }
public IPAddress Ipv6SourceAddress { get; }
}
}

View File

@ -0,0 +1,30 @@
using skyscraper5.Mpeg2.Descriptors;
namespace skyscraper8.Docsis.AnnexC
{
internal class MulticastCmInterfaceMask
{
public MulticastCmInterfaceMask(byte[] v)
{
uint buffered = BitConverter.ToUInt32(v, 0);
CmIpStack = (buffered & 0x00000001) != 0;
PrimaryCpeInterfae = (buffered & 0x00000002) != 0;
RfInterface = (buffered & 0x00000004) != 0;
//Reserved = (buffered & 0x00000018) != 0;
OtherCpeInterfaces = (buffered & 0x0000ffe0) != 0;
PacketCableEmta = (buffered & 0x00010000) != 0;
EstbIp = (buffered & 0x00020000) != 0;
//Reserved = (buffered & 0x00040000) != 0;
OtherESafeInterfaces = (buffered & 0xfff80000) != 0;
}
public bool CmIpStack { get; }
public bool PrimaryCpeInterfae { get; }
public bool RfInterface { get; }
public bool OtherCpeInterfaces { get; }
public bool PacketCableEmta { get; }
public bool EstbIp { get; }
public bool OtherESafeInterfaces { get; }
}
}

View File

@ -10,7 +10,7 @@ using static skyscraper5.src.InteractionChannel.Model2.Tbtp2;
namespace skyscraper5.Docsis.AnnexC
{
internal class RcpIdEncoding
public class RcpIdEncoding
{
public RcpIdEncoding(byte[] buffer)
{
@ -35,7 +35,7 @@ namespace skyscraper5.Docsis.AnnexC
public SimplifiedReceiveChannelAssignmentEncoding SimplifiedReceiveChannelConfiguration { get; private set; }
}
class SimplifiedReceiveChannelAssignmentEncoding
public class SimplifiedReceiveChannelAssignmentEncoding
{
public SimplifiedReceiveChannelAssignmentEncoding(byte[] buffer)
{

View File

@ -8,7 +8,7 @@ using skyscraper5.Skyscraper.IO;
namespace skyscraper5.Docsis.AnnexC
{
internal class ServiceFlowSidClusterAssignmentObject
public class ServiceFlowSidClusterAssignmentObject
{
public ServiceFlowSidClusterAssignmentObject(byte[] buffer)
{

View File

@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace skyscraper8.Docsis.DQoS
{
internal class AuthorizationBlock : Validatable
public class AuthorizationBlock : Validatable
{
public AuthorizationBlock(byte[] buffer)
{

View File

@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace skyscraper8.Docsis.DQoS
{
internal class PacketCableAuthorizationBlockEncoding : Validatable
public class PacketCableAuthorizationBlockEncoding : Validatable
{
public PacketCableAuthorizationBlockEncoding(byte[] buffer)
{

View File

@ -28,6 +28,11 @@ namespace skyscraper5.Docsis.MacManagement
{
byte type = ms.ReadUInt8();
byte length = ms.ReadUInt8();
if (ms.GetAvailableBytes() < length)
{
Valid = false;
return;
}
byte[] v = ms.ReadBytes(length);
switch (type)
{

View File

@ -8,7 +8,7 @@ namespace skyscraper5.Docsis.MacManagement
{
[SkyscraperPlugin]
[MacManagementMessageType(4,45)]
internal class T45_V4_MultipartRegistrationResponse : MacManagementMessage
public class T45_V4_MultipartRegistrationResponse : MacManagementMessage
{
public T45_V4_MultipartRegistrationResponse(PhysicalAddress source, PhysicalAddress destination, byte[] buffer) : base(source, destination, buffer)
{
@ -18,6 +18,7 @@ namespace skyscraper5.Docsis.MacManagement
NumberOfFragments = ms.ReadUInt8();
FragmentSequenceNumber = ms.ReadUInt8();
TlvEncodedInformation = new CommonTlvEncodingObject(ms);
Valid = true;
}
public CommonTlvEncodingObject TlvEncodedInformation { get; set; }

View File

@ -150,19 +150,20 @@ namespace skyscraper8.Skyscraper.IO
public override bool CanRead => throw new NotImplementedException();
public override bool CanSeek => throw new NotImplementedException();
public override bool CanSeek => false;
public override bool CanWrite => throw new NotImplementedException();
public override bool CanWrite => false;
public override long Length => throw new NotImplementedException();
public override long Length => throw new NotSupportedException();
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public override long Position { get => actuallyRead; set => throw new NotSupportedException(); }
public override void Flush()
{
throw new NotImplementedException();
}
private long actuallyRead;
public override int Read(byte[] buffer, int offset, int count)
{
int result = 0;
@ -173,6 +174,7 @@ namespace skyscraper8.Skyscraper.IO
{
if (!GetNextSegment())
{
actuallyRead += result;
return result;
}
continue;
@ -181,6 +183,7 @@ namespace skyscraper8.Skyscraper.IO
count -= readResult;
result += readResult;
}
actuallyRead += result;
return result;
}