// Copyright 2017 Google, Inc. 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 (
	"encoding/binary"
	"errors"
	"fmt"

	"github.com/gopacket/gopacket"
)

// OSPFType denotes what kind of OSPF type it is
type OSPFType uint8

// Potential values for OSPF.Type.
const (
	OSPFHello                   OSPFType = 1
	OSPFDatabaseDescription     OSPFType = 2
	OSPFLinkStateRequest        OSPFType = 3
	OSPFLinkStateUpdate         OSPFType = 4
	OSPFLinkStateAcknowledgment OSPFType = 5
)

// LSA Function Codes for LSAheader.LSType
const (
	RouterLSAtypeV2         = 0x1
	RouterLSAtype           = 0x2001
	NetworkLSAtypeV2        = 0x2
	NetworkLSAtype          = 0x2002
	SummaryLSANetworktypeV2 = 0x3
	InterAreaPrefixLSAtype  = 0x2003
	SummaryLSAASBRtypeV2    = 0x4
	InterAreaRouterLSAtype  = 0x2004
	ASExternalLSAtypeV2     = 0x5
	ASExternalLSAtype       = 0x4005
	NSSALSAtype             = 0x2007
	NSSALSAtypeV2           = 0x7
	LinkLSAtype             = 0x0008
	IntraAreaPrefixLSAtype  = 0x2009
)

// String conversions for OSPFType
func (i OSPFType) String() string {
	switch i {
	case OSPFHello:
		return "Hello"
	case OSPFDatabaseDescription:
		return "Database Description"
	case OSPFLinkStateRequest:
		return "Link State Request"
	case OSPFLinkStateUpdate:
		return "Link State Update"
	case OSPFLinkStateAcknowledgment:
		return "Link State Acknowledgment"
	default:
		return ""
	}
}

// Prefix extends IntraAreaPrefixLSA
type Prefix struct {
	PrefixLength  uint8
	PrefixOptions uint8
	Metric        uint16
	AddressPrefix []byte
}

// IntraAreaPrefixLSA is the struct from RFC 5340  A.4.10.
type IntraAreaPrefixLSA struct {
	NumOfPrefixes  uint16
	RefLSType      uint16
	RefLinkStateID uint32
	RefAdvRouter   uint32
	Prefixes       []Prefix
}

// LinkLSA is the struct from RFC 5340  A.4.9.
type LinkLSA struct {
	RtrPriority      uint8
	Options          uint32
	LinkLocalAddress []byte
	NumOfPrefixes    uint32
	Prefixes         []Prefix
}

// ASExternalLSAV2 is the struct from RFC 2328  A.4.5.
type ASExternalLSAV2 struct {
	NetworkMask       uint32
	ExternalBit       uint8
	Metric            uint32
	ForwardingAddress uint32
	ExternalRouteTag  uint32
}

// ASExternalLSA is the struct from RFC 5340  A.4.7.
type ASExternalLSA struct {
	Flags             uint8
	Metric            uint32
	PrefixLength      uint8
	PrefixOptions     uint8
	RefLSType         uint16
	AddressPrefix     []byte
	ForwardingAddress []byte
	ExternalRouteTag  uint32
	RefLinkStateID    uint32
}

// InterAreaRouterLSA is the struct from RFC 5340  A.4.6.
type InterAreaRouterLSA struct {
	Options             uint32
	Metric              uint32
	DestinationRouterID uint32
}

// InterAreaPrefixLSA is the struct from RFC 5340  A.4.5.
type InterAreaPrefixLSA struct {
	Metric        uint32
	PrefixLength  uint8
	PrefixOptions uint8
	AddressPrefix []byte
}

// NetworkLSA is the struct from RFC 5340  A.4.4.
type NetworkLSA struct {
	Options        uint32
	AttachedRouter []uint32
}

// NetworkLSAV2 is the struct from RFC 2328  A.4.3.
type NetworkLSAV2 struct {
	NetworkMask    uint32
	AttachedRouter []uint32
}

// RouterV2 extends RouterLSAV2
type RouterV2 struct {
	Type     uint8
	LinkID   uint32
	LinkData uint32
	Metric   uint16
}

// RouterLSAV2 is the struct from RFC 2328  A.4.2.
type RouterLSAV2 struct {
	Flags   uint8
	Links   uint16
	Routers []RouterV2
}

