// Copyright 2012, Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

package layers

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"net"
	"reflect"
	"strings"
	"testing"

	"github.com/gopacket/gopacket"
	"github.com/gopacket/gopacket/bytediff"
)

var testSimpleTCPPacket = []byte{
	0x00, 0x00, 0x0c, 0x9f, 0xf0, 0x20, 0xbc, 0x30, 0x5b, 0xe8, 0xd3, 0x49,
	0x08, 0x00, 0x45, 0x00, 0x01, 0xa4, 0x39, 0xdf, 0x40, 0x00, 0x40, 0x06,
	0x55, 0x5a, 0xac, 0x11, 0x51, 0x49, 0xad, 0xde, 0xfe, 0xe1, 0xc5, 0xf7,
	0x00, 0x50, 0xc5, 0x7e, 0x0e, 0x48, 0x49, 0x07, 0x42, 0x32, 0x80, 0x18,
	0x00, 0x73, 0x9a, 0x8f, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x03, 0x77,
	0x37, 0x9c, 0x42, 0x77, 0x5e, 0x3a, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x20,
	0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f,
	0x73, 0x74, 0x3a, 0x20, 0x77, 0x77, 0x77, 0x2e, 0x66, 0x69, 0x73, 0x68,
	0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
	0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x6b, 0x65, 0x65, 0x70, 0x2d, 0x61,
	0x6c, 0x69, 0x76, 0x65, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41,
	0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c,
	0x61, 0x2f, 0x35, 0x2e, 0x30, 0x20, 0x28, 0x58, 0x31, 0x31, 0x3b, 0x20,
	0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x78, 0x38, 0x36, 0x5f, 0x36, 0x34,
	0x29, 0x20, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x57, 0x65, 0x62, 0x4b, 0x69,
	0x74, 0x2f, 0x35, 0x33, 0x35, 0x2e, 0x32, 0x20, 0x28, 0x4b, 0x48, 0x54,
	0x4d, 0x4c, 0x2c, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x47, 0x65, 0x63,
	0x6b, 0x6f, 0x29, 0x20, 0x43, 0x68, 0x72, 0x6f, 0x6d, 0x65, 0x2f, 0x31,
	0x35, 0x2e, 0x30, 0x2e, 0x38, 0x37, 0x34, 0x2e, 0x31, 0x32, 0x31, 0x20,
	0x53, 0x61, 0x66, 0x61, 0x72, 0x69, 0x2f, 0x35, 0x33, 0x35, 0x2e, 0x32,
	0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x74, 0x65,
	0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c,
	0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x68, 0x74, 0x6d,
	0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63,
	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x6d, 0x6c, 0x3b, 0x71, 0x3d,
	0x30, 0x2e, 0x39, 0x2c, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, 0x2e,
	0x38, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e,
	0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, 0x69, 0x70,
	0x2c, 0x64, 0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, 0x63,
	0x68, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, 0x61,
	0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x65, 0x6e, 0x2d, 0x55,
	0x53, 0x2c, 0x65, 0x6e, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x38, 0x0d, 0x0a,
	0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x43, 0x68, 0x61, 0x72, 0x73,
	0x65, 0x74, 0x3a, 0x20, 0x49, 0x53, 0x4f, 0x2d, 0x38, 0x38, 0x35, 0x39,
	0x2d, 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x3b, 0x71, 0x3d, 0x30,
	0x2e, 0x37, 0x2c, 0x2a, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x33, 0x0d, 0x0a,
	0x0d, 0x0a,
}

var testDecodeOptions = gopacket.DecodeOptions{
	SkipDecodeRecovery: true,
}

// Benchmarks for actual gopacket code

func BenchmarkLayerClassSliceContains(b *testing.B) {
	lc := gopacket.NewLayerClassSlice([]gopacket.LayerType{LayerTypeTCP, LayerTypeEthernet})
	for i := 0; i < b.N; i++ {
		_ = lc.Contains(LayerTypeTCP)
	}
}

func BenchmarkLayerClassMapContains(b *testing.B) {
	lc := gopacket.NewLayerClassMap([]gopacket.LayerType{LayerTypeTCP, LayerTypeEthernet})
	for i := 0; i < b.N; i++ {
		_ = lc.Contains(LayerTypeTCP)
	}
}

func BenchmarkLazyNoCopyEthLayer(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, gopacket.DecodeOptions{Lazy: true, NoCopy: true}).Layer(LayerTypeEthernet)
	}
}

func BenchmarkLazyNoCopyIPLayer(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, gopacket.DecodeOptions{Lazy: true, NoCopy: true}).Layer(LayerTypeIPv4)
	}
}

func BenchmarkLazyNoCopyTCPLayer(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, gopacket.DecodeOptions{Lazy: true, NoCopy: true}).Layer(LayerTypeTCP)
	}
}

func BenchmarkLazyNoCopyAllLayers(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, gopacket.DecodeOptions{Lazy: true, NoCopy: true}).Layers()
	}
}

func BenchmarkDefault(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, gopacket.Default)
	}
}

func getSerializeLayers() []gopacket.SerializableLayer {
	p := gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, testDecodeOptions)
	slayers := []gopacket.SerializableLayer{}
	for _, l := range p.Layers() {
		slayers = append(slayers, l.(gopacket.SerializableLayer))
	}
	p.Layer(LayerTypeTCP).(*TCP).SetNetworkLayerForChecksum(
		p.NetworkLayer())
	return slayers
}

func BenchmarkSerializeTcpNoOptions(b *testing.B) {
	slayers := getSerializeLayers()
	buf := gopacket.NewSerializeBuffer()
	opts := gopacket.SerializeOptions{}
	for i := 0; i < b.N; i++ {
		gopacket.SerializeLayers(buf, opts, slayers...)
	}
}

func BenchmarkSerializeTcpFixLengths(b *testing.B) {
	slayers := getSerializeLayers()
	buf := gopacket.NewSerializeBuffer()
	opts := gopacket.SerializeOptions{FixLengths: true}
	for i := 0; i < b.N; i++ {
		gopacket.SerializeLayers(buf, opts, slayers...)
	}
}

func BenchmarkSerializeTcpComputeChecksums(b *testing.B) {
	slayers := getSerializeLayers()
	buf := gopacket.NewSerializeBuffer()
	opts := gopacket.SerializeOptions{ComputeChecksums: true}
	for i := 0; i < b.N; i++ {
		gopacket.SerializeLayers(buf, opts, slayers...)
	}
}

func BenchmarkSerializeTcpFixLengthsComputeChecksums(b *testing.B) {
	slayers := getSerializeLayers()
	buf := gopacket.NewSerializeBuffer()
	opts := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}
	for i := 0; i < b.N; i++ {
		gopacket.SerializeLayers(buf, opts, slayers...)
	}
}

func BenchmarkLazy(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, gopacket.Lazy)
	}
}

func BenchmarkNoCopy(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, gopacket.NoCopy)
	}
}

func BenchmarkLazyNoCopy(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, gopacket.DecodeOptions{Lazy: true, NoCopy: true})
	}
}

func BenchmarkKnownStack(b *testing.B) {
	stack := []gopacket.DecodingLayer{&Ethernet{}, &IPv4{}, &TCP{}, &gopacket.Payload{}}
	nf := gopacket.NilDecodeFeedback
	for i := 0; i < b.N; i++ {
		data := testSimpleTCPPacket[:]
		for _, d := range stack {
			_ = d.DecodeFromBytes(data, nf)
			data = d.LayerPayload()
		}
	}
}

func BenchmarkDecodingLayerParserIgnorePanic(b *testing.B) {
	decoded := make([]gopacket.LayerType, 0, 20)
	dlp := gopacket.NewDecodingLayerParser(LayerTypeEthernet, &Ethernet{}, &IPv4{}, &TCP{}, &gopacket.Payload{})
	dlp.IgnorePanic = true
	for i := 0; i < b.N; i++ {
		dlp.DecodeLayers(testSimpleTCPPacket, &decoded)
	}
}

func BenchmarkDecodingLayerParserHandlePanic(b *testing.B) {
	decoded := make([]gopacket.LayerType, 0, 20)
	dlp := gopacket.NewDecodingLayerParser(LayerTypeEthernet, &Ethernet{}, &IPv4{}, &TCP{}, &gopacket.Payload{})
	dlp.IgnorePanic = false
	for i := 0; i < b.N; i++ {
		dlp.DecodeLayers(testSimpleTCPPacket, &decoded)
	}
}

func benchmarkDecodingLayerParser(b *testing.B, dlc gopacket.DecodingLayerContainer, ignorePanic bool) {
	decoded := make([]gopacket.LayerType, 0, 20)
	dlc = dlc.Put(&Ethernet{})
	dlc = dlc.Put(&IPv4{})
	dlc = dlc.Put(&TCP{})
	dlc = dlc.Put(&gopacket.Payload{})
	dlp := gopacket.NewDecodingLayerParser(LayerTypeEthernet)
	dlp.SetDecodingLayerContainer(dlc)
	dlp.IgnorePanic = ignorePanic
	for i := 0; i < b.N; i++ {
		dlp.DecodeLayers(testSimpleTCPPacket, &decoded)
	}
}

func BenchmarkDecodingLayerParserSparseIgnorePanic(b *testing.B) {
	benchmarkDecodingLayerParser(b, gopacket.DecodingLayerSparse(nil), true)
}

func BenchmarkDecodingLayerParserSparseHandlePanic(b *testing.B) {
	benchmarkDecodingLayerParser(b, gopacket.DecodingLayerSparse(nil), false)
}

func BenchmarkDecodingLayerParserArrayIgnorePanic(b *testing.B) {
	benchmarkDecodingLayerParser(b, gopacket.DecodingLayerArray(nil), true)
}

func BenchmarkDecodingLayerParserArrayHandlePanic(b *testing.B) {
	benchmarkDecodingLayerParser(b, gopacket.DecodingLayerArray(nil), false)
}

func BenchmarkDecodingLayerParserMapIgnorePanic(b *testing.B) {
	benchmarkDecodingLayerParser(b, gopacket.DecodingLayerMap(nil), true)
}

func BenchmarkDecodingLayerParserMapHandlePanic(b *testing.B) {
	benchmarkDecodingLayerParser(b, gopacket.DecodingLayerMap(nil), false)
}

