diff --git a/PacketDotNet/EthernetPacket.cs b/PacketDotNet/EthernetPacket.cs
index f4b2e434..3956334f 100644
--- a/PacketDotNet/EthernetPacket.cs
+++ b/PacketDotNet/EthernetPacket.cs
@@ -236,6 +236,9 @@ internal static PacketOrByteArraySegment ParseEncapsulatedBytes(ByteArraySegment
case EthernetPacketType.WakeOnLan:
payloadPacketOrData.ThePacket = new WakeOnLanPacket(payload);
break;
+ case EthernetPacketType.VLanTaggedFrame:
+ payloadPacketOrData.ThePacket = new Ieee8021QPacket(payload);
+ break;
default: // consider the sub-packet to be a byte array
payloadPacketOrData.TheByteArraySegment = payload;
break;
diff --git a/PacketDotNet/Ieee8021QFields.cs b/PacketDotNet/Ieee8021QFields.cs
new file mode 100644
index 00000000..00d4a01c
--- /dev/null
+++ b/PacketDotNet/Ieee8021QFields.cs
@@ -0,0 +1,42 @@
+/*
+This file is part of PacketDotNet
+
+PacketDotNet is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PacketDotNet is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with PacketDotNet. If not, see .
+*/
+/*
+ * Copyright 2013 Chris Morgan
+ */
+namespace PacketDotNet
+{
+ /// 802.1Q fields
+ public class Ieee8021QFields
+ {
+ /// Length of the ethertype value in bytes.
+ public readonly static int TypeLength = 2;
+ /// Length of the tag control information in bytes.
+ public readonly static int TagControlInformationLength = 2;
+ /// Position of the tag control information
+ public readonly static int TagControlInformationPosition = 0;
+ /// Position of the type field
+ public readonly static int TypePosition;
+ /// Length in bytes of a Ieee8021Q header.
+ public readonly static int HeaderLength; // 4
+
+ static Ieee8021QFields()
+ {
+ TypePosition = TagControlInformationPosition + TagControlInformationLength;
+ HeaderLength = TypePosition + TypeLength;
+ }
+ }
+}
diff --git a/PacketDotNet/Ieee8021QPacket.cs b/PacketDotNet/Ieee8021QPacket.cs
new file mode 100644
index 00000000..4019754e
--- /dev/null
+++ b/PacketDotNet/Ieee8021QPacket.cs
@@ -0,0 +1,226 @@
+/*
+This file is part of PacketDotNet
+
+PacketDotNet is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PacketDotNet is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with PacketDotNet. If not, see .
+*/
+/*
+ * Copyright 2013 Chris Morgan
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using MiscUtil.Conversion;
+using PacketDotNet.Utils;
+
+namespace PacketDotNet
+{
+ ///
+ /// 802.1Q vlan packet
+ /// http://en.wikipedia.org/wiki/IEEE_802.1Q
+ ///
+ [Serializable]
+ public class Ieee8021QPacket : InternetPacket
+ {
+ ///
+ /// Type of packet that this vlan packet encapsulates
+ ///
+ public virtual EthernetPacketType Type
+ {
+ get
+ {
+ return (EthernetPacketType)EndianBitConverter.Big.ToInt16(header.Bytes,
+ header.Offset + Ieee8021QFields.TypePosition);
+ }
+
+ set
+ {
+ Int16 val = (Int16)value;
+ EndianBitConverter.Big.CopyBytes(val,
+ header.Bytes,
+ header.Offset + Ieee8021QFields.TypePosition);
+ }
+ }
+
+ ///
+ /// Gets or sets the priority control point.
+ ///
+ ///
+ /// The priority control point.
+ ///
+ public IeeeP8021PPriorities PriorityControlPoint
+ {
+ get
+ {
+ var tci = TagControlInformation;
+ tci >>= (16 - 3); // priority is the upper 3 bits
+ return (IeeeP8021PPriorities)tci;
+ }
+
+ set
+ {
+ var tci = TagControlInformation;
+
+ // mask the existing Priority off and then back in from value
+ ushort val = (ushort)value;
+ tci = (ushort)((tci & 0x1FFF) | ((val & 0x7) << (16 - 3)));
+ TagControlInformation = tci;
+ }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether this instance canonical format indicator.
+ ///
+ ///
+ /// true if the mac address is in non-canonical format false if otherwise.
+ ///
+ public bool CanonicalFormatIndicator
+ {
+ get
+ {
+ var tci = TagControlInformation;
+ tci >>= 12;
+ return ((tci & 0x1) == 1) ? true : false;
+ }
+
+ set
+ {
+ var tci = TagControlInformation;
+
+ // mask the existing CFI off and then back in from value
+ int val = ((value == true) ? 1 : 0);
+ tci = (ushort)((tci & 0xEFFF) | (val << 12));
+ TagControlInformation = tci;
+ }
+ }
+
+ ///
+ /// Gets or sets the VLAN identifier.
+ ///
+ ///
+ /// The VLAN identifier.
+ ///
+ public ushort VLANIdentifier
+ {
+ get
+ {
+ var tci = TagControlInformation;
+ return (ushort)(tci & 0xFFF);
+ }
+
+ set
+ {
+ var tci = TagControlInformation;
+
+ // mask the existing vlan id off
+ tci = (ushort)((tci & 0xF000) | (value & 0xFFF));
+ TagControlInformation = tci;
+ }
+ }
+
+ private ushort TagControlInformation
+ {
+ get
+ {
+ return (ushort)EndianBitConverter.Big.ToInt16(header.Bytes,
+ header.Offset + Ieee8021QFields.TagControlInformationPosition);
+ }
+
+ set
+ {
+ Int16 val = (Int16)value;
+ EndianBitConverter.Big.CopyBytes(val,
+ header.Bytes,
+ header.Offset + Ieee8021QFields.TagControlInformationPosition);
+ }
+ }
+
+ /// Fetch ascii escape sequence of the color associated with this packet type.
+ override public System.String Color
+ {
+ get
+ {
+ return AnsiEscapeSequences.LightCyan;
+ }
+ }
+
+ ///
+ /// Constructor
+ ///
+ ///
+ /// A
+ ///
+ public Ieee8021QPacket(ByteArraySegment bas)
+ {
+ // set the header field, header field values are retrieved from this byte array
+ header = new ByteArraySegment(bas);
+ header.Length = Ieee8021QFields.HeaderLength;
+
+ // parse the payload via an EthernetPacket method
+ payloadPacketOrData = EthernetPacket.ParseEncapsulatedBytes(header,
+ Type);
+ }
+
+ ///
+ public override string ToString(StringOutputType outputFormat)
+ {
+ var buffer = new StringBuilder();
+ string color = "";
+ string colorEscape = "";
+
+ if(outputFormat == StringOutputType.Colored || outputFormat == StringOutputType.VerboseColored)
+ {
+ color = Color;
+ colorEscape = AnsiEscapeSequences.Reset;
+ }
+
+ if(outputFormat == StringOutputType.Normal || outputFormat == StringOutputType.Colored)
+ {
+ // build the output string
+ buffer.AppendFormat("{0}[Ieee8021QPacket: PriorityControlPoint={2}, CanonicalFormatIndicator={3}, Type={4}]{1}",
+ color,
+ colorEscape,
+ PriorityControlPoint,
+ CanonicalFormatIndicator,
+ Type);
+ }
+
+ if(outputFormat == StringOutputType.Verbose || outputFormat == StringOutputType.VerboseColored)
+ {
+ // collect the properties and their value
+ Dictionary properties = new Dictionary();
+ properties.Add("priority", PriorityControlPoint + " (0x" + PriorityControlPoint.ToString("x") + ")");
+ properties.Add("canonical format indicator", CanonicalFormatIndicator.ToString());
+ properties.Add("type", Type.ToString() + " (0x" + Type.ToString("x") + ")");
+ properties.Add ("VLANIdentifier", VLANIdentifier.ToString () + " (0x" + VLANIdentifier.ToString ("x") + ")");
+
+ // calculate the padding needed to right-justify the property names
+ int padLength = Utils.RandomUtils.LongestStringLength(new List(properties.Keys));
+
+ // build the output string
+ buffer.AppendLine("Ieee802.1Q: ******* Ieee802.1Q - \"VLan tag\" - offset=? length=" + TotalPacketLength);
+ buffer.AppendLine("Ieee802.1Q:");
+ foreach (var property in properties)
+ {
+ buffer.AppendLine("Ieee802.1Q: " + property.Key.PadLeft(padLength) + " = " + property.Value);
+ }
+ buffer.AppendLine("Ieee802.1Q:");
+ }
+
+ // append the base string output
+ buffer.Append(base.ToString(outputFormat));
+
+ return buffer.ToString();
+ }
+ }
+}
diff --git a/PacketDotNet/IeeeP8021PPriorities.cs b/PacketDotNet/IeeeP8021PPriorities.cs
new file mode 100644
index 00000000..de5d3ba1
--- /dev/null
+++ b/PacketDotNet/IeeeP8021PPriorities.cs
@@ -0,0 +1,63 @@
+/*
+This file is part of PacketDotNet
+
+PacketDotNet is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PacketDotNet is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with PacketDotNet. If not, see .
+*/
+/*
+ * Copyright 2013 Chris Morgan
+ */
+using System;
+
+namespace PacketDotNet
+{
+ ///
+ /// Ieee p8021 P priorities.
+ /// http://en.wikipedia.org/wiki/IEEE_802.1p
+ ///
+ public enum IeeeP8021PPriorities : byte
+ {
+ ///
+ /// Background
+ ///
+ Background_0 = 1,
+ ///
+ /// Best effort
+ ///
+ BestEffort_1 = 0,
+ ///
+ /// Excellent effort
+ ///
+ ExcellentEffort_2 = 2,
+ ///
+ /// Critical application
+ ///
+ CriticalApplications_3 = 3,
+ ///
+ /// Video, < 100ms latency and jitter
+ ///
+ Video_4 = 4,
+ ///
+ /// Voice, < 10ms latency and jitter
+ ///
+ Voice_5 = 5,
+ ///
+ /// Internetwork control
+ ///
+ InternetworkControl_6 = 6,
+ ///
+ /// Network control
+ ///
+ NetworkControl_7 = 7
+ }
+}
\ No newline at end of file
diff --git a/PacketDotNet/PacketDotNet.csproj b/PacketDotNet/PacketDotNet.csproj
index 307d17e7..80488a14 100644
--- a/PacketDotNet/PacketDotNet.csproj
+++ b/PacketDotNet/PacketDotNet.csproj
@@ -187,6 +187,9 @@
+
+
+
@@ -194,7 +197,7 @@
-
+
diff --git a/Test/CaptureFiles/802.1q_vlan_ipv4_tcp.pcap b/Test/CaptureFiles/802.1q_vlan_ipv4_tcp.pcap
new file mode 100644
index 00000000..0f8ed14e
Binary files /dev/null and b/Test/CaptureFiles/802.1q_vlan_ipv4_tcp.pcap differ
diff --git a/Test/PacketType/Vlan802_1QTest.cs b/Test/PacketType/Vlan802_1QTest.cs
new file mode 100644
index 00000000..7fc1ba8f
--- /dev/null
+++ b/Test/PacketType/Vlan802_1QTest.cs
@@ -0,0 +1,59 @@
+/*
+This file is part of PacketDotNet
+
+PacketDotNet is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PacketDotNet is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with PacketDotNet. If not, see .
+*/
+/*
+ * Copyright 2013 Chris Morgan
+ */
+
+using System;
+using NUnit.Framework;
+using PacketDotNet;
+using PacketDotNet.Utils;
+using SharpPcap;
+using SharpPcap.LibPcap;
+
+namespace Test.PacketType
+{
+ [TestFixture]
+ public class Vlan802_1QTest
+ {
+ ///
+ /// Test that a vlan packet can be properly parsed
+ ///
+ [Test]
+ public void ParsingVlanPacket()
+ {
+ Console.WriteLine("Loading the sample capture file");
+ var dev = new CaptureFileReaderDevice("../../CaptureFiles/802.1q_vlan_ipv4_tcp.pcap");
+ dev.Open();
+
+ Console.WriteLine("Reading packet data");
+ var rawCapture = dev.GetNextPacket();
+
+ Console.WriteLine("Parsing");
+ var p = Packet.ParsePacket(rawCapture.LinkLayerType, rawCapture.Data);
+
+ Console.WriteLine("Printing human readable string");
+ Console.WriteLine(p.ToString(StringOutputType.Verbose));
+
+ var vlanTag = (Ieee8021QPacket)p.Extract(typeof(Ieee8021QPacket));
+ Assert.AreEqual(IeeeP8021PPriorities.BestEffort_1, vlanTag.PriorityControlPoint);
+ var tagId = 102;
+ Assert.AreEqual(tagId, vlanTag.VLANIdentifier);
+ Assert.AreEqual(false, vlanTag.CanonicalFormatIndicator);
+ }
+ }
+}
diff --git a/Test/Test.csproj b/Test/Test.csproj
index 98c479ba..828a8e01 100644
--- a/Test/Test.csproj
+++ b/Test/Test.csproj
@@ -105,6 +105,7 @@
+