// Router extends RouterLSA
type Router struct {
	Type                uint8
	Metric              uint16
	InterfaceID         uint32
	NeighborInterfaceID uint32
	NeighborRouterID    uint32
}

// RouterLSA is the struct from RFC 5340  A.4.3.
type RouterLSA struct {
	Flags   uint8
	Options uint32
	Routers []Router
}

// LSAheader is the struct from RFC 5340  A.4.2 and RFC 2328 A.4.1.
type LSAheader struct {
	LSAge       uint16
	LSType      uint16
	LinkStateID uint32
	AdvRouter   uint32
	LSSeqNumber uint32
	LSChecksum  uint16
	Length      uint16
	LSOptions   uint8
}

// LSA links LSAheader with the structs from RFC 5340  A.4.
type LSA struct {
	LSAheader
	Content interface{}
}

// LSUpdate is the struct from RFC 5340  A.3.5.
type LSUpdate struct {
	NumOfLSAs uint32
	LSAs      []LSA
}

// LSReq is the struct from RFC 5340  A.3.4.
type LSReq struct {
	LSType    uint16
	LSID      uint32
	AdvRouter uint32
}

// DbDescPkg is the struct from RFC 5340  A.3.3.
type DbDescPkg struct {
	Options      uint32
	InterfaceMTU uint16
	Flags        uint16
	DDSeqNumber  uint32
	LSAinfo      []LSAheader
}

// HelloPkg  is the struct from RFC 5340  A.3.2.
type HelloPkg struct {
	InterfaceID              uint32
	RtrPriority              uint8
	Options                  uint32
	HelloInterval            uint16
	RouterDeadInterval       uint32
	DesignatedRouterID       uint32
	BackupDesignatedRouterID uint32
	NeighborID               []uint32
}

// HelloPkgV2 extends the HelloPkg struct with OSPFv2 information
type HelloPkgV2 struct {
	HelloPkg
	NetworkMask uint32
}

// OSPF is a basic OSPF packet header with common fields of Version 2 and Version 3.
type OSPF struct {
	Version      uint8
	Type         OSPFType
	PacketLength uint16
	RouterID     uint32
	AreaID       uint32
	Checksum     uint16
	Content      interface{}
}

// OSPFv2 extend the OSPF head with version 2 specific fields
type OSPFv2 struct {
	BaseLayer
	OSPF
	AuType         uint16
	Authentication uint64
}

// OSPFv3 extend the OSPF head with version 3 specific fields
type OSPFv3 struct {
	BaseLayer
	OSPF
	Instance uint8
	Reserved uint8
}

// getLSAsv2 parses the LSA information from the packet for OSPFv2
func getLSAsv2(num uint32, data []byte) ([]LSA, error) {
	var lsas []LSA
	var i uint32 = 0
	var offset uint32 = 0
	for ; i < num; i++ {
		lstype := uint16(data[offset+3])
		lsalength := binary.BigEndian.Uint16(data[offset+18 : offset+20])
		content, err := extractLSAInformation(lstype, lsalength, data[offset:])
		if err != nil {
			return nil, fmt.Errorf("Could not extract Link State type.")
		}
		lsa := LSA{
			LSAheader: LSAheader{
				LSAge:       binary.BigEndian.Uint16(data[offset : offset+2]),
				LSOptions:   data[offset+2],
				LSType:      lstype,
				LinkStateID: binary.BigEndian.Uint32(data[offset+4 : offset+8]),
				AdvRouter:   binary.BigEndian.Uint32(data[offset+8 : offset+12]),
				LSSeqNumber: binary.BigEndian.Uint32(data[offset+12 : offset+16]),
				LSChecksum:  binary.BigEndian.Uint16(data[offset+16 : offset+18]),
				Length:      lsalength,
			},
			Content: content,
		}
		lsas = append(lsas, lsa)
		offset += uint32(lsalength)
	}
	return lsas, nil
}