func benchmarkDecodingLayerContainer(b *testing.B, dlc gopacket.DecodingLayerContainer) {
	decoded := make([]gopacket.LayerType, 0, 20)
	dlc = dlc.Put(&Ethernet{})
	dlc = dlc.Put(&IPv4{})
	dlc = dlc.Put(&TCP{})
	dlc = dlc.Put(&gopacket.Payload{})
	df := gopacket.NewDecodingLayerParser(LayerTypeEthernet)
	decoder := dlc.LayersDecoder(LayerTypeEthernet, df)
	for i := 0; i < b.N; i++ {
		decoder(testSimpleTCPPacket, &decoded)
	}
}

func BenchmarkDecodingLayerArray(b *testing.B) {
	benchmarkDecodingLayerContainer(b, gopacket.DecodingLayerArray(nil))
}

func BenchmarkDecodingLayerMap(b *testing.B) {
	benchmarkDecodingLayerContainer(b, gopacket.DecodingLayerMap(nil))
}

func BenchmarkDecodingLayerSparse(b *testing.B) {
	benchmarkDecodingLayerContainer(b, gopacket.DecodingLayerSparse(nil))
}

func BenchmarkAlloc(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = &TCP{}
	}
}

func BenchmarkFlow(b *testing.B) {
	p := gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, gopacket.DecodeOptions{Lazy: true, NoCopy: true})
	net := p.NetworkLayer()
	for i := 0; i < b.N; i++ {
		net.NetworkFlow()
	}
}

func BenchmarkEndpoints(b *testing.B) {
	p := gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, gopacket.DecodeOptions{Lazy: true, NoCopy: true})
	flow := p.NetworkLayer().NetworkFlow()
	for i := 0; i < b.N; i++ {
		flow.Endpoints()
	}
}

func BenchmarkTCPLayerFromDecodedPacket(b *testing.B) {
	b.StopTimer()
	p := gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, testDecodeOptions)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		_ = p.Layer(LayerTypeTCP)
	}
}

func BenchmarkTCPLayerClassFromDecodedPacket(b *testing.B) {
	b.StopTimer()
	p := gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, testDecodeOptions)
	lc := gopacket.NewLayerClass([]gopacket.LayerType{LayerTypeTCP})
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		_ = p.LayerClass(lc)
	}
}

func BenchmarkTCPTransportLayerFromDecodedPacket(b *testing.B) {
	b.StopTimer()
	p := gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, testDecodeOptions)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		_ = p.TransportLayer()
	}
}

func testDecoder([]byte, gopacket.PacketBuilder) error {
	return nil
}

func BenchmarkDecodeFuncCallOverheadDirectCall(b *testing.B) {
	var data []byte
	var pb gopacket.PacketBuilder
	for i := 0; i < b.N; i++ {
		_ = testDecoder(data, pb)
	}
}

func BenchmarkDecodeFuncCallOverheadDecoderCall(b *testing.B) {
	d := gopacket.DecodeFunc(testDecoder)
	var data []byte
	var pb gopacket.PacketBuilder
	for i := 0; i < b.N; i++ {
		_ = d.Decode(data, pb)
	}
}

func BenchmarkDecodeFuncCallOverheadArrayCall(b *testing.B) {
	EthernetTypeMetadata[1] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(testDecoder)}
	d := EthernetType(1)
	var data []byte
	var pb gopacket.PacketBuilder
	for i := 0; i < b.N; i++ {
		_ = d.Decode(data, pb)
	}
}

func BenchmarkFmtVerboseString(b *testing.B) {
	b.StopTimer()
	p := gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, testDecodeOptions)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		_ = fmt.Sprintf("%#v", p)
	}
}

func BenchmarkPacketString(b *testing.B) {
	b.StopTimer()
	p := gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, testDecodeOptions)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		_ = p.String()
	}
}

func BenchmarkPacketDumpString(b *testing.B) {
	b.StopTimer()
	p := gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, testDecodeOptions)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		_ = p.String()
	}
}

// TestFlowMapKey makes sure a flow and an endpoint can be used as map keys.
func TestFlowMapKey(t *testing.T) {
	_ = map[gopacket.Flow]bool{}
	_ = map[gopacket.Endpoint]bool{}
	_ = map[[2]gopacket.Flow]bool{}
}

func TestDecodeSimpleTCPPacket(t *testing.T) {
	equal := func(desc, want string, got fmt.Stringer) {
		if want != got.String() {
			t.Errorf("%s: got %q want %q", desc, got.String(), want)
		}
	}
	p := gopacket.NewPacket(testSimpleTCPPacket, LinkTypeEthernet, gopacket.DecodeOptions{Lazy: true, NoCopy: true})
	if eth := p.LinkLayer(); eth == nil {
		t.Error("No ethernet layer found")
	} else {
		equal("Eth Src", "bc:30:5b:e8:d3:49", eth.LinkFlow().Src())
		equal("Eth Dst", "00:00:0c:9f:f0:20", eth.LinkFlow().Dst())
	}
	if net := p.NetworkLayer(); net == nil {
		t.Error("No net layer found")
	} else if ip, ok := net.(*IPv4); !ok {
		t.Error("Net layer is not IP layer")
	} else {
		equal("IP Src", "172.17.81.73", net.NetworkFlow().Src())
		equal("IP Dst", "173.222.254.225", net.NetworkFlow().Dst())
		want := &IPv4{
			BaseLayer:  BaseLayer{testSimpleTCPPacket[14:34], testSimpleTCPPacket[34:]},
			Version:    4,
			IHL:        5,
			TOS:        0,
			Length:     420,
			Id:         14815,
			Flags:      0x02,
			FragOffset: 0,
			TTL:        64,
			Protocol:   6,
			Checksum:   0x555A,
			SrcIP:      []byte{172, 17, 81, 73},
			DstIP:      []byte{173, 222, 254, 225},
		}
		if !reflect.DeepEqual(ip, want) {
			t.Errorf("IP layer mismatch, \ngot  %#v\nwant %#v\n", ip, want)
		}
	}
	if trans := p.TransportLayer(); trans == nil {
		t.Error("No transport layer found")
	} else if tcp, ok := trans.(*TCP); !ok {
		t.Error("Transport layer is not TCP layer")
	} else {
		equal("TCP Src", "50679", trans.TransportFlow().Src())
		equal("TCP Dst", "80", trans.TransportFlow().Dst())
		want := &TCP{
			BaseLayer:  BaseLayer{testSimpleTCPPacket[34:66], testSimpleTCPPacket[66:]},
			SrcPort:    50679,
			DstPort:    80,
			Seq:        0xc57e0e48,
			Ack:        0x49074232,
			DataOffset: 8,
			ACK:        true,
			PSH:        true,
			Window:     0x73,
			Checksum:   0x9a8f,
			Urgent:     0,
			sPort:      []byte{0xc5, 0xf7},
			dPort:      []byte{0x0, 0x50},
			Options: []TCPOption{
				TCPOption{
					OptionType:   0x1,
					OptionLength: 0x1,
				},
				TCPOption{
					OptionType:   0x1,
					OptionLength: 0x1,
				},
				TCPOption{
					OptionType:   0x8,
					OptionLength: 0xa,
					OptionData:   []byte{0x3, 0x77, 0x37, 0x9c, 0x42, 0x77, 0x5e, 0x3a},
				},
			},
			opts: [4]TCPOption{
				TCPOption{
					OptionType:   0x1,
					OptionLength: 0x1,
				},
				TCPOption{
					OptionType:   0x1,
					OptionLength: 0x1,
				},
				TCPOption{
					OptionType:   0x8,
					OptionLength: 0xa,
					OptionData:   []byte{0x3, 0x77, 0x37, 0x9c, 0x42, 0x77, 0x5e, 0x3a},
				},
				TCPOption{},
			},
		}
		if !reflect.DeepEqual(tcp, want) {
			t.Errorf("TCP layer mismatch\ngot  %#v\nwant %#v", tcp, want)
		}
	}
	if payload, ok := p.Layer(gopacket.LayerTypePayload).(*gopacket.Payload); payload == nil || !ok {
		t.Error("No payload layer found")
	} else {
		if string(payload.Payload()) != "GET / HTTP/1.1\r\nHost: www.fish.com\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n\r\n" {
			t.Error("--- Payload STRING ---\n", string(payload.Payload()), "\n--- Payload BYTES ---\n", payload.Payload())
		}
	}

	// Test re-serialization.
	testSerialization(t, p, testSimpleTCPPacket)
}

type canSetNetLayer interface {
	SetNetworkLayerForChecksum(gopacket.NetworkLayer) error
}

func testSerialization(t *testing.T, p gopacket.Packet, data []byte) {
	for _, opts := range []gopacket.SerializeOptions{
		gopacket.SerializeOptions{},
		gopacket.SerializeOptions{FixLengths: true},
		gopacket.SerializeOptions{ComputeChecksums: true},
		gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true},
	} {
		testSerializationWithOpts(t, p, data, opts)
	}
}

func testSerializationWithOpts(t *testing.T, p gopacket.Packet, data []byte, opts gopacket.SerializeOptions) {
	// Test re-serialization.
	slayers := []gopacket.SerializableLayer{}
	for _, l := range p.Layers() {
		slayers = append(slayers, l.(gopacket.SerializableLayer))
		if h, ok := l.(canSetNetLayer); ok {
			if err := h.SetNetworkLayerForChecksum(p.NetworkLayer()); err != nil {
				t.Fatal("can't set network layer:", err)
			}
		}
	}
	buf := gopacket.NewSerializeBuffer()
	err := gopacket.SerializeLayers(buf, opts, slayers...)
	if err != nil {
		t.Errorf("unable to reserialize layers with opts %#v: %v", opts, err)
	} else if !bytes.Equal(buf.Bytes(), data) {
		t.Errorf("serialization failure with opts %#v:\n---want---\n%v\n---got---\n%v\nBASH-colorized diff, want->got:\n%v\n\n---PACKET---\n%v",
			opts, hex.Dump(data), hex.Dump(buf.Bytes()), bytediff.BashOutput.String(bytediff.Diff(data, buf.Bytes())), p)
	}
}

// Makes sure packet payload doesn't display the 6 trailing null of this packet
// as part of the payload.  They're actually the ethernet trailer.
func TestDecodeSmallTCPPacketHasEmptyPayload(t *testing.T) {
	smallPacket := []byte{
		0xbc, 0x30, 0x5b, 0xe8, 0xd3, 0x49, 0xb8, 0xac, 0x6f, 0x92, 0xd5, 0xbf,
		0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06,
		0x3f, 0x9f, 0xac, 0x11, 0x51, 0xc5, 0xac, 0x11, 0x51, 0x49, 0x00, 0x63,
		0x9a, 0xef, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xc1, 0x27, 0x83, 0x50, 0x14,
		0x00, 0x00, 0xc3, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	}
	p := gopacket.NewPacket(smallPacket, LinkTypeEthernet, testDecodeOptions)

	if payload := p.Layer(gopacket.LayerTypePayload); payload != nil {
		t.Error("Payload found for empty TCP packet")
	}

	testSerialization(t, p, smallPacket)
}

