diff --git a/skyscraper8/Ietf/IetfException.cs b/skyscraper8/Ietf/IetfException.cs
new file mode 100644
index 0000000..b53e269
--- /dev/null
+++ b/skyscraper8/Ietf/IetfException.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using skyscraper5;
+
+namespace skyscraper8.Ietf
+{
+ public class IetfException : SkyscraperException
+ {
+ public IetfException()
+ {
+ }
+
+ public IetfException(string message) : base(message)
+ {
+ }
+
+ public IetfException(string message, Exception inner) : base(message, inner)
+ {
+ }
+ }
+}
diff --git a/skyscraper8/Ietf/Rfc4236_ULE/UleContestant.cs b/skyscraper8/Ietf/Rfc4236_ULE/UleContestant.cs
new file mode 100644
index 0000000..5418d86
--- /dev/null
+++ b/skyscraper8/Ietf/Rfc4236_ULE/UleContestant.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.NetworkInformation;
+using System.Text;
+using System.Threading.Tasks;
+using skyscraper5.Skyscraper.Plugins;
+using skyscraper5.Skyscraper.Scraper;
+using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
+
+namespace skyscraper8.Ietf.Rfc4236_ULE
+{
+ [SkyscraperPlugin]
+ internal class UleContestant : Contestant, UleEventHandler
+ {
+ public UleContestant(int pid) : base("ULE", pid)
+ {
+ PacketProcessor = new UlePacketProcessor(pid, this);
+ }
+
+ public override void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Introduce(ProgramContext programContext)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void OnEthernetFrame(int pid, PhysicalAddress destination, PhysicalAddress source, ushort etherType, byte[] contents)
+ {
+ Score++;
+ }
+
+ public void OnUleError(int pid, int errorNo)
+ {
+ Score--;
+ }
+ }
+}
diff --git a/skyscraper8/Ietf/Rfc4236_ULE/UleEventHandler.cs b/skyscraper8/Ietf/Rfc4236_ULE/UleEventHandler.cs
new file mode 100644
index 0000000..b774498
--- /dev/null
+++ b/skyscraper8/Ietf/Rfc4236_ULE/UleEventHandler.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.NetworkInformation;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace skyscraper8.Ietf.Rfc4236_ULE
+{
+ internal interface UleEventHandler
+ {
+ void OnEthernetFrame(int pid, PhysicalAddress destination, PhysicalAddress source, ushort etherType, byte[] contents);
+
+ ///
+ /// The UlePacketProcessor is supposed to call this whenever an Error occurs during deframing.
+ ///
+ /// The source PID of the ULE ES
+ ///
+ /// Set this to:
+ /// 1* for a CRC error.
+ ///
+ void OnUleError(int pid, int errorNo);
+ }
+}
diff --git a/skyscraper8/Ietf/Rfc4236_ULE/UleException.cs b/skyscraper8/Ietf/Rfc4236_ULE/UleException.cs
new file mode 100644
index 0000000..44682f8
--- /dev/null
+++ b/skyscraper8/Ietf/Rfc4236_ULE/UleException.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace skyscraper8.Ietf.Rfc4236_ULE
+{
+ public class UleException : IetfException
+ {
+ public UleException()
+ {
+ }
+
+ public UleException(string message) : base(message)
+ {
+ }
+
+ public UleException(string message, Exception inner) : base(message, inner)
+ {
+ }
+ }
+}
diff --git a/skyscraper8/Ietf/Rfc4236_ULE/UlePacketProcessor.cs b/skyscraper8/Ietf/Rfc4236_ULE/UlePacketProcessor.cs
new file mode 100644
index 0000000..6e627e6
--- /dev/null
+++ b/skyscraper8/Ietf/Rfc4236_ULE/UlePacketProcessor.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.NetworkInformation;
+using System.Text;
+using System.Threading.Tasks;
+using skyscraper5.Mpeg2;
+using skyscraper5.Skyscraper.IO;
+
+namespace skyscraper8.Ietf.Rfc4236_ULE
+{
+ internal class UlePacketProcessor : ITsPacketProcessor, IPayloadUnitDecoder
+ {
+ private readonly int _pid;
+ private readonly UleEventHandler _eventHandler;
+
+ private bool reassemblyMode;
+ private int reassemblyRemainingBytes;
+ private MemoryStream reassemblyStream;
+ private long offset;
+
+ public UlePacketProcessor(int pid, UleEventHandler eventHandler)
+ {
+ _pid = pid;
+ _eventHandler = eventHandler;
+ }
+
+ public void PushPacket(TsPacket packet)
+ {
+
+ if (packet.PayloadUnitStart)
+ {
+ PushPusiPacket(packet);
+ }
+ else
+ {
+ if (reassemblyMode)
+ {
+ int availableBytes = Math.Min(184, reassemblyRemainingBytes);
+ reassemblyStream.Write(packet.RawPacket, 4, availableBytes);
+ reassemblyRemainingBytes -= availableBytes;
+ if (reassemblyRemainingBytes == 0)
+ {
+ reassemblyMode = false;
+ reassemblyStream.Position = 0;
+ OnReassembledPacket(reassemblyStream);
+ reassemblyStream = null;
+ }
+ }
+ else
+ {
+ //Es gibt keine neue Payload Unit, und wir bauen uns auch keine zusammen, also diese wegwerfen.
+ return;
+ }
+ }
+
+ offset += 188;
+ }
+
+ private void PushPusiPacket(TsPacket packet)
+ {
+ bool multipleSndusInPacket = false;
+
+ MemoryStream payload = new MemoryStream(packet.RawPacket, false);
+ payload.Position += 4;
+ byte nextPacketOffset = payload.ReadUInt8();
+ if (!reassemblyMode)
+ payload.Position += nextPacketOffset;
+
+ while (payload.GetAvailableBytes() > 0)
+ {
+ if (reassemblyMode)
+ {
+ int availableBytes = Math.Min((int)payload.GetAvailableBytes(), reassemblyRemainingBytes);
+ byte[] stepBuffer = new byte[availableBytes];
+ int sucessfullyCopiedBytes = payload.Read(stepBuffer, 0, availableBytes);
+ if (sucessfullyCopiedBytes != availableBytes)
+ throw new UleException("Byte copy operation failed during reassembly.");
+ reassemblyStream.Write(stepBuffer, 0, sucessfullyCopiedBytes);
+ reassemblyRemainingBytes -= sucessfullyCopiedBytes;
+ if (reassemblyRemainingBytes == 0)
+ {
+ reassemblyMode = false;
+ reassemblyStream.Position = 0;
+ OnReassembledPacket(reassemblyStream);
+ reassemblyStream = null;
+ multipleSndusInPacket = true;
+ }
+ }
+ else
+ {
+ if (payload.GetAvailableBytes() == 1)
+ {
+ /*"If only one byte remains unprocessed in the TS Packet payload
+ after completion of the Current SNDU, the Receiver MUST discard this
+ final byte of TS Packet payload."*/
+ break;
+ }
+
+ byte lengthByteA = payload.ReadUInt8();
+ bool destinationAddressAbsent = (lengthByteA & 0x80) != 0;
+
+ byte lengthByteB = payload.ReadUInt8();
+
+ int length = lengthByteA & 0x7f;
+ length <<= 8;
+ length += lengthByteB;
+ length += 2;
+
+ if (length == 0x8001)
+ {
+ break;
+ }
+
+ reassemblyMode = true;
+ reassemblyRemainingBytes = length;
+ reassemblyStream = new MemoryStream();
+ reassemblyStream.WriteUInt8(lengthByteA);
+ reassemblyStream.WriteUInt8(lengthByteB);
+ }
+ }
+ }
+
+ private void OnReassembledPacket(MemoryStream ms)
+ {
+ bool crc = DvbCrc32.ValidateCrc(ms, 0, (int)ms.Length);
+ if (!crc)
+ {
+ _eventHandler.OnUleError(_pid, 1);
+ return;
+ }
+
+ byte lengthByteA = ms.ReadUInt8();
+ bool destinationAddressAbsent = (lengthByteA & 0x80) != 0;
+ byte lengthBytesB = ms.ReadUInt8();
+
+ ushort typeField = ms.ReadUInt16BE();
+
+ PhysicalAddress destAddress = null;
+ if (!destinationAddressAbsent)
+ destAddress = new PhysicalAddress(ms.ReadBytes(6));
+
+ long packetSize = ms.GetAvailableBytes() - 4;
+ byte[] pdu = ms.ReadBytes(packetSize);
+ uint crc32 = ms.ReadUInt32BE();
+
+ switch (typeField)
+ {
+ case 1:
+ OnBridgedFrame(pdu);
+ break;
+ default:
+ throw new NotImplementedException(String.Format("ULE Type 0x{0:X4}", typeField));
+ }
+ }
+
+ private void OnBridgedFrame(byte[] pdu)
+ {
+ MemoryStream ms = new MemoryStream(pdu, false);
+ PhysicalAddress destination = new PhysicalAddress(ms.ReadBytes(6));
+ PhysicalAddress source = new PhysicalAddress(ms.ReadBytes(6));
+ ushort etherType = ms.ReadUInt16BE();
+ byte[] contents = ms.ReadBytes(ms.GetAvailableBytes());
+ //_eventHandler.OnEthernetFrame(_pid, destination, source, etherType, contents);
+ }
+
+ public void PacketLoss()
+ {
+ reassemblyMode = false;
+ reassemblyRemainingBytes = 0;
+ reassemblyStream = null;
+ }
+
+
+ }
+}