// extractLSAInformation extracts all the LSA information
func extractLSAInformation(lstype, lsalength uint16, data []byte) (interface{}, error) {
	if lsalength < 20 {
		return nil, fmt.Errorf("Link State header length %v too short, %v required", lsalength, 20)
	}
	if len(data) < int(lsalength) {
		return nil, fmt.Errorf("Link State header length %v too short, %v required", len(data), lsalength)
	}
	var content interface{}
	switch lstype {
	case RouterLSAtypeV2:
		var routers []RouterV2
		var j uint32
		for j = 24; j < uint32(lsalength); j += 12 {
			if len(data) < int(j+12) {
				return nil, errors.New("LSAtypeV2 too small")
			}
			router := RouterV2{
				LinkID:   binary.BigEndian.Uint32(data[j : j+4]),
				LinkData: binary.BigEndian.Uint32(data[j+4 : j+8]),
				Type:     uint8(data[j+8]),
				Metric:   binary.BigEndian.Uint16(data[j+10 : j+12]),
			}
			routers = append(routers, router)
		}
		if len(data) < 24 {
			return nil, errors.New("LSAtypeV2 too small")
		}
		links := binary.BigEndian.Uint16(data[22:24])
		content = RouterLSAV2{
			Flags:   data[20],
			Links:   links,
			Routers: routers,
		}
	case NSSALSAtypeV2:
		fallthrough
	case ASExternalLSAtypeV2:
		content = ASExternalLSAV2{
			NetworkMask:       binary.BigEndian.Uint32(data[20:24]),
			ExternalBit:       data[24] & 0x80,
			Metric:            binary.BigEndian.Uint32(data[24:28]) & 0x00FFFFFF,
			ForwardingAddress: binary.BigEndian.Uint32(data[28:32]),
			ExternalRouteTag:  binary.BigEndian.Uint32(data[32:36]),
		}
	case NetworkLSAtypeV2:
		var routers []uint32
		var j uint32
		for j = 24; j < uint32(lsalength); j += 4 {
			routers = append(routers, binary.BigEndian.Uint32(data[j:j+4]))
		}
		content = NetworkLSAV2{
			NetworkMask:    binary.BigEndian.Uint32(data[20:24]),
			AttachedRouter: routers,
		}
	case RouterLSAtype:
		var routers []Router
		var j uint32
		for j = 24; j < uint32(lsalength); j += 16 {
			router := Router{
				Type:                uint8(data[j]),
				Metric:              binary.BigEndian.Uint16(data[j+2 : j+4]),
				InterfaceID:         binary.BigEndian.Uint32(data[j+4 : j+8]),
				NeighborInterfaceID: binary.BigEndian.Uint32(data[j+8 : j+12]),
				NeighborRouterID:    binary.BigEndian.Uint32(data[j+12 : j+16]),
			}
			routers = append(routers, router)
		}
		content = RouterLSA{
			Flags:   uint8(data[20]),
			Options: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
			Routers: routers,
		}
	case NetworkLSAtype:
		var routers []uint32
		var j uint32
		for j = 24; j < uint32(lsalength); j += 4 {
			routers = append(routers, binary.BigEndian.Uint32(data[j:j+4]))
		}
		content = NetworkLSA{
			Options:        binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
			AttachedRouter: routers,
		}
	case InterAreaPrefixLSAtype:
		content = InterAreaPrefixLSA{
			Metric:        binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
			PrefixLength:  uint8(data[24]),
			PrefixOptions: uint8(data[25]),
			AddressPrefix: data[28:uint32(lsalength)],
		}
	case InterAreaRouterLSAtype:
		content = InterAreaRouterLSA{
			Options:             binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
			Metric:              binary.BigEndian.Uint32(data[24:28]) & 0x00FFFFFF,
			DestinationRouterID: binary.BigEndian.Uint32(data[28:32]),
		}
	case ASExternalLSAtype:
		fallthrough
	case NSSALSAtype:
		flags := uint8(data[20])
		prefixLen := uint8(data[24]) / 8
		var forwardingAddress []byte
		if (flags & 0x02) == 0x02 {
			forwardingAddress = data[28+uint32(prefixLen) : 28+uint32(prefixLen)+16]
		}
		content = ASExternalLSA{
			Flags:             flags,
			Metric:            binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
			PrefixLength:      prefixLen,
			PrefixOptions:     uint8(data[25]),
			RefLSType:         binary.BigEndian.Uint16(data[26:28]),
			AddressPrefix:     data[28 : 28+uint32(prefixLen)],
			ForwardingAddress: forwardingAddress,
		}
	case LinkLSAtype:
		var prefixes []Prefix
		var prefixOffset uint32 = 44
		var j uint32
		numOfPrefixes := binary.BigEndian.Uint32(data[40:44])
		for j = 0; j < numOfPrefixes; j++ {
			prefixLen := uint8(data[prefixOffset])
			prefix := Prefix{
				PrefixLength:  prefixLen,
				PrefixOptions: uint8(data[prefixOffset+1]),
				AddressPrefix: data[prefixOffset+4 : prefixOffset+4+uint32(prefixLen)/8],
			}
			prefixes = append(prefixes, prefix)
			prefixOffset = prefixOffset + 4 + uint32(prefixLen)/8
		}
		content = LinkLSA{
			RtrPriority:      uint8(data[20]),
			Options:          binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
			LinkLocalAddress: data[24:40],
			NumOfPrefixes:    numOfPrefixes,
			Prefixes:         prefixes,
		}
	case IntraAreaPrefixLSAtype:
		var prefixes []Prefix
		var prefixOffset uint32 = 32
		var j uint16
		numOfPrefixes := binary.BigEndian.Uint16(data[20:22])
		for j = 0; j < numOfPrefixes; j++ {
			prefixLen := uint8(data[prefixOffset])
			prefix := Prefix{
				PrefixLength:  prefixLen,
				PrefixOptions: uint8(data[prefixOffset+1]),
				Metric:        binary.BigEndian.Uint16(data[prefixOffset+2 : prefixOffset+4]),
				AddressPrefix: data[prefixOffset+4 : prefixOffset+4+uint32(prefixLen)/8],
			}
			prefixes = append(prefixes, prefix)
			prefixOffset = prefixOffset + 4 + uint32(prefixLen)
		}
		content = IntraAreaPrefixLSA{
			NumOfPrefixes:  numOfPrefixes,
			RefLSType:      binary.BigEndian.Uint16(data[22:24]),
			RefLinkStateID: binary.BigEndian.Uint32(data[24:28]),
			RefAdvRouter:   binary.BigEndian.Uint32(data[28:32]),
			Prefixes:       prefixes,
		}
	default:
		return nil, fmt.Errorf("Unknown Link State type.")
	}
	return content, nil
}