func TestDecodeVLANPacket(t *testing.T) {
	p := gopacket.NewPacket(
		[]byte{
			0x00, 0x10, 0xdb, 0xff, 0x10, 0x00, 0x00, 0x15, 0x2c, 0x9d, 0xcc, 0x00,
			0x81, 0x00, 0x01, 0xf7, 0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0x29, 0x8d,
			0x40, 0x00, 0x7d, 0x06, 0x83, 0xa0, 0xac, 0x1b, 0xca, 0x8e, 0x45, 0x16,
			0x94, 0xe2, 0xd4, 0x0a, 0x00, 0x50, 0xdf, 0xab, 0x9c, 0xc6, 0xcd, 0x1e,
			0xe5, 0xd1, 0x50, 0x10, 0x01, 0x00, 0x5a, 0x74, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00,
		}, LinkTypeEthernet, testDecodeOptions)
	if err := p.ErrorLayer(); err != nil {
		t.Error("Error while parsing vlan packet:", err)
	}
	if vlan := p.Layer(LayerTypeDot1Q); vlan == nil {
		t.Error("Didn't detect vlan")
	} else if _, ok := vlan.(*Dot1Q); !ok {
		t.Error("LayerTypeDot1Q layer is not a Dot1Q object")
	}
	for i, l := range p.Layers() {
		t.Logf("Layer %d: %#v", i, l)
	}
	want := []gopacket.LayerType{LayerTypeEthernet, LayerTypeDot1Q, LayerTypeIPv4, LayerTypeTCP}
	checkLayers(p, want, t)
}

func TestDecodeSCTPPackets(t *testing.T) {
	sctpPackets := [][]byte{
		[]byte{ // INIT
			0x00, 0x00, 0x0c, 0x9f, 0xf0, 0x1f, 0x24, 0xbe, 0x05, 0x27, 0x0b, 0x17, 0x08, 0x00, 0x45, 0x02,
			0x00, 0x44, 0x00, 0x00, 0x40, 0x00, 0x40, 0x84, 0xc4, 0x22, 0xac, 0x1d, 0x14, 0x0f, 0xac, 0x19,
			0x09, 0xcc, 0x27, 0x0f, 0x22, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x19, 0x6b, 0x0b, 0x40, 0x01, 0x00,
			0x00, 0x24, 0xb6, 0x96, 0xb0, 0x9e, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xdb, 0x85,
			0x60, 0x23, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0xc0, 0x00,
			0x00, 0x04,
		}, []byte{ // INIT ACK
			0x24, 0xbe, 0x05, 0x27, 0x0b, 0x17, 0x00, 0x1f, 0xca, 0xb3, 0x76, 0x40, 0x08, 0x00, 0x45, 0x20,
			0x01, 0x24, 0x00, 0x00, 0x40, 0x00, 0x36, 0x84, 0xcd, 0x24, 0xac, 0x19, 0x09, 0xcc, 0xac, 0x1d,
			0x14, 0x0f, 0x22, 0xb8, 0x27, 0x0f, 0xb6, 0x96, 0xb0, 0x9e, 0x4b, 0xab, 0x40, 0x9a, 0x02, 0x00,
			0x01, 0x04, 0x32, 0x80, 0xfb, 0x42, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x85, 0x98,
			0xb1, 0x26, 0x00, 0x07, 0x00, 0xe8, 0xd3, 0x08, 0xce, 0xe2, 0x52, 0x95, 0xcc, 0x09, 0xa1, 0x4c,
			0x6f, 0xa7, 0x9e, 0xba, 0x03, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfb, 0x80, 0x32, 0x9e, 0xb0,
			0x96, 0xb6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x46, 0xc2, 0x50, 0x00, 0x00,
			0x00, 0x00, 0x5e, 0x25, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x26, 0xb1,
			0x98, 0x85, 0x02, 0x00, 0x27, 0x0f, 0xac, 0x1d, 0x14, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x22,
			0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x24, 0x6a, 0x72, 0x5c, 0x1c, 0x3c, 0xaa,
			0x7a, 0xcd, 0xd3, 0x8f, 0x52, 0x78, 0x7c, 0x77, 0xfd, 0x46, 0xbd, 0x72, 0x82, 0xc1, 0x1f, 0x70,
			0x44, 0xcc, 0xc7, 0x9b, 0x9b, 0x7b, 0x13, 0x54, 0x3f, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x24, 0xb6, 0x96,
			0xb0, 0x9e, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xdb, 0x85, 0x60, 0x23, 0x00, 0x0c,
			0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x04, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0xc0, 0x00,
			0x00, 0x04,
		}, []byte{ // COOKIE ECHO, DATA
			0x00, 0x00, 0x0c, 0x9f, 0xf0, 0x1f, 0x24, 0xbe, 0x05, 0x27, 0x0b, 0x17, 0x08, 0x00, 0x45, 0x02,
			0x01, 0x20, 0x00, 0x00, 0x40, 0x00, 0x40, 0x84, 0xc3, 0x46, 0xac, 0x1d, 0x14, 0x0f, 0xac, 0x19,
			0x09, 0xcc, 0x27, 0x0f, 0x22, 0xb8, 0x32, 0x80, 0xfb, 0x42, 0x01, 0xf9, 0xf3, 0xa9, 0x0a, 0x00,
			0x00, 0xe8, 0xd3, 0x08, 0xce, 0xe2, 0x52, 0x95, 0xcc, 0x09, 0xa1, 0x4c, 0x6f, 0xa7, 0x9e, 0xba,
			0x03, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfb, 0x80, 0x32, 0x9e, 0xb0, 0x96, 0xb6, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x46, 0xc2, 0x50, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x25,
			0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x26, 0xb1, 0x98, 0x85, 0x02, 0x00,
			0x27, 0x0f, 0xac, 0x1d, 0x14, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x22, 0x01, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x80, 0x02, 0x00, 0x24, 0x6a, 0x72, 0x5c, 0x1c, 0x3c, 0xaa, 0x7a, 0xcd, 0xd3, 0x8f,
			0x52, 0x78, 0x7c, 0x77, 0xfd, 0x46, 0xbd, 0x72, 0x82, 0xc1, 0x1f, 0x70, 0x44, 0xcc, 0xc7, 0x9b,
			0x9b, 0x7b, 0x13, 0x54, 0x3f, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x24, 0xb6, 0x96, 0xb0, 0x9e, 0x00, 0x01,
			0xc0, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xdb, 0x85, 0x60, 0x23, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x05,
			0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x16, 0xdb, 0x85, 0x60, 0x23, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6f, 0x21, 0x0a, 0x00, 0x00, 0x00,
		}, []byte{ // COOKIE ACK, SACK
			0x24, 0xbe, 0x05, 0x27, 0x0b, 0x17, 0x00, 0x1f, 0xca, 0xb3, 0x76, 0x40, 0x08, 0x00, 0x45, 0x20,
			0x00, 0x34, 0x00, 0x00, 0x40, 0x00, 0x36, 0x84, 0xce, 0x14, 0xac, 0x19, 0x09, 0xcc, 0xac, 0x1d,
			0x14, 0x0f, 0x22, 0xb8, 0x27, 0x0f, 0xb6, 0x96, 0xb0, 0x9e, 0xed, 0x64, 0x30, 0x98, 0x0b, 0x00,
			0x00, 0x04, 0x03, 0x00, 0x00, 0x10, 0xdb, 0x85, 0x60, 0x23, 0x00, 0x00, 0xf3, 0xfa, 0x00, 0x00,
			0x00, 0x00,
		}, []byte{ // DATA
			0x00, 0x00, 0x0c, 0x9f, 0xf0, 0x1f, 0x24, 0xbe, 0x05, 0x27, 0x0b, 0x17, 0x08, 0x00, 0x45, 0x02,
			0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x84, 0xc4, 0x2a, 0xac, 0x1d, 0x14, 0x0f, 0xac, 0x19,
			0x09, 0xcc, 0x27, 0x0f, 0x22, 0xb8, 0x32, 0x80, 0xfb, 0x42, 0xa1, 0xe3, 0xb2, 0x31, 0x00, 0x03,
			0x00, 0x19, 0xdb, 0x85, 0x60, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x62, 0x69,
			0x7a, 0x7a, 0x6c, 0x65, 0x21, 0x0a, 0x00, 0x00, 0x00, 0x00,
		}, []byte{ // SACK
			0x24, 0xbe, 0x05, 0x27, 0x0b, 0x17, 0x00, 0x1f, 0xca, 0xb3, 0x76, 0x40, 0x08, 0x00, 0x45, 0x20,
			0x00, 0x30, 0x00, 0x00, 0x40, 0x00, 0x36, 0x84, 0xce, 0x18, 0xac, 0x19, 0x09, 0xcc, 0xac, 0x1d,
			0x14, 0x0f, 0x22, 0xb8, 0x27, 0x0f, 0xb6, 0x96, 0xb0, 0x9e, 0xfa, 0x49, 0x94, 0x3a, 0x03, 0x00,
			0x00, 0x10, 0xdb, 0x85, 0x60, 0x24, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00,
		}, []byte{ // SHUTDOWN
			0x00, 0x00, 0x0c, 0x9f, 0xf0, 0x1f, 0x24, 0xbe, 0x05, 0x27, 0x0b, 0x17, 0x08, 0x00, 0x45, 0x02,
			0x00, 0x28, 0x00, 0x00, 0x40, 0x00, 0x40, 0x84, 0xc4, 0x3e, 0xac, 0x1d, 0x14, 0x0f, 0xac, 0x19,
			0x09, 0xcc, 0x27, 0x0f, 0x22, 0xb8, 0x32, 0x80, 0xfb, 0x42, 0x3f, 0x29, 0x59, 0x23, 0x07, 0x00,
			0x00, 0x08, 0x85, 0x98, 0xb1, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		}, []byte{ // SHUTDOWN ACK
			0x24, 0xbe, 0x05, 0x27, 0x0b, 0x17, 0x00, 0x1f, 0xca, 0xb3, 0x76, 0x40, 0x08, 0x00, 0x45, 0x20,
			0x00, 0x24, 0x00, 0x00, 0x40, 0x00, 0x36, 0x84, 0xce, 0x24, 0xac, 0x19, 0x09, 0xcc, 0xac, 0x1d,
			0x14, 0x0f, 0x22, 0xb8, 0x27, 0x0f, 0xb6, 0x96, 0xb0, 0x9e, 0xb2, 0xc8, 0x99, 0x24, 0x08, 0x00,
			0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		}, []byte{ // SHUTDOWN COMPLETE
			0x00, 0x00, 0x0c, 0x9f, 0xf0, 0x1f, 0x24, 0xbe, 0x05, 0x27, 0x0b, 0x17, 0x08, 0x00, 0x45, 0x02,
			0x00, 0x24, 0x00, 0x00, 0x40, 0x00, 0x40, 0x84, 0xc4, 0x42, 0xac, 0x1d, 0x14, 0x0f, 0xac, 0x19,
			0x09, 0xcc, 0x27, 0x0f, 0x22, 0xb8, 0x32, 0x80, 0xfb, 0x42, 0xa8, 0xd1, 0x86, 0x85, 0x0e, 0x00,
			0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		}}
	wantLayers := [][]gopacket.LayerType{
		[]gopacket.LayerType{LayerTypeSCTPInit},
		[]gopacket.LayerType{LayerTypeSCTPInitAck},
		[]gopacket.LayerType{LayerTypeSCTPCookieEcho, LayerTypeSCTPData},
		[]gopacket.LayerType{LayerTypeSCTPCookieAck, LayerTypeSCTPSack},
		[]gopacket.LayerType{LayerTypeSCTPData},
		[]gopacket.LayerType{LayerTypeSCTPSack},
		[]gopacket.LayerType{LayerTypeSCTPShutdown},
		[]gopacket.LayerType{LayerTypeSCTPShutdownAck},
		[]gopacket.LayerType{LayerTypeSCTPShutdownComplete},
	}
	for i, data := range sctpPackets {
		p := gopacket.NewPacket(data, LinkTypeEthernet, testDecodeOptions)
		for _, typ := range wantLayers[i] {
			if p.Layer(typ) == nil {
				t.Errorf("Packet %d missing layer type %v, got:", i, typ)
				for _, layer := range p.Layers() {
					t.Errorf("\t%v", layer.LayerType())
				}
				if p.ErrorLayer() != nil {
					t.Error("\tPacket layer error:", p.ErrorLayer().Error())
				}
			}
		}
		// Test re-serialization.
		testSerializationWithOpts(t, p, data, gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true})
	}
}

