diff --git a/PacketDotNet/LinkLayers.cs b/PacketDotNet/LinkLayers.cs
index 54cb8d80..9524c933 100644
--- a/PacketDotNet/LinkLayers.cs
+++ b/PacketDotNet/LinkLayers.cs
@@ -162,5 +162,8 @@ public enum LinkLayers : ushort
IPv6 = 229,
/// Protocol for communication between host and guest machines in VMware and KVM hypervisors.
- VSock = 271
- }
+ VSock = 271,
+
+ /// Linux "cooked" capture encapsulation v2.
+ LinuxSll2 = 276,
+}
diff --git a/PacketDotNet/LinuxSll2Fields.cs b/PacketDotNet/LinuxSll2Fields.cs
new file mode 100644
index 00000000..6c77c087
--- /dev/null
+++ b/PacketDotNet/LinuxSll2Fields.cs
@@ -0,0 +1,102 @@
+/*
+This file is part of PacketDotNet.
+
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+namespace PacketDotNet;
+
+ ///
+ /// Lengths and offsets to the fields in the LinuxSll2 packet
+ /// See http://github.com/mcr/libpcap/blob/master/pcap/sll.h
+ ///
+ public struct LinuxSll2Fields
+ {
+ ///
+ /// Length of the ethernet protocol field
+ ///
+ public static readonly int EthernetProtocolTypeLength = 2;
+
+ ///
+ /// Position of the ethernet protocol type field
+ ///
+ public static readonly int EthernetProtocolTypePosition = 0;
+
+ ///
+ /// Link layer address length
+ ///
+ public static readonly int LinkLayerAddressLengthLength = 1;
+
+ ///
+ /// Positino of the link layer address length field
+ ///
+ public static readonly int LinkLayerAddressLengthPosition;
+
+ ///
+ /// The link layer address field length
+ /// NOTE: the actual link layer address MAY be shorter than this
+ ///
+ public static readonly int LinkLayerAddressMaximumLength = 8;
+
+ ///
+ /// Position of the link layer address field
+ ///
+ public static readonly int LinkLayerAddressPosition;
+
+ ///
+ /// Link layer address type
+ ///
+ public static readonly int LinkLayerAddressTypeLength = 2;
+
+ ///
+ /// Position of the link layer address type field
+ ///
+ public static readonly int LinkLayerAddressTypePosition;
+
+ ///
+ /// Length of the packet type field
+ ///
+ public static readonly int PacketTypeLength = 1;
+
+ ///
+ /// Position of the packet type field
+ ///
+ public static readonly int PacketTypePosition;
+
+ ///
+ /// Reserved (MBZ)
+ ///
+ public static readonly int ReservedMBZLength = 2;
+
+ ///
+ /// Position of the Reserved (MBZ) field
+ ///
+ public static readonly int ReservedMBZPosition = 0;
+
+ ///
+ /// Length of the interface index field
+ ///
+ public static readonly int InterfaceIndexLength = 4;
+
+ ///
+ /// Position of the interface index field
+ ///
+ public static readonly int InterfaceIndexPosition = 0;
+
+ ///
+ /// Number of bytes in a SLL2 header
+ ///
+ public static readonly int SLL2HeaderLength = 20;
+
+ static LinuxSll2Fields()
+ {
+ ReservedMBZPosition = EthernetProtocolTypePosition + EthernetProtocolTypeLength;
+ InterfaceIndexPosition = ReservedMBZPosition + ReservedMBZLength;
+ LinkLayerAddressTypePosition = InterfaceIndexPosition + InterfaceIndexLength;
+ PacketTypePosition = LinkLayerAddressTypePosition + LinkLayerAddressTypeLength;
+ LinkLayerAddressLengthPosition = PacketTypePosition + PacketTypeLength;
+ LinkLayerAddressPosition = LinkLayerAddressLengthPosition + LinkLayerAddressLengthLength;
+ }
+ }
\ No newline at end of file
diff --git a/PacketDotNet/LinuxSll2Packet.cs b/PacketDotNet/LinuxSll2Packet.cs
new file mode 100644
index 00000000..c6145623
--- /dev/null
+++ b/PacketDotNet/LinuxSll2Packet.cs
@@ -0,0 +1,207 @@
+/*
+This file is part of PacketDotNet.
+
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using PacketDotNet.Utils;
+using PacketDotNet.Utils.Converters;
+
+namespace PacketDotNet;
+
+ ///
+ /// Represents a Linux cooked capture packet, the kinds of packets
+ /// received when capturing on an 'any' device
+ /// See http://github.com/mcr/libpcap/blob/master/pcap/sll.h
+ ///
+ public class LinuxSll2Packet : InternetLinkLayerPacket
+ {
+ ///
+ /// Constructor
+ ///
+ ///
+ /// A
+ ///
+ public LinuxSll2Packet(ByteArraySegment byteArraySegment)
+ {
+ Header = new ByteArraySegment(byteArraySegment) { Length = LinuxSll2Fields.SLL2HeaderLength };
+
+ // parse the payload via an EthernetPacket method
+ PayloadPacketOrData = new LazySlim(() => EthernetPacket.ParseNextSegment(Header,
+ EthernetProtocolType));
+ }
+
+ ///
+ /// The encapsulated protocol type
+ ///
+ public EthernetType EthernetProtocolType
+ {
+ get => (EthernetType) EndianBitConverter.Big.ToInt16(Header.Bytes,
+ Header.Offset + LinuxSll2Fields.EthernetProtocolTypePosition);
+ set
+ {
+ var v = (short) value;
+ EndianBitConverter.Big.CopyBytes(v,
+ Header.Bytes,
+ Header.Offset + LinuxSll2Fields.EthernetProtocolTypePosition);
+ }
+ }
+
+ ///
+ /// Link layer header bytes, maximum of 8 bytes
+ ///
+ public byte[] LinkLayerAddress
+ {
+ get
+ {
+ var headerLength = LinkLayerAddressLength;
+ var theHeader = new byte[headerLength];
+ Array.Copy(Header.Bytes,
+ Header.Offset + LinuxSll2Fields.LinkLayerAddressPosition,
+ theHeader,
+ 0,
+ headerLength);
+
+ return theHeader;
+ }
+ set
+ {
+ // update the link layer length
+ LinkLayerAddressLength = value.Length;
+
+ // copy in the new link layer header bytes
+ Array.Copy(value,
+ 0,
+ Header.Bytes,
+ Header.Offset + LinuxSll2Fields.LinkLayerAddressPosition,
+ value.Length);
+ }
+ }
+
+ ///
+ /// Number of bytes in the link layer address of the sender of the packet
+ ///
+ public int LinkLayerAddressLength
+ {
+ get => Header.Bytes[Header.Offset + LinuxSll2Fields.LinkLayerAddressLengthPosition];
+ set
+ {
+ // range check
+ if (value is < 0 or > 8)
+ {
+ throw new InvalidOperationException("value of " + value + " out of range of 0 to 8");
+ }
+
+ Header.Bytes[Header.Offset + LinuxSll2Fields.LinkLayerAddressLengthPosition] = (byte) value;
+ }
+ }
+
+ ///
+ /// The
+ ///
+ public int LinkLayerAddressType
+ {
+ get => EndianBitConverter.Big.ToInt16(Header.Bytes,
+ Header.Offset + LinuxSll2Fields.LinkLayerAddressTypePosition);
+ set
+ {
+ var v = (short) value;
+ EndianBitConverter.Big.CopyBytes(v,
+ Header.Bytes,
+ Header.Offset + LinuxSll2Fields.LinkLayerAddressTypePosition);
+ }
+ }
+
+ ///
+ /// Information about the packet direction
+ ///
+ public LinuxSll2Type Type
+ {
+ get => (LinuxSll2Type)Header.Bytes[Header.Offset + LinuxSll2Fields.PacketTypePosition];
+ set
+ {
+ Header.Bytes[Header.Offset + LinuxSll2Fields.PacketTypePosition] = (byte) value;
+ }
+ }
+
+ ///
+ /// Information about the interface index
+ ///
+ public int InterfaceIndex
+ {
+ get => EndianBitConverter.Big.ToInt32(Header.Bytes,
+ Header.Offset + LinuxSll2Fields.InterfaceIndexPosition);
+ set
+ {
+ var v = (int)value;
+ EndianBitConverter.Big.CopyBytes(v,
+ Header.Bytes,
+ Header.Offset + LinuxSll2Fields.InterfaceIndexPosition);
+ }
+ }
+
+ ///
+ public override string ToString(StringOutputType outputFormat)
+ {
+ var buffer = new StringBuilder();
+ var color = "";
+ var colorEscape = "";
+
+ if (outputFormat is StringOutputType.Colored or StringOutputType.VerboseColored)
+ {
+ color = Color;
+ colorEscape = AnsiEscapeSequences.Reset;
+ }
+
+ if (outputFormat is StringOutputType.Normal or StringOutputType.Colored)
+ {
+ // build the output string
+ buffer.AppendFormat("[{0}LinuxSll2Packet{1}: ProtocolType={2}, InterfaceIndex={3}, LinkLayerAddressType={4}, Type={5}, LinkLayerAddressLength={6}, Source={7}]",
+ color,
+ colorEscape,
+ EthernetProtocolType,
+ InterfaceIndex,
+ LinkLayerAddressType,
+ Type,
+ LinkLayerAddressLength,
+ BitConverter.ToString(LinkLayerAddress, 0));
+ }
+
+ if (outputFormat is StringOutputType.Verbose or StringOutputType.VerboseColored)
+ {
+ // collect the properties and their value
+ var properties = new Dictionary
+ {
+ { "protocol", EthernetProtocolType + " (0x" + EthernetProtocolType.ToString("x") + ")" },
+ { "interface index", InterfaceIndex.ToString() },
+ { "link layer address type", LinkLayerAddressType.ToString() },
+ { "type", Type + " (" + (int) Type + ")" },
+ { "link layer address length", LinkLayerAddressLength.ToString() },
+ { "source", BitConverter.ToString(LinkLayerAddress) },
+ };
+
+ // calculate the padding needed to right-justify the property names
+ var padLength = RandomUtils.LongestStringLength(new List(properties.Keys));
+
+ // build the output string
+ buffer.AppendLine("LCC: ******* LinuxSll2 - \"Linux Cooked Capture v2\" - offset=? length=" + TotalPacketLength);
+ buffer.AppendLine("LCC:");
+ foreach (var property in properties)
+ {
+ buffer.AppendLine("LCC: " + property.Key.PadLeft(padLength) + " = " + property.Value);
+ }
+
+ buffer.AppendLine("LCC:");
+ }
+
+ // append the base output
+ buffer.Append(base.ToString(outputFormat));
+
+ return buffer.ToString();
+ }
+ }
\ No newline at end of file
diff --git a/PacketDotNet/LinuxSll2Type.cs b/PacketDotNet/LinuxSll2Type.cs
new file mode 100644
index 00000000..9d22d908
--- /dev/null
+++ b/PacketDotNet/LinuxSll2Type.cs
@@ -0,0 +1,41 @@
+/*
+This file is part of PacketDotNet.
+
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+namespace PacketDotNet;
+
+ ///
+ /// The types of cooked packets v2
+ /// See http://github.com/mcr/libpcap/blob/master/pcap/sll.h
+ ///
+ public enum LinuxSll2Type
+ {
+ ///
+ /// Packet was sent to us by somebody else
+ ///
+ PacketSentToUs = 0x0,
+
+ ///
+ /// Packet was broadcast by somebody else
+ ///
+ PacketBroadCast = 0x1,
+
+ ///
+ /// Packet was multicast, but not broadcast
+ ///
+ PacketMulticast = 0x2,
+
+ ///
+ /// Packet was sent by somebody else to somebody else
+ ///
+ PacketSentToSomeoneElse = 0x3,
+
+ ///
+ /// Packet was sent by us
+ ///
+ PacketSentByUs = 0x4
+ }
\ No newline at end of file
diff --git a/PacketDotNet/Packet.cs b/PacketDotNet/Packet.cs
index 07434638..63f885d9 100644
--- a/PacketDotNet/Packet.cs
+++ b/PacketDotNet/Packet.cs
@@ -339,6 +339,11 @@ public static Packet ParsePacket(LinkLayers linkLayers, byte[] packetData)
p = new LinuxSllPacket(byteArraySegment);
break;
}
+ case LinkLayers.LinuxSll2:
+ {
+ p = new LinuxSll2Packet(byteArraySegment);
+ break;
+ }
case LinkLayers.Null:
{
p = new NullPacket(byteArraySegment);