// getLSAs parses the LSA information from the packet for OSPFv3
func getLSAs(num uint32, data []byte) ([]LSA, error) {
	var lsas []LSA
	var i uint32 = 0
	var offset uint32 = 0
	for ; i < num; i++ {
		var content interface{}
		lstype := binary.BigEndian.Uint16(data[offset+2 : offset+4])
		lsalength := binary.BigEndian.Uint16(data[offset+18 : offset+20])

		content, err := extractLSAInformation(lstype, lsalength, data[offset:])
		if err != nil {
			return nil, fmt.Errorf("Could not extract Link State type.")
		}
		lsa := LSA{
			LSAheader: LSAheader{
				LSAge:       binary.BigEndian.Uint16(data[offset : offset+2]),
				LSType:      lstype,
				LinkStateID: binary.BigEndian.Uint32(data[offset+4 : offset+8]),
				AdvRouter:   binary.BigEndian.Uint32(data[offset+8 : offset+12]),
				LSSeqNumber: binary.BigEndian.Uint32(data[offset+12 : offset+16]),
				LSChecksum:  binary.BigEndian.Uint16(data[offset+16 : offset+18]),
				Length:      lsalength,
			},
			Content: content,
		}
		lsas = append(lsas, lsa)
		offset += uint32(lsalength)
	}
	return lsas, nil
}