func TestDecodeCiscoDiscovery(t *testing.T) {
	// http://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=get&target=cdp_v2.pcap
	data := []byte{
		0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc, 0x00, 0x0b, 0xbe, 0x18, 0x9a, 0x41, 0x01, 0xc3, 0xaa, 0xaa,
		0x03, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x02, 0xb4, 0x09, 0xa0, 0x00, 0x01, 0x00, 0x0c, 0x6d, 0x79,
		0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
		0xcc, 0x00, 0x04, 0xc0, 0xa8, 0x00, 0xfd, 0x00, 0x03, 0x00, 0x13, 0x46, 0x61, 0x73, 0x74, 0x45,
		0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x30, 0x2f, 0x31, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00,
		0x00, 0x28, 0x00, 0x05, 0x01, 0x14, 0x43, 0x69, 0x73, 0x63, 0x6f, 0x20, 0x49, 0x6e, 0x74, 0x65,
		0x72, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
		0x6e, 0x67, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61,
		0x72, 0x65, 0x20, 0x0a, 0x49, 0x4f, 0x53, 0x20, 0x28, 0x74, 0x6d, 0x29, 0x20, 0x43, 0x32, 0x39,
		0x35, 0x30, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x28, 0x43, 0x32, 0x39,
		0x35, 0x30, 0x2d, 0x49, 0x36, 0x4b, 0x32, 0x4c, 0x32, 0x51, 0x34, 0x2d, 0x4d, 0x29, 0x2c, 0x20,
		0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x32, 0x2e, 0x31, 0x28, 0x32, 0x32, 0x29,
		0x45, 0x41, 0x31, 0x34, 0x2c, 0x20, 0x52, 0x45, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x20, 0x53, 0x4f,
		0x46, 0x54, 0x57, 0x41, 0x52, 0x45, 0x20, 0x28, 0x66, 0x63, 0x31, 0x29, 0x0a, 0x54, 0x65, 0x63,
		0x68, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x3a, 0x20,
		0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x69, 0x73, 0x63, 0x6f,
		0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x65, 0x63, 0x68, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74,
		0x0a, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x31,
		0x39, 0x38, 0x36, 0x2d, 0x32, 0x30, 0x31, 0x30, 0x20, 0x62, 0x79, 0x20, 0x63, 0x69, 0x73, 0x63,
		0x6f, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a,
		0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x54, 0x75, 0x65, 0x20, 0x32, 0x36, 0x2d,
		0x4f, 0x63, 0x74, 0x2d, 0x31, 0x30, 0x20, 0x31, 0x30, 0x3a, 0x33, 0x35, 0x20, 0x62, 0x79, 0x20,
		0x6e, 0x62, 0x75, 0x72, 0x72, 0x61, 0x00, 0x06, 0x00, 0x15, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x20,
		0x57, 0x53, 0x2d, 0x43, 0x32, 0x39, 0x35, 0x30, 0x2d, 0x31, 0x32, 0x00, 0x08, 0x00, 0x24, 0x00,
		0x00, 0x0c, 0x01, 0x12, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x02, 0x20, 0xff,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xbe, 0x18, 0x9a, 0x40, 0xff, 0x00, 0x00, 0x00,
		0x09, 0x00, 0x0c, 0x4d, 0x59, 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x00, 0x0a, 0x00, 0x06, 0x00,
		0x01, 0x00, 0x0b, 0x00, 0x05, 0x01, 0x00, 0x12, 0x00, 0x05, 0x00, 0x00, 0x13, 0x00, 0x05, 0x00,
		0x00, 0x16, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0xcc, 0x00, 0x04, 0xc0, 0xa8, 0x00,
		0xfd,
	}
	p := gopacket.NewPacket(data, LinkTypeEthernet, testDecodeOptions)
	wantLayers := []gopacket.LayerType{LayerTypeEthernet, LayerTypeLLC, LayerTypeSNAP, LayerTypeCiscoDiscovery, LayerTypeCiscoDiscoveryInfo}
	checkLayers(p, wantLayers, t)

	want := &CiscoDiscoveryInfo{
		CDPHello: CDPHello{
			OUI:              []byte{0, 0, 12},
			ProtocolID:       274,
			ClusterMaster:    []byte{0, 0, 0, 0},
			Unknown1:         []byte{255, 255, 255, 255},
			Version:          1,
			SubVersion:       2,
			Status:           32,
			Unknown2:         255,
			ClusterCommander: net.HardwareAddr{0, 0, 0, 0, 0, 0},
			SwitchMAC:        net.HardwareAddr{0, 0x0b, 0xbe, 0x18, 0x9a, 0x40},
			Unknown3:         255,
			ManagementVLAN:   0,
		},
		DeviceID:      "myswitch",
		Addresses:     []net.IP{net.IPv4(192, 168, 0, 253)},
		PortID:        "FastEthernet0/1",
		Capabilities:  CDPCapabilities{false, false, false, true, false, true, false, false, false},
		Version:       "Cisco Internetwork Operating System Software \nIOS (tm) C2950 Software (C2950-I6K2L2Q4-M), Version 12.1(22)EA14, RELEASE SOFTWARE (fc1)\nTechnical Support: http://www.cisco.com/techsupport\nCopyright (c) 1986-2010 by cisco Systems, Inc.\nCompiled Tue 26-Oct-10 10:35 by nburra",
		Platform:      "cisco WS-C2950-12",
		VTPDomain:     "MYDOMAIN",
		NativeVLAN:    1,
		FullDuplex:    true,
		MgmtAddresses: []net.IP{net.IPv4(192, 168, 0, 253)},
		BaseLayer:     BaseLayer{Contents: data[26:]},
	}
	cdpL := p.Layer(LayerTypeCiscoDiscoveryInfo)
	info, _ := cdpL.(*CiscoDiscoveryInfo)
	if !reflect.DeepEqual(info, want) {
		t.Errorf("Values mismatch, \ngot  %#v\nwant %#v\n", info, want)
	}
}

func TestDecodeLinkLayerDiscovery(t *testing.T) {
	// http://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=get&target=lldp.detailed.pcap
	data := []byte{
		0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x30, 0xf9, 0xad, 0xa0,
		0x88, 0xcc, 0x02, 0x07, 0x04, 0x00, 0x01, 0x30, 0xf9, 0xad, 0xa0, 0x04,
		0x04, 0x05, 0x31, 0x2f, 0x31, 0x06, 0x02, 0x00, 0x78, 0x08, 0x17, 0x53,
		0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, 0x30, 0x2d, 0x34, 0x38, 0x2d,
		0x50, 0x6f, 0x72, 0x74, 0x20, 0x31, 0x30, 0x30, 0x31, 0x00, 0x0a, 0x0d,
		0x53, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, 0x30, 0x2d, 0x34, 0x38,
		0x00, 0x0c, 0x4c, 0x53, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, 0x30,
		0x2d, 0x34, 0x38, 0x20, 0x2d, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
		0x6e, 0x20, 0x37, 0x2e, 0x34, 0x65, 0x2e, 0x31, 0x20, 0x28, 0x42, 0x75,
		0x69, 0x6c, 0x64, 0x20, 0x35, 0x29, 0x20, 0x62, 0x79, 0x20, 0x52, 0x65,
		0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72,
		0x20, 0x30, 0x35, 0x2f, 0x32, 0x37, 0x2f, 0x30, 0x35, 0x20, 0x30, 0x34,
		0x3a, 0x35, 0x33, 0x3a, 0x31, 0x31, 0x00, 0x0e, 0x04, 0x00, 0x14, 0x00,
		0x14, 0x10, 0x0e, 0x07, 0x06, 0x00, 0x01, 0x30, 0xf9, 0xad, 0xa0, 0x02,
		0x00, 0x00, 0x03, 0xe9, 0x00, 0xfe, 0x07, 0x00, 0x12, 0x0f, 0x02, 0x07,
		0x01, 0x00, 0xfe, 0x09, 0x00, 0x12, 0x0f, 0x01, 0x03, 0x6c, 0x00, 0x00,
		0x10, 0xfe, 0x09, 0x00, 0x12, 0x0f, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00,
		0xfe, 0x06, 0x00, 0x12, 0x0f, 0x04, 0x05, 0xf2, 0xfe, 0x06, 0x00, 0x80,
		0xc2, 0x01, 0x01, 0xe8, 0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, 0x01, 0x00,
		0x00, 0xfe, 0x17, 0x00, 0x80, 0xc2, 0x03, 0x01, 0xe8, 0x10, 0x76, 0x32,
		0x2d, 0x30, 0x34, 0x38, 0x38, 0x2d, 0x30, 0x33, 0x2d, 0x30, 0x35, 0x30,
		0x35, 0x00, 0xfe, 0x05, 0x00, 0x80, 0xc2, 0x04, 0x00, 0x00, 0x00,
	}

	p := gopacket.NewPacket(data, LinkTypeEthernet, testDecodeOptions)
	wantLayers := []gopacket.LayerType{LayerTypeEthernet, LayerTypeLinkLayerDiscovery, LayerTypeLinkLayerDiscoveryInfo}
	checkLayers(p, wantLayers, t)
	lldpL := p.Layer(LayerTypeLinkLayerDiscovery)
	lldp := lldpL.(*LinkLayerDiscovery)
	want := &LinkLayerDiscovery{
		ChassisID: LLDPChassisID{LLDPChassisIDSubTypeMACAddr, []byte{0x00, 0x01, 0x30, 0xf9, 0xad, 0xa0}},
		PortID:    LLDPPortID{LLDPPortIDSubtypeIfaceName, []byte("1/1")},
		TTL:       120,
		BaseLayer: BaseLayer{Contents: data[14:]},
	}
	lldp.Values = nil // test these in next stage
	if !reflect.DeepEqual(lldp, want) {
		t.Errorf("Values mismatch, \ngot  %#v\nwant %#v\n", lldp, want)
	}

	infoL := p.Layer(LayerTypeLinkLayerDiscoveryInfo)
	info := infoL.(*LinkLayerDiscoveryInfo)
	wantinfo := &LinkLayerDiscoveryInfo{
		PortDescription: "Summit300-48-Port 1001\x00",
		SysName:         "Summit300-48\x00",
		SysDescription:  "Summit300-48 - Version 7.4e.1 (Build 5) by Release_Master 05/27/05 04:53:11\x00",
		SysCapabilities: LLDPSysCapabilities{
			SystemCap:  LLDPCapabilities{Bridge: true, Router: true},
			EnabledCap: LLDPCapabilities{Bridge: true, Router: true},
		},
		MgmtAddress: LLDPMgmtAddress{IANAAddressFamily802, []byte{0x00, 0x01, 0x30, 0xf9, 0xad, 0xa0}, LLDPInterfaceSubtypeifIndex, 1001, ""},
		OrgTLVs: []LLDPOrgSpecificTLV{
			LLDPOrgSpecificTLV{OUI: 0x120f, SubType: 0x2, Info: []uint8{0x7, 0x1, 0x0}},
			LLDPOrgSpecificTLV{OUI: 0x120f, SubType: 0x1, Info: []uint8{0x3, 0x6c, 0x0, 0x0, 0x10}},
			LLDPOrgSpecificTLV{OUI: 0x120f, SubType: 0x3, Info: []uint8{0x1, 0x0, 0x0, 0x0, 0x0}},
			LLDPOrgSpecificTLV{OUI: 0x120f, SubType: 0x4, Info: []uint8{0x5, 0xf2}},
			LLDPOrgSpecificTLV{OUI: 0x80c2, SubType: 0x1, Info: []uint8{0x1, 0xe8}},
			LLDPOrgSpecificTLV{OUI: 0x80c2, SubType: 0x2, Info: []uint8{0x1, 0x0, 0x0}},
			LLDPOrgSpecificTLV{OUI: 0x80c2, SubType: 0x3, Info: []uint8{0x1, 0xe8, 0x10, 0x76, 0x32, 0x2d, 0x30, 0x34, 0x38, 0x38, 0x2d, 0x30, 0x33, 0x2d, 0x30, 0x35, 0x30, 0x35, 0x0}},
			LLDPOrgSpecificTLV{OUI: 0x80c2, SubType: 0x4, Info: []uint8{0x0}},
		},
		Unknown: nil,
	}
	if !reflect.DeepEqual(info, wantinfo) {
		t.Errorf("Values mismatch, \ngot  %#v\nwant %#v\n", info, wantinfo)
	}
	info8021, err := info.Decode8021()
	if err != nil {
		t.Errorf("8021 Values decode error: %v", err)
	}
	want8021 := LLDPInfo8021{
		PVID:               488,
		PPVIDs:             []PortProtocolVLANID{PortProtocolVLANID{false, false, 0}},
		VLANNames:          []VLANName{VLANName{488, "v2-0488-03-0505\x00"}},
		ProtocolIdentities: nil,
		VIDUsageDigest:     0,
		ManagementVID:      0,
		LinkAggregation:    LLDPLinkAggregation{false, false, 0},
	}
	if !reflect.DeepEqual(info8021, want8021) {
		t.Errorf("Values mismatch, \ngot  %#v\nwant %#v\n", info8021, want8021)
	}
	info8023, err := info.Decode8023()
	if err != nil {
		t.Errorf("8023 Values decode error: %v", err)
	}
	want8023 := LLDPInfo8023{
		LinkAggregation:    LLDPLinkAggregation{true, false, 0},
		MACPHYConfigStatus: LLDPMACPHYConfigStatus{true, true, 0x6c00, 0x0010},
		PowerViaMDI:        LLDPPowerViaMDI8023{true, true, true, false, 1, 0, 0, 0, 0, 0, 0},
		MTU:                1522,
	}

	if !reflect.DeepEqual(info8023, want8023) {
		t.Errorf("Values mismatch, \ngot  %#v\nwant %#v\n", info8023, want8023)
	}

	// http://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=get&target=lldpmed_civicloc.pcap
	data = []byte{
		0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e, 0x00, 0x13, 0x21, 0x57, 0xca, 0x7f,
		0x88, 0xcc, 0x02, 0x07, 0x04, 0x00, 0x13, 0x21, 0x57, 0xca, 0x40, 0x04,
		0x02, 0x07, 0x31, 0x06, 0x02, 0x00, 0x78, 0x08, 0x01, 0x31, 0x0a, 0x1a,
		0x50, 0x72, 0x6f, 0x43, 0x75, 0x72, 0x76, 0x65, 0x20, 0x53, 0x77, 0x69,
		0x74, 0x63, 0x68, 0x20, 0x32, 0x36, 0x30, 0x30, 0x2d, 0x38, 0x2d, 0x50,
		0x57, 0x52, 0x0c, 0x5f, 0x50, 0x72, 0x6f, 0x43, 0x75, 0x72, 0x76, 0x65,
		0x20, 0x4a, 0x38, 0x37, 0x36, 0x32, 0x41, 0x20, 0x53, 0x77, 0x69, 0x74,
		0x63, 0x68, 0x20, 0x32, 0x36, 0x30, 0x30, 0x2d, 0x38, 0x2d, 0x50, 0x57,
		0x52, 0x2c, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20,
		0x48, 0x2e, 0x30, 0x38, 0x2e, 0x38, 0x39, 0x2c, 0x20, 0x52, 0x4f, 0x4d,
		0x20, 0x48, 0x2e, 0x30, 0x38, 0x2e, 0x35, 0x58, 0x20, 0x28, 0x2f, 0x73,
		0x77, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64,
		0x2f, 0x66, 0x69, 0x73, 0x68, 0x28, 0x74, 0x73, 0x5f, 0x30, 0x38, 0x5f,
		0x35, 0x29, 0x29, 0x0e, 0x04, 0x00, 0x14, 0x00, 0x04, 0x10, 0x0c, 0x05,
		0x01, 0x0f, 0xff, 0x7a, 0x94, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
		0x09, 0x00, 0x12, 0x0f, 0x01, 0x03, 0x6c, 0x00, 0x00, 0x10, 0xfe, 0x07,
		0x00, 0x12, 0xbb, 0x01, 0x00, 0x0f, 0x04, 0xfe, 0x08, 0x00, 0x12, 0xbb,
		0x02, 0x01, 0x40, 0x65, 0xae, 0xfe, 0x2e, 0x00, 0x12, 0xbb, 0x03, 0x02,
		0x28, 0x02, 0x55, 0x53, 0x01, 0x02, 0x43, 0x41, 0x03, 0x09, 0x52, 0x6f,
		0x73, 0x65, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x06, 0x09, 0x46, 0x6f, 0x6f,
		0x74, 0x68, 0x69, 0x6c, 0x6c, 0x73, 0x13, 0x04, 0x38, 0x30, 0x30, 0x30,
		0x1a, 0x03, 0x52, 0x33, 0x4c, 0xfe, 0x07, 0x00, 0x12, 0xbb, 0x04, 0x03,
		0x00, 0x41, 0x00, 0x00,
	}

	p = gopacket.NewPacket(data, LinkTypeEthernet, testDecodeOptions)
	wantLayers = []gopacket.LayerType{LayerTypeEthernet, LayerTypeLinkLayerDiscovery, LayerTypeLinkLayerDiscoveryInfo}
	checkLayers(p, wantLayers, t)
	lldpL = p.Layer(LayerTypeLinkLayerDiscovery)
	lldp = lldpL.(*LinkLayerDiscovery)
	want = &LinkLayerDiscovery{
		ChassisID: LLDPChassisID{LLDPChassisIDSubTypeMACAddr, []byte{0x00, 0x13, 0x21, 0x57, 0xca, 0x40}},
		PortID:    LLDPPortID{LLDPPortIDSubtypeLocal, []byte("1")},
		TTL:       120,
		BaseLayer: BaseLayer{Contents: data[14:]},
	}
	lldp.Values = nil // test these in next stage
	if !reflect.DeepEqual(lldp, want) {
		t.Errorf("Values mismatch, \ngot  %#v\nwant %#v\n", lldp, want)
	}

	infoL = p.Layer(LayerTypeLinkLayerDiscoveryInfo)
	info = infoL.(*LinkLayerDiscoveryInfo)
	wantinfo = &LinkLayerDiscoveryInfo{
		PortDescription: "1",
		SysName:         "ProCurve Switch 2600-8-PWR",
		SysDescription:  "ProCurve J8762A Switch 2600-8-PWR, revision H.08.89, ROM H.08.5X (/sw/code/build/fish(ts_08_5))",
		SysCapabilities: LLDPSysCapabilities{
			SystemCap:  LLDPCapabilities{Bridge: true, Router: true},
			EnabledCap: LLDPCapabilities{Bridge: true},
		},
		MgmtAddress: LLDPMgmtAddress{IANAAddressFamilyIPV4, []byte{0x0f, 0xff, 0x7a, 0x94}, LLDPInterfaceSubtypeifIndex, 0, ""},
		OrgTLVs: []LLDPOrgSpecificTLV{
			LLDPOrgSpecificTLV{OUI: 0x120f, SubType: 0x1, Info: []uint8{0x3, 0x6c, 0x0, 0x0, 0x10}},
			LLDPOrgSpecificTLV{OUI: 0x12bb, SubType: 0x1, Info: []uint8{0x0, 0xf, 0x4}},
			LLDPOrgSpecificTLV{OUI: 0x12bb, SubType: 0x2, Info: []uint8{0x1, 0x40, 0x65, 0xae}},
			LLDPOrgSpecificTLV{OUI: 0x12bb, SubType: 0x3, Info: []uint8{0x2, 0x28, 0x2, 0x55, 0x53, 0x1, 0x2, 0x43, 0x41, 0x3, 0x9, 0x52, 0x6f, 0x73, 0x65, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x6, 0x9, 0x46, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6c, 0x6c, 0x73, 0x13, 0x4, 0x38, 0x30, 0x30, 0x30, 0x1a, 0x3, 0x52, 0x33, 0x4c}},
			LLDPOrgSpecificTLV{OUI: 0x12bb, SubType: 0x4, Info: []uint8{0x3, 0x0, 0x41}},
		},
		Unknown: nil,
	}
	if !reflect.DeepEqual(info, wantinfo) {
		t.Errorf("Values mismatch, \ngot  %#v\nwant %#v\n", info, wantinfo)
	}
	info8023, err = info.Decode8023()
	if err != nil {
		t.Errorf("8023 Values decode error: %v", err)
	}
	want8023 = LLDPInfo8023{
		MACPHYConfigStatus: LLDPMACPHYConfigStatus{true, true, 0x6c00, 0x0010},
	}

	if !reflect.DeepEqual(info8023, want8023) {
		t.Errorf("Values mismatch, \ngot  %#v\nwant %#v\n", info8023, want8023)
	}

	infoMedia, err := info.DecodeMedia()
	if err != nil {
		t.Errorf("8023 Values decode error: %v", err)
	}
	wantMedia := LLDPInfoMedia{
		MediaCapabilities: LLDPMediaCapabilities{true, true, true, true, false, false, LLDPMediaClassNetwork},
		NetworkPolicy:     LLDPNetworkPolicy{LLDPAppTypeVoice, true, true, 50, 6, 46},
		Location: LLDPLocation{Format: LLDPLocationFormatAddress, Address: LLDPLocationAddress{
			What:        LLDPLocationAddressWhatClient,
			CountryCode: "US",
			AddressLines: []LLDPLocationAddressLine{
				LLDPLocationAddressLine{LLDPLocationAddressTypeNational, "CA"},
				LLDPLocationAddressLine{LLDPLocationAddressTypeCity, "Roseville"},
				LLDPLocationAddressLine{LLDPLocationAddressTypeStreet, "Foothills"},
				LLDPLocationAddressLine{LLDPLocationAddressTypeHouseNum, "8000"},
				LLDPLocationAddressLine{LLDPLocationAddressTypeUnit, "R3L"},
			},
		}},
		PowerViaMDI: LLDPPowerViaMDI{0, 0, LLDPPowerPriorityLow, 6500},
	}

	if !reflect.DeepEqual(infoMedia, wantMedia) {
		t.Errorf("Values mismatch, \ngot  %#v\nwant %#v\n", infoMedia, wantMedia)
	}

}