// DecodeFromBytes decodes the given bytes into the OSPF layer.
func (ospf *OSPFv2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 24 {
		return fmt.Errorf("Packet too smal for OSPF Version 2")
	}

	ospf.Version = uint8(data[0])
	ospf.Type = OSPFType(data[1])
	ospf.PacketLength = binary.BigEndian.Uint16(data[2:4])
	ospf.RouterID = binary.BigEndian.Uint32(data[4:8])
	ospf.AreaID = binary.BigEndian.Uint32(data[8:12])
	ospf.Checksum = binary.BigEndian.Uint16(data[12:14])
	ospf.AuType = binary.BigEndian.Uint16(data[14:16])
	ospf.Authentication = binary.BigEndian.Uint64(data[16:24])

	switch ospf.Type {
	case OSPFHello:
		var neighbors []uint32
		for i := 44; uint16(i+4) <= ospf.PacketLength; i += 4 {
			neighbors = append(neighbors, binary.BigEndian.Uint32(data[i:i+4]))
		}
		ospf.Content = HelloPkgV2{
			NetworkMask: binary.BigEndian.Uint32(data[24:28]),
			HelloPkg: HelloPkg{
				HelloInterval:            binary.BigEndian.Uint16(data[28:30]),
				Options:                  uint32(data[30]),
				RtrPriority:              uint8(data[31]),
				RouterDeadInterval:       binary.BigEndian.Uint32(data[32:36]),
				DesignatedRouterID:       binary.BigEndian.Uint32(data[36:40]),
				BackupDesignatedRouterID: binary.BigEndian.Uint32(data[40:44]),
				NeighborID:               neighbors,
			},
		}
	case OSPFDatabaseDescription:
		var lsas []LSAheader
		for i := 32; uint16(i+20) <= ospf.PacketLength; i += 20 {
			lsa := LSAheader{
				LSAge:       binary.BigEndian.Uint16(data[i : i+2]),
				LSType:      binary.BigEndian.Uint16(data[i+2 : i+4]),
				LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]),
				AdvRouter:   binary.BigEndian.Uint32(data[i+8 : i+12]),
				LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]),
				LSChecksum:  binary.BigEndian.Uint16(data[i+16 : i+18]),
				Length:      binary.BigEndian.Uint16(data[i+18 : i+20]),
			}
			lsas = append(lsas, lsa)
		}
		ospf.Content = DbDescPkg{
			InterfaceMTU: binary.BigEndian.Uint16(data[24:26]),
			Options:      uint32(data[26]),
			Flags:        uint16(data[27]),
			DDSeqNumber:  binary.BigEndian.Uint32(data[28:32]),
			LSAinfo:      lsas,
		}
	case OSPFLinkStateRequest:
		var lsrs []LSReq
		for i := 24; uint16(i+12) <= ospf.PacketLength; i += 12 {
			lsr := LSReq{
				LSType:    binary.BigEndian.Uint16(data[i+2 : i+4]),
				LSID:      binary.BigEndian.Uint32(data[i+4 : i+8]),
				AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]),
			}
			lsrs = append(lsrs, lsr)
		}
		ospf.Content = lsrs
	case OSPFLinkStateUpdate:
		num := binary.BigEndian.Uint32(data[24:28])

		lsas, err := getLSAsv2(num, data[28:])
		if err != nil {
			return fmt.Errorf("Cannot parse Link State Update packet: %v", err)
		}
		ospf.Content = LSUpdate{
			NumOfLSAs: num,
			LSAs:      lsas,
		}
	case OSPFLinkStateAcknowledgment:
		var lsas []LSAheader
		for i := 24; uint16(i+20) <= ospf.PacketLength; i += 20 {
			lsa := LSAheader{
				LSAge:       binary.BigEndian.Uint16(data[i : i+2]),
				LSOptions:   data[i+2],
				LSType:      uint16(data[i+3]),
				LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]),
				AdvRouter:   binary.BigEndian.Uint32(data[i+8 : i+12]),
				LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]),
				LSChecksum:  binary.BigEndian.Uint16(data[i+16 : i+18]),
				Length:      binary.BigEndian.Uint16(data[i+18 : i+20]),
			}
			lsas = append(lsas, lsa)
		}
		ospf.Content = lsas
	}
	return nil
}