func TestDecodeNortelDiscovery(t *testing.T) {
	// http://www.thetechfirm.com/packets/nortel_btdp/btdp_nai.enc
	data := []byte{
		0x01, 0x00, 0x81, 0x00, 0x01, 0x00, 0x00, 0x04, 0x38, 0xe0, 0xcc, 0xde,
		0x00, 0x13, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x81, 0x01, 0xa2, 0xac, 0x13,
		0x58, 0x03, 0x00, 0x04, 0x15, 0x30, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x04, 0x38, 0xe0, 0xcc, 0xde, 0x80, 0x6a, 0x00, 0x01, 0x14, 0x00,
		0x02, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	}
	p := gopacket.NewPacket(data, LinkTypeEthernet, testDecodeOptions)
	wantLayers := []gopacket.LayerType{LayerTypeEthernet, LayerTypeLLC, LayerTypeSNAP, LayerTypeNortelDiscovery}
	checkLayers(p, wantLayers, t)

	want := &NortelDiscovery{
		IPAddress: []byte{172, 19, 88, 3},
		SegmentID: []byte{0x00, 0x04, 0x15},
		Chassis:   NDPChassisBayStack450101001000Switches,
		Backplane: NDPBackplaneEthernetFastEthernetGigabitEthernet,
		State:     NDPStateHeartbeat,
		NumLinks:  0,
	}
	ndpL := p.Layer(LayerTypeNortelDiscovery)
	info, _ := ndpL.(*NortelDiscovery)
	if !reflect.DeepEqual(info, want) {
		t.Errorf("Values mismatch, \ngot  %#v\nwant %#v\n", info, want)
	}
}

func TestDecodeIPv6Jumbogram(t *testing.T) {
	// Haven't found any of these in the wild or on example pcaps online, so had
	// to generate one myself via scapy.  Unfortunately, scapy can only
	// str(packet) for packets with length < 65536, due to limitations in python's
	// struct library, so I generated the header with:
	// Ether() / IPv6(src='::1', dst='::2') / IPv6ExtHdrHopByHop(options=[Jumbo(jumboplen=70000)]) / TCP(sport=8888, dport=80)
	// then added the payload manually ("payload" * 9996).  The checksums here are
	// not correct, but we don't check, so who cares ;)
	dataStr := "\x00\x1f\xca\xb3v@$\xbe\x05'\x0b\x17\x86\xdd`\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x06\x00\xc2\x04\x00\x01\x11p\"\xb8\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00l\xd8\x00\x00"
	payload := strings.Repeat("payload", 9996)
	data := []byte(dataStr + payload)
	p := gopacket.NewPacket(data, LinkTypeEthernet, testDecodeOptions)
	checkLayers(p, []gopacket.LayerType{LayerTypeEthernet, LayerTypeIPv6, LayerTypeIPv6HopByHop, LayerTypeTCP, gopacket.LayerTypePayload}, t)
	if p.ApplicationLayer() == nil {
		t.Error("Packet has no application layer")
	} else if string(p.ApplicationLayer().Payload()) != payload {
		t.Errorf("Jumbogram payload wrong")
	}
	// Check truncated for jumbograms
	data = data[:len(data)-1]
	p = gopacket.NewPacket(data, LinkTypeEthernet, testDecodeOptions)
	checkLayers(p, []gopacket.LayerType{LayerTypeEthernet, LayerTypeIPv6, LayerTypeIPv6HopByHop, LayerTypeTCP, gopacket.LayerTypePayload}, t)
	if !p.Metadata().Truncated {
		t.Error("Jumbogram should be truncated")
	}
}

func TestDecodeUDPPacketTooSmall(t *testing.T) {
	data := []byte{
		0x00, 0x15, 0x2c, 0x9d, 0xcc, 0x00, 0x00, 0x10, 0xdb, 0xff, 0x10, 0x00, 0x81, 0x00, 0x01, 0xf7,
		0x08, 0x00, 0x45, 0x60, 0x00, 0x3c, 0x0f, 0xa9, 0x00, 0x00, 0x6e, 0x11, 0x01, 0x0a, 0x47, 0xe6,
		0xee, 0x2e, 0xac, 0x16, 0x59, 0x73, 0x00, 0x50, 0x00, 0x50, 0x00, 0x28, 0x4d, 0xad, 0x00, 0x67,
		0x00, 0x01, 0x00, 0x72, 0xd5, 0xc7, 0xf1, 0x07, 0x00, 0x00, 0x01, 0x01, 0x00, 0x0d, 0x00, 0x00,
		0x00, 0x14, 0x00, 0x00, 0x19, 0xba,
	}
	p := gopacket.NewPacket(data, LinkTypeEthernet, testDecodeOptions)
	checkLayers(p, []gopacket.LayerType{LayerTypeEthernet, LayerTypeDot1Q, LayerTypeIPv4, LayerTypeUDP, gopacket.LayerTypePayload}, t)
	if !p.Metadata().Truncated {
		t.Error("UDP short packet should be truncated")
	}
}

func TestDecodingLayerParserFullTCPPacket(t *testing.T) {
	dlp := gopacket.NewDecodingLayerParser(LayerTypeEthernet, &Ethernet{}, &IPv4{}, &TCP{}, &gopacket.Payload{})
	decoded := make([]gopacket.LayerType, 1)
	err := dlp.DecodeLayers(testSimpleTCPPacket, &decoded)
	if err != nil {
		t.Error("Error from dlp parser: ", err)
	}
	if len(decoded) != 4 {
		t.Error("Expected 4 layers parsed, instead got ", len(decoded))
	}
}

func testDecodingLayerContainer(t *testing.T, dlc gopacket.DecodingLayerContainer) {
	dlc = dlc.Put(&Ethernet{})
	dlc = dlc.Put(&IPv4{})
	dlc = dlc.Put(&TCP{})
	dlc = dlc.Put(&gopacket.Payload{})
	decoded := make([]gopacket.LayerType, 1)

	// just as a DecodeFeedback
	df := gopacket.NewDecodingLayerParser(LayerTypeEthernet)
	decoder := dlc.LayersDecoder(LayerTypeEthernet, df)
	typ, err := decoder(testSimpleTCPPacket, &decoded)
	if err != nil {
		t.Error("Error from decoder: ", err)
	}
	if typ != gopacket.LayerTypeZero {
		t.Error("Unsupported layer type", typ)
	}
	if len(decoded) != 4 {
		t.Error("Expected 4 layers parsed, instead got ", len(decoded))
	}
}

func TestDecodingLayerMap(t *testing.T) {
	testDecodingLayerContainer(t, gopacket.DecodingLayerMap(nil))
}

func TestDecodingLayerSparse(t *testing.T) {
	testDecodingLayerContainer(t, gopacket.DecodingLayerSparse(nil))
}

func TestDecodingLayerArray(t *testing.T) {
	testDecodingLayerContainer(t, gopacket.DecodingLayerArray(nil))
}

// testICMP is the packet:
//
//	15:49:15.773265 IP 72.14.222.226 > 172.29.20.15: ICMP host 10.66.73.201 unreachable - admin prohibited filter, length 36
//	   0x0000:  24be 0527 0b17 001f cab3 75c0 0800 4500  $..'......u...E.
//	   0x0010:  0038 0000 0000 fc01 d7a7 480e dee2 ac1d  .8........H.....
//	   0x0020:  140f 030d 946e 0000 0000 4520 004d 0000  .....n....E..M..
//	   0x0030:  4000 3e11 2849 ac1d 140f 0a42 49c9 8ecc  @.>.(I.....BI...
//	   0x0040:  62e1 0039 769d                           b..9v.
var testICMP = []byte{
	0x24, 0xbe, 0x05, 0x27, 0x0b, 0x17, 0x00, 0x1f, 0xca, 0xb3, 0x75, 0xc0, 0x08, 0x00, 0x45, 0x00,
	0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0xd7, 0xa7, 0x48, 0x0e, 0xde, 0xe2, 0xac, 0x1d,
	0x14, 0x0f, 0x03, 0x0d, 0x94, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x45, 0x20, 0x00, 0x4d, 0x00, 0x00,
	0x40, 0x00, 0x3e, 0x11, 0x28, 0x49, 0xac, 0x1d, 0x14, 0x0f, 0x0a, 0x42, 0x49, 0xc9, 0x8e, 0xcc,
	0x62, 0xe1, 0x00, 0x39, 0x76, 0x9d,
}

func TestICMP(t *testing.T) {
	p := gopacket.NewPacket(testICMP, LinkTypeEthernet, testDecodeOptions)
	if p.ErrorLayer() != nil {
		t.Error("Failed to decode packet:", p.ErrorLayer().Error())
	}
	checkLayers(p, []gopacket.LayerType{LayerTypeEthernet, LayerTypeIPv4, LayerTypeICMPv4, gopacket.LayerTypePayload}, t)
	testSerialization(t, p, testICMP)
}
func BenchmarkDecodeICMP(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testICMP, LinkTypeEthernet, gopacket.NoCopy)
	}
}

// testICMP6 is the packet:
//
//	16:17:37.758937 IP6 fe80::21f:caff:feb3:75c0 > 2620:0:1005:0:26be:5ff:fe27:b17: ICMP6, neighbor solicitation, who has 2620:0:1005:0:26be:5ff:fe27:b17, length 32
//	   0x0000:  24be 0527 0b17 001f cab3 75c0 86dd 6e00  $..'......u...n.
//	   0x0010:  0000 0020 3aff fe80 0000 0000 0000 021f  ....:...........
//	   0x0020:  caff feb3 75c0 2620 0000 1005 0000 26be  ....u.&.......&.
//	   0x0030:  05ff fe27 0b17 8700 1eba 0000 0000 2620  ...'..........&.
//	   0x0040:  0000 1005 0000 26be 05ff fe27 0b17 0101  ......&....'....
//	   0x0050:  001f cab3 75c0                           ....u.
var testICMP6 = []byte{
	0x24, 0xbe, 0x05, 0x27, 0x0b, 0x17, 0x00, 0x1f, 0xca, 0xb3, 0x75, 0xc0, 0x86, 0xdd, 0x6e, 0x00,
	0x00, 0x00, 0x00, 0x20, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f,
	0xca, 0xff, 0xfe, 0xb3, 0x75, 0xc0, 0x26, 0x20, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x26, 0xbe,
	0x05, 0xff, 0xfe, 0x27, 0x0b, 0x17, 0x87, 0x00, 0x1e, 0xba, 0x00, 0x00, 0x00, 0x00, 0x26, 0x20,
	0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x26, 0xbe, 0x05, 0xff, 0xfe, 0x27, 0x0b, 0x17, 0x01, 0x01,
	0x00, 0x1f, 0xca, 0xb3, 0x75, 0xc0,
}

func TestICMP6(t *testing.T) {
	p := gopacket.NewPacket(testICMP6, LinkTypeEthernet, testDecodeOptions)
	if p.ErrorLayer() != nil {
		t.Error("Failed to decode packet:", p.ErrorLayer().Error())
	}
	checkLayers(p, []gopacket.LayerType{LayerTypeEthernet, LayerTypeIPv6, LayerTypeICMPv6, gopacket.LayerTypePayload}, t)
	testSerialization(t, p, testICMP6)
}
func BenchmarkDecodeICMP6(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testICMP6, LinkTypeEthernet, gopacket.NoCopy)
	}
}

// testMPLS is the packet:
//
//	12:48:57.201014 MPLS (label 29, exp 0, [S], ttl 255) IP 10.1.2.1 > 10.34.0.1: ICMP echo request, id 2618, seq 1579, length 80
//	   0x0000:  0030 96e6 fc39 0030 9605 2838 8847 0001  .0...9.0..(8.G..
//	   0x0010:  d1ff 4500 0064 000b 0000 ff01 a569 0a01  ..E..d.......i..
//	   0x0020:  0201 0a22 0001 0800 3a76 0a3a 062b 0000  ..."....:v.:.+..
//	   0x0030:  0000 001f 3350 abcd abcd abcd abcd abcd  ....3P..........
//	   0x0040:  abcd abcd abcd abcd abcd abcd abcd abcd  ................
//	   0x0050:  abcd abcd abcd abcd abcd abcd abcd abcd  ................
//	   0x0060:  abcd abcd abcd abcd abcd abcd abcd abcd  ................
//	   0x0070:  abcd abcd abcd                           ......
var testMPLS = []byte{
	0x00, 0x30, 0x96, 0xe6, 0xfc, 0x39, 0x00, 0x30, 0x96, 0x05, 0x28, 0x38, 0x88, 0x47, 0x00, 0x01,
	0xd1, 0xff, 0x45, 0x00, 0x00, 0x64, 0x00, 0x0b, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x69, 0x0a, 0x01,
	0x02, 0x01, 0x0a, 0x22, 0x00, 0x01, 0x08, 0x00, 0x3a, 0x76, 0x0a, 0x3a, 0x06, 0x2b, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x1f, 0x33, 0x50, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
	0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
	0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
	0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
	0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
}

func TestMPLS(t *testing.T) {
	p := gopacket.NewPacket(testMPLS, LinkTypeEthernet, testDecodeOptions)
	if p.ErrorLayer() != nil {
		t.Error("Failed to decode packet:", p.ErrorLayer().Error())
	}
	checkLayers(p, []gopacket.LayerType{LayerTypeEthernet, LayerTypeMPLS, LayerTypeIPv4, LayerTypeICMPv4, gopacket.LayerTypePayload}, t)
	testSerialization(t, p, testMPLS)
}
func BenchmarkDecodeMPLS(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testMPLS, LinkTypeEthernet, gopacket.NoCopy)
	}
}

// testPPPGREIPv4IPv6VLAN is the packet from http://packetlife.net/captures/gre_and_4over6.cap
//
//	0x0000:  6000 0000 008b 04f6 2402 f000 0001 8e01  `.......$.......
//	0x0010:  0000 0000 0000 5555 2607 fcd0 0100 2300  ......UU&.....#.
//	0x0020:  0000 0000 b108 2a6b 4500 008b 8caf 0000  ......*kE.......
//	0x0030:  402f 75fe 1000 00c8 c034 a69a 3081 880b  @/u......4..0...
//	0x0040:  0067 1780 0006 8fb1 0008 3a76 ff03 0021  .g........:v...!
//	0x0050:  4500 0063 0000 4000 3c11 5667 ac10 2c03  E..c..@.<.Vg..,.
//	0x0060:  0808 0808 9f40 0035 004f 2d23 a62c 0100  .....@.5.O-#.,..
//	0x0070:  0001 0000 0000 0000 3578 7174 2d64 6574  ........5xqt-det
//	0x0080:  6563 742d 6d6f 6465 322d 3937 3731 3265  ect-mode2-97712e
//	0x0090:  3838 2d31 3637 612d 3435 6239 2d39 3365  88-167a-45b9-93e
//	0x00a0:  652d 3931 3331 3430 6537 3636 3738 0000  e-913140e76678..
//	0x00b0:  1c00 01
//
//04:35:03.821897 IP6 2402:f000:1:8e01::5555 > 2607:fcd0:100:2300::b108:2a6b: IP 16.0.0.200 > 192.52.166.154: GREv1, call 6016, seq 430001, ack 539254, length 119: IP 172.16.44.3.40768 > 8.8.8.8.53: 42540+ AAAA? xqt-detect-mode2-97712e88-167a-45b9-93ee-913140e76678. (71)
var testPPPGREIPv4IPv6VLAN = []byte{
	0xc5, 0x00, 0x00, 0x00, 0x82, 0xc4, 0x00, 0x12, 0x1e, 0xf2, 0x61, 0x3d, 0x81, 0x00, 0x00, 0x64,
	0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x04, 0xf6, 0x24, 0x02, 0xf0, 0x00, 0x00, 0x01,
	0x8e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x26, 0x07, 0xfc, 0xd0, 0x01, 0x00,
	0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x08, 0x2a, 0x6b, 0x45, 0x00, 0x00, 0x8b, 0x8c, 0xaf,
	0x00, 0x00, 0x40, 0x2f, 0x75, 0xfe, 0x10, 0x00, 0x00, 0xc8, 0xc0, 0x34, 0xa6, 0x9a, 0x30, 0x81,
	0x88, 0x0b, 0x00, 0x67, 0x17, 0x80, 0x00, 0x06, 0x8f, 0xb1, 0x00, 0x08, 0x3a, 0x76, 0xff, 0x03,
	0x00, 0x21, 0x45, 0x00, 0x00, 0x63, 0x00, 0x00, 0x40, 0x00, 0x3c, 0x11, 0x56, 0x67, 0xac, 0x10,
	0x2c, 0x03, 0x08, 0x08, 0x08, 0x08, 0x9f, 0x40, 0x00, 0x35, 0x00, 0x4f, 0xfb, 0x9f, 0xa6, 0x2c,
	0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x78, 0x71, 0x74, 0x2d, 0x64,
	0x65, 0x74, 0x65, 0x63, 0x74, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x32, 0x2d, 0x39, 0x37, 0x37, 0x31,
	0x32, 0x65, 0x38, 0x38, 0x2d, 0x31, 0x36, 0x37, 0x61, 0x2d, 0x34, 0x35, 0x62, 0x39, 0x2d, 0x39,
	0x33, 0x65, 0x65, 0x2d, 0x39, 0x31, 0x33, 0x31, 0x34, 0x30, 0x65, 0x37, 0x36, 0x36, 0x37, 0x38,
	0x00, 0x00, 0x1c, 0x00, 0x01,
}