// DecodeFromBytes decodes the given bytes into the OSPF layer.
func (ospf *OSPFv3) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {

	if len(data) < 16 {
		return fmt.Errorf("Packet too smal for OSPF Version 3")
	}

	ospf.Version = uint8(data[0])
	ospf.Type = OSPFType(data[1])
	ospf.PacketLength = binary.BigEndian.Uint16(data[2:4])
	ospf.RouterID = binary.BigEndian.Uint32(data[4:8])
	ospf.AreaID = binary.BigEndian.Uint32(data[8:12])
	ospf.Checksum = binary.BigEndian.Uint16(data[12:14])
	ospf.Instance = uint8(data[14])
	ospf.Reserved = uint8(data[15])

	switch ospf.Type {
	case OSPFHello:
		var neighbors []uint32
		for i := 36; uint16(i+4) <= ospf.PacketLength; i += 4 {
			neighbors = append(neighbors, binary.BigEndian.Uint32(data[i:i+4]))
		}
		ospf.Content = HelloPkg{
			InterfaceID:              binary.BigEndian.Uint32(data[16:20]),
			RtrPriority:              uint8(data[20]),
			Options:                  binary.BigEndian.Uint32(data[21:25]) >> 8,
			HelloInterval:            binary.BigEndian.Uint16(data[24:26]),
			RouterDeadInterval:       uint32(binary.BigEndian.Uint16(data[26:28])),
			DesignatedRouterID:       binary.BigEndian.Uint32(data[28:32]),
			BackupDesignatedRouterID: binary.BigEndian.Uint32(data[32:36]),
			NeighborID:               neighbors,
		}
	case OSPFDatabaseDescription:
		var lsas []LSAheader
		for i := 28; uint16(i+20) <= ospf.PacketLength; i += 20 {
			lsa := LSAheader{
				LSAge:       binary.BigEndian.Uint16(data[i : i+2]),
				LSType:      binary.BigEndian.Uint16(data[i+2 : i+4]),
				LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]),
				AdvRouter:   binary.BigEndian.Uint32(data[i+8 : i+12]),
				LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]),
				LSChecksum:  binary.BigEndian.Uint16(data[i+16 : i+18]),
				Length:      binary.BigEndian.Uint16(data[i+18 : i+20]),
			}
			lsas = append(lsas, lsa)
		}
		ospf.Content = DbDescPkg{
			Options:      binary.BigEndian.Uint32(data[16:20]) & 0x00FFFFFF,
			InterfaceMTU: binary.BigEndian.Uint16(data[20:22]),
			Flags:        binary.BigEndian.Uint16(data[22:24]),
			DDSeqNumber:  binary.BigEndian.Uint32(data[24:28]),
			LSAinfo:      lsas,
		}
	case OSPFLinkStateRequest:
		var lsrs []LSReq
		for i := 16; uint16(i+12) <= ospf.PacketLength; i += 12 {
			lsr := LSReq{
				LSType:    binary.BigEndian.Uint16(data[i+2 : i+4]),
				LSID:      binary.BigEndian.Uint32(data[i+4 : i+8]),
				AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]),
			}
			lsrs = append(lsrs, lsr)
		}
		ospf.Content = lsrs
	case OSPFLinkStateUpdate:
		num := binary.BigEndian.Uint32(data[16:20])
		lsas, err := getLSAs(num, data[20:])
		if err != nil {
			return fmt.Errorf("Cannot parse Link State Update packet: %v", err)
		}
		ospf.Content = LSUpdate{
			NumOfLSAs: num,
			LSAs:      lsas,
		}

	case OSPFLinkStateAcknowledgment:
		var lsas []LSAheader
		for i := 16; uint16(i+20) <= ospf.PacketLength; i += 20 {
			lsa := LSAheader{
				LSAge:       binary.BigEndian.Uint16(data[i : i+2]),
				LSType:      binary.BigEndian.Uint16(data[i+2 : i+4]),
				LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]),
				AdvRouter:   binary.BigEndian.Uint32(data[i+8 : i+12]),
				LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]),
				LSChecksum:  binary.BigEndian.Uint16(data[i+16 : i+18]),
				Length:      binary.BigEndian.Uint16(data[i+18 : i+20]),
			}
			lsas = append(lsas, lsa)
		}
		ospf.Content = lsas
	default:
	}

	return nil
}

// LayerType returns LayerTypeOSPF
func (ospf *OSPFv2) LayerType() gopacket.LayerType {
	return LayerTypeOSPF
}
func (ospf *OSPFv3) LayerType() gopacket.LayerType {
	return LayerTypeOSPF
}

// NextLayerType returns the layer type contained by this DecodingLayer.
func (ospf *OSPFv2) NextLayerType() gopacket.LayerType {
	return gopacket.LayerTypeZero
}
func (ospf *OSPFv3) NextLayerType() gopacket.LayerType {
	return gopacket.LayerTypeZero
}

// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (ospf *OSPFv2) CanDecode() gopacket.LayerClass {
	return LayerTypeOSPF
}
func (ospf *OSPFv3) CanDecode() gopacket.LayerClass {
	return LayerTypeOSPF
}

func decodeOSPF(data []byte, p gopacket.PacketBuilder) error {
	if len(data) < 14 {
		return fmt.Errorf("Packet too smal for OSPF")
	}

	switch uint8(data[0]) {
	case 2:
		ospf := &OSPFv2{}
		return decodingLayerDecoder(ospf, data, p)
	case 3:
		ospf := &OSPFv3{}
		return decodingLayerDecoder(ospf, data, p)
	default:
	}

	return fmt.Errorf("Unable to determine OSPF type.")
}