func TestPPPGREIPv4IPv6VLAN(t *testing.T) {
	p := gopacket.NewPacket(testPPPGREIPv4IPv6VLAN, LinkTypeEthernet, testDecodeOptions)
	if p.ErrorLayer() != nil {
		t.Error("Failed to decode packet:", p.ErrorLayer().Error())
	}
	checkLayers(p, []gopacket.LayerType{
		LayerTypeEthernet,
		LayerTypeDot1Q,
		LayerTypeIPv6,
		LayerTypeIPv4,
		LayerTypeGRE,
		LayerTypePPP,
		LayerTypeIPv4,
		LayerTypeUDP,
		LayerTypeDNS,
	}, t)
	testSerialization(t, p, testPPPGREIPv4IPv6VLAN)
}

// testPPPoEICMPv6 is the packet:
//
//	07:43:31.091560 PPPoE  [ses 0x11] IP6 fe80::c801:eff:fe88:8 > ff02::1: ICMP6, neighbor advertisement, tgt is fe80::c801:eff:fe88:8, length 24
//	   0x0000:  cc05 0e88 0000 ca01 0e88 0006 8864 1100  .............d..
//	   0x0010:  0011 0042 0057 6e00 0000 0018 3aff fe80  ...B.Wn.....:...
//	   0x0020:  0000 0000 0000 c801 0eff fe88 0008 ff02  ................
//	   0x0030:  0000 0000 0000 0000 0000 0000 0001 8800  ................
//	   0x0040:  5083 8000 0000 fe80 0000 0000 0000 c801  P...............
//	   0x0050:  0eff fe88 0008                           ......
var testPPPoEICMPv6 = []byte{
	0xcc, 0x05, 0x0e, 0x88, 0x00, 0x00, 0xca, 0x01, 0x0e, 0x88, 0x00, 0x06, 0x88, 0x64, 0x11, 0x00,
	0x00, 0x11, 0x00, 0x42, 0x00, 0x57, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3a, 0xff, 0xfe, 0x80,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x0e, 0xff, 0xfe, 0x88, 0x00, 0x08, 0xff, 0x02,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, 0x00,
	0x50, 0x83, 0x80, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01,
	0x0e, 0xff, 0xfe, 0x88, 0x00, 0x08,
}

func TestPPPoEICMPv6(t *testing.T) {
	p := gopacket.NewPacket(testPPPoEICMPv6, LinkTypeEthernet, testDecodeOptions)
	if p.ErrorLayer() != nil {
		t.Error("Failed to decode packet:", p.ErrorLayer().Error())
	}
	checkLayers(p, []gopacket.LayerType{
		LayerTypeEthernet,
		LayerTypePPPoE,
		LayerTypePPP,
		LayerTypeIPv6,
		LayerTypeICMPv6,
		gopacket.LayerTypePayload,
	}, t)
	testSerialization(t, p, testPPPoEICMPv6)
}
func BenchmarkDecodePPPoEICMPv6(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gopacket.NewPacket(testPPPoEICMPv6, LinkTypeEthernet, gopacket.NoCopy)
	}
}

var testPFLogUDP = []byte{
	0x3d, 0x02, 0x00, 0x00, 0x65, 0x6e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x6c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0xff, 0xff, 0xff, 0x7f,
	0xa0, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xb8, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
	0x45, 0x00, 0x00, 0x2c, 0x02, 0x16, 0x00, 0x00, 0x40, 0x11, 0x4e, 0xb0, 0xac, 0x17, 0xe8, 0xcc,
	0xac, 0x17, 0xe8, 0xff, 0xf0, 0xff, 0x21, 0xa4, 0x00, 0x18, 0x2a, 0x25, 0x50, 0x4e, 0x4a, 0x50,
	0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}

func TestPFLogUDP(t *testing.T) {
	p := gopacket.NewPacket(testPFLogUDP, LinkTypePFLog, testDecodeOptions)
	if p.ErrorLayer() != nil {
		t.Error("Failed to decode packet:", p.ErrorLayer().Error())
	}
	checkLayers(p, []gopacket.LayerType{
		LayerTypePFLog,
		LayerTypeIPv4,
		LayerTypeUDP,
		gopacket.LayerTypePayload,
	}, t)
}

func TestRegressionDot1QPriority(t *testing.T) {
	d := &Dot1Q{
		Priority: 2,
	}
	out := gopacket.NewSerializeBuffer()
	gopacket.SerializeLayers(out, gopacket.SerializeOptions{}, d)
	if err := d.DecodeFromBytes(out.Bytes(), gopacket.NilDecodeFeedback); err != nil {
		t.Errorf("could not decode encoded dot1q")
	} else if d.Priority != 2 {
		t.Errorf("priority mismatch, want 2 got %d", d.Priority)
	}
}

// testPacketMPLSInMPLS is the packet:
//
//	15:27:44.753678 MPLS (label 18, exp 0, ttl 255) (label 16, exp 0, [S], ttl
//	255) IP 10.31.0.1 > 10.34.0.1: ICMP echo request, id 3941, seq 4768, length
//	80
//	   0x0000:  0030 96e6 fc39 0030 9605 2838 8847 0001  .0...9.0..(8.G..
//	   0x0010:  20ff 0001 01ff 4500 0064 0050 0000 ff01  ......E..d.P....
//	   0x0020:  a706 0a1f 0001 0a22 0001 0800 bd11 0f65  .......".......e
//	   0x0030:  12a0 0000 0000 0053 9ee0 abcd abcd abcd  .......S........
//	   0x0040:  abcd abcd abcd abcd abcd abcd abcd abcd  ................
//	   0x0050:  abcd abcd abcd abcd abcd abcd abcd abcd  ................
//	   0x0060:  abcd abcd abcd abcd abcd abcd abcd abcd  ................
//	   0x0070:  abcd abcd abcd abcd abcd                 ..........
var testPacketMPLSInMPLS = []byte{
	0x00, 0x30, 0x96, 0xe6, 0xfc, 0x39, 0x00, 0x30, 0x96, 0x05, 0x28, 0x38, 0x88, 0x47, 0x00, 0x01,
	0x20, 0xff, 0x00, 0x01, 0x01, 0xff, 0x45, 0x00, 0x00, 0x64, 0x00, 0x50, 0x00, 0x00, 0xff, 0x01,
	0xa7, 0x06, 0x0a, 0x1f, 0x00, 0x01, 0x0a, 0x22, 0x00, 0x01, 0x08, 0x00, 0xbd, 0x11, 0x0f, 0x65,
	0x12, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x9e, 0xe0, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
	0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
	0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
	0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
	0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
}

func TestPacketMPLSInMPLS(t *testing.T) {
	p := gopacket.NewPacket(testPacketMPLSInMPLS, LinkTypeEthernet, testDecodeOptions)
	if p.ErrorLayer() != nil {
		t.Error("Failed to decode packet:", p.ErrorLayer().Error())
	}
	checkLayers(p, []gopacket.LayerType{
		LayerTypeEthernet,
		LayerTypeMPLS,
		LayerTypeMPLS,
		LayerTypeIPv4,
		LayerTypeICMPv4,
		gopacket.LayerTypePayload}, t)
}

// testPacketIPv4Fragmented is the packet:
//
//	22:11:26.616090 IP 10.1.1.1.31915 > 129.111.30.27.20197: UDP, length 28
//	   0x0000:  0000 39cf d9cd 0040 33d9 7cfd 0800 4500  ..9....@3.|...E.
//	   0x0010:  0038 00f2 2000 4011 af37 0a01 0101 816f  .8....@..7.....o
//	   0x0020:  1e1b 7cab 4ee5 0024 0000 0000 0000 0000  ..|.N..$........
//	   0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................
//	   0x0040:  0000 0000 0000                           ......
var testPacketIPv4Fragmented = []byte{
	0x00, 0x00, 0x39, 0xcf, 0xd9, 0xcd, 0x00, 0x40, 0x33, 0xd9, 0x7c, 0xfd, 0x08, 0x00, 0x45, 0x00,
	0x00, 0x38, 0x00, 0xf2, 0x20, 0x00, 0x40, 0x11, 0xaf, 0x37, 0x0a, 0x01, 0x01, 0x01, 0x81, 0x6f,
	0x1e, 0x1b, 0x7c, 0xab, 0x4e, 0xe5, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}

func TestPacketIPv4Fragmented(t *testing.T) {
	p := gopacket.NewPacket(testPacketIPv4Fragmented, LinkTypeEthernet, testDecodeOptions)
	if p.ErrorLayer() != nil {
		t.Error("Failed to decode packet:", p.ErrorLayer().Error())
	}
	checkLayers(p, []gopacket.LayerType{LayerTypeEthernet, LayerTypeIPv4, gopacket.LayerTypeFragment}, t)
	testSerializationWithOpts(t, p, testPacketIPv4Fragmented, gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true})
}

// TestSCTPChunkBadLength tests for issue #146
func TestSCTPChunkBadLength(t *testing.T) {
	data := []byte(
		"0000\xad9$e\x11\xe4\xaeo\b\x00E\x00\x018\xb4\xa3" +
			"\x00\x00Y\x84\xc4@\x11gz\xc0\xa8\xee\x01\xc0\xa8" +
			"\xeeD\x007le\x03\x01\xc0\f\xdf\b\x01\x00\x00")

	// this panic'd previously due to a zero length chunk getting
	// repeatedly read
	gopacket.NewPacket(data, LinkTypeEthernet, gopacket.Default)
}

// TestSTP
func TestSTP(t *testing.T) {
	testSTPpacket := []byte{
		0x01, 0x80, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0E, 0x87, 0x85, 0x04, 0x00, 0x26, 0x42, 0x42,
		0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x64, 0x00, 0x1C, 0x0E, 0x87, 0x78, 0x00, 0x00, 0x00,
		0x00, 0x04, 0x80, 0x64, 0x00, 0x1C, 0x0E, 0x87, 0x85, 0x00, 0x80, 0x04, 0x01, 0x00, 0x14, 0x00,
		0x02, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	}
	p := gopacket.NewPacket(testSTPpacket, LinkTypeEthernet, testDecodeOptions)
	checkLayers(p, []gopacket.LayerType{LayerTypeEthernet, LayerTypeLLC, LayerTypeSTP}, t)
}
