func newV2Sccrq(cfg *TunnelConfig) (msg *v2ControlMessage, err error) {
	in := []avpIn{
		{avpTypeMessage, avpMsgTypeSccrq},
		{avpTypeProtocolVersion, []byte{1, 0}},
		{avpTypeHostName, cfg.HostName},
		{avpTypeFramingCap, uint32(cfg.FramingCaps)},
		{avpTypeTunnelID, uint16(cfg.TunnelID)},
	}
	return buildV2Msg(0, 0, in)
}
newV2Sccrq builds a new SCCRQ message
package l2tp
import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
)
type l2tpCommonHeader struct {
	FlagsVer uint16
	Len      uint16
}
type l2tpV2Header struct {
	Common l2tpCommonHeader
	Tid    uint16
	Sid    uint16
	Ns     uint16
	Nr     uint16
}
type l2tpV3Header struct {
	Common l2tpCommonHeader
	Ccid   uint32
	Ns     uint16
	Nr     uint16
}
const (
	controlMessageMinLen = 12
	controlMessageMaxLen = ^uint16(0)
	commonHeaderLen      = 4
	v2HeaderLen          = 12
	v3HeaderLen          = 12
)
type avpSpec int
type msgSpec struct {
	m map[avpType]avpSpec
}
const (
	mustExist avpSpec = 1
	mayExist  avpSpec = 2
)
func (spec *msgSpec) hasAvp(t avpType) (avpSpec, bool) {
	as, ok := spec.m[t]
	return as, ok
}
func v2SccrqMsgSpec() *msgSpec {
	spec := msgSpec{make(map[avpType]avpSpec)}
	spec.m[avpTypeMessage] = mustExist
	spec.m[avpTypeProtocolVersion] = mustExist
	spec.m[avpTypeHostName] = mustExist
	spec.m[avpTypeFramingCap] = mustExist
	spec.m[avpTypeTunnelID] = mustExist
	spec.m[avpTypeBearerCap] = mayExist
	spec.m[avpTypeRxWindowSize] = mayExist
	spec.m[avpTypeChallenge] = mayExist
	spec.m[avpTypeTiebreaker] = mayExist
	spec.m[avpTypeFirmwareRevision] = mayExist
	spec.m[avpTypeVendorName] = mayExist
	return &spec
}
func v2SccrpMsgSpec() *msgSpec {
	spec := msgSpec{make(map[avpType]avpSpec)}
	spec.m[avpTypeMessage] = mustExist
	spec.m[avpTypeProtocolVersion] = mustExist
	spec.m[avpTypeFramingCap] = mustExist
	spec.m[avpTypeHostName] = mustExist
	spec.m[avpTypeTunnelID] = mustExist
	spec.m[avpTypeBearerCap] = mayExist
	spec.m[avpTypeRxWindowSize] = mayExist
	spec.m[avpTypeChallenge] = mayExist
	spec.m[avpTypeChallengeResponse] = mayExist
	spec.m[avpTypeTiebreaker] = mayExist
	spec.m[avpTypeFirmwareRevision] = mayExist
	spec.m[avpTypeVendorName] = mayExist
	return &spec
}
func v2ScccnMsgSpec() *msgSpec {
	spec := msgSpec{make(map[avpType]avpSpec)}
	spec.m[avpTypeMessage] = mustExist
	spec.m[avpTypeChallengeResponse] = mayExist
	return &spec
}
func v2StopccnMsgSpec() *msgSpec {
	spec := msgSpec{make(map[avpType]avpSpec)}
	spec.m[avpTypeMessage] = mustExist
	spec.m[avpTypeTunnelID] = mustExist
	spec.m[avpTypeResultCode] = mustExist
	return &spec
}
func v2HelloMsgSpec() *msgSpec {
	spec := msgSpec{make(map[avpType]avpSpec)}
	spec.m[avpTypeMessage] = mustExist
	return &spec
}
func v2IcrqMsgSpec() *msgSpec {
	spec := msgSpec{make(map[avpType]avpSpec)}
	spec.m[avpTypeMessage] = mustExist
	spec.m[avpTypeSessionID] = mustExist
	spec.m[avpTypeCallSerialNumber] = mustExist
	spec.m[avpTypeBearerType] = mayExist
	spec.m[avpTypePhysicalChannelID] = mayExist
	spec.m[avpTypeCallingNumber] = mayExist
	spec.m[avpTypeCalledNumber] = mayExist
	spec.m[avpTypeSubAddress] = mayExist
	return &spec
}
func v2IcrpMsgSpec() *msgSpec {
	spec := msgSpec{make(map[avpType]avpSpec)}
	spec.m[avpTypeMessage] = mustExist
	spec.m[avpTypeSessionID] = mustExist
	return &spec
}
func v2IccnMsgSpec() *msgSpec {
	spec := msgSpec{make(map[avpType]avpSpec)}
	spec.m[avpTypeMessage] = mustExist
	spec.m[avpTypeConnectSpeed] = mustExist
	spec.m[avpTypeFramingType] = mustExist
	spec.m[avpTypeInitialRcvdLcpConfreq] = mayExist
	spec.m[avpTypeLastSentLcpConfreq] = mayExist
	spec.m[avpTypeLastRcvdLcpConfreq] = mayExist
	spec.m[avpTypeProxyAuthType] = mayExist
	spec.m[avpTypeProxyAuthName] = mayExist
	spec.m[avpTypeProxyAuthChallenge] = mayExist
	spec.m[avpTypeProxyAuthID] = mayExist
	spec.m[avpTypeProxyAuthResponse] = mayExist
	spec.m[avpTypePrivGroupID] = mayExist
	spec.m[avpTypeRxConnectSpeed] = mayExist
	spec.m[avpTypeSequencingRequired] = mayExist
	return &spec
}
func v2CdnMsgSpec() *msgSpec {
	spec := msgSpec{make(map[avpType]avpSpec)}
	spec.m[avpTypeMessage] = mustExist
	spec.m[avpTypeResultCode] = mustExist
	spec.m[avpTypeSessionID] = mustExist
	spec.m[avpTypeQ931CauseCode] = mayExist
	return &spec
}
func getV2MsgSpec(t avpMsgType) (*msgSpec, error) {
	switch t {
	case avpMsgTypeSccrq:
		return v2SccrqMsgSpec(), nil
	case avpMsgTypeSccrp:
		return v2SccrpMsgSpec(), nil
	case avpMsgTypeScccn:
		return v2ScccnMsgSpec(), nil
	case avpMsgTypeStopccn:
		return v2StopccnMsgSpec(), nil
	case avpMsgTypeHello:
		return v2HelloMsgSpec(), nil
	case avpMsgTypeIcrq:
		return v2IcrqMsgSpec(), nil
	case avpMsgTypeIcrp:
		return v2IcrpMsgSpec(), nil
	case avpMsgTypeIccn:
		return v2IccnMsgSpec(), nil
	case avpMsgTypeCdn:
		return v2CdnMsgSpec(), nil
	}
	return nil, fmt.Errorf("no specification for v2 message %v", t)
}
func v3HelloMsgSpec() *msgSpec {
	spec := msgSpec{make(map[avpType]avpSpec)}
	spec.m[avpTypeMessage] = mustExist
	spec.m[avpTypeRandomVector] = mayExist
	spec.m[avpTypeMessageDigest] = mayExist
	return &spec
}
func getV3MsgSpec(t avpMsgType) (*msgSpec, error) {
	switch t {
	case avpMsgTypeHello:
		return v3HelloMsgSpec(), nil
	}
	return nil, fmt.Errorf("no specification for v3 message %v", t)
}
func (h *l2tpCommonHeader) protocolVersion() (version ProtocolVersion, err error) {
	switch h.FlagsVer & 0xf {
	case 2:
		return ProtocolVersion2, nil
	case 3:
		return ProtocolVersion3, nil
	}
	return 0, errors.New("illegal protocol version")
}
func validateAvps(avps []avp, spec *msgSpec) error {
	seen := make(map[avpType]bool)
	for at, as := range spec.m {
		if as == mustExist {
			seen[at] = false
		}
	}
	for _, avp := range avps {
		as, ok := spec.hasAvp(avp.getType())
		if !ok {
			if avp.isMandatory() {
				return fmt.Errorf("unexpected AVP %v", avp.getType())
			}
			continue
		}
		if as == mustExist {
			seen[avp.getType()] = true
		}
		_, err := avp.decode()
		if err != nil {
			return fmt.Errorf("failed to decode AVP %v: %v", avp.getType(), err)
		}
	}
	for at, ok := range seen {
		if !ok {
			return fmt.Errorf("missing mandatory AVP %v", at)
		}
	}
	return nil
}
func newL2tpV2MessageHeader(tid, sid, ns, nr uint16, payloadBytes int) *l2tpV2Header {
	return &l2tpV2Header{
		Common: l2tpCommonHeader{
			FlagsVer: 0xc802,
			Len:      uint16(v2HeaderLen + payloadBytes),
		},
		Tid: tid,
		Sid: sid,
		Ns:  ns,
		Nr:  nr,
	}
}
func newL2tpV3MessageHeader(ccid uint32, ns, nr uint16, payloadBytes int) *l2tpV3Header {
	return &l2tpV3Header{
		Common: l2tpCommonHeader{
			FlagsVer: 0xc803,
			Len:      uint16(v3HeaderLen + payloadBytes),
		},
		Ccid: ccid,
		Ns:   ns,
		Nr:   nr,
	}
}
func bytesToV2CtlMsg(b []byte) (msg *v2ControlMessage, err error) {
	var hdr l2tpV2Header
	var avps []avp
	r := bytes.NewReader(b)
	if err = binary.Read(r, binary.BigEndian, &hdr); err != nil {
		return nil, err
	}
	if hdr.Common.Len > v2HeaderLen {
		if avps, err = parseAVPBuffer(b[v2HeaderLen:hdr.Common.Len]); err != nil {
			return nil, err
		}
		if avps[0].getType() != avpTypeMessage {
			return nil, errors.New("invalid L2TPv2 message: first AVP is not Message Type AVP")
		}
	}
	return &v2ControlMessage{
		header: hdr,
		avps:   avps,
	}, nil
}
func bytesToV3CtlMsg(b []byte) (msg *v3ControlMessage, err error) {
	var hdr l2tpV3Header
	var avps []avp
	r := bytes.NewReader(b)
	if err = binary.Read(r, binary.BigEndian, &hdr); err != nil {
		return nil, err
	}
	if avps, err = parseAVPBuffer(b[v3HeaderLen:hdr.Common.Len]); err != nil {
		return nil, err
	}
	if avps[0].getType() != avpTypeMessage {
		return nil, errors.New("invalid L2TPv3 message: first AVP is not Message Type AVP")
	}
	return &v3ControlMessage{
		header: hdr,
		avps:   avps,
	}, nil
}
type controlMessage interface {
	protocolVersion() ProtocolVersion
	getLen() int
	ns() uint16
	nr() uint16
	getAvps() []avp
	getType() avpMsgType
	appendAvp(avp *avp)
	setTransportSeqNum(ns, nr uint16)
	toBytes() ([]byte, error)
	validate() error
}
type v2ControlMessage struct {
	header l2tpV2Header
	avps   []avp
}
type v3ControlMessage struct {
	header l2tpV3Header
	avps   []avp
}
func (m *v2ControlMessage) protocolVersion() ProtocolVersion {
	return ProtocolVersion2
}
func (m *v2ControlMessage) getLen() int {
	return int(m.header.Common.Len)
}
func (m *v2ControlMessage) ns() uint16 {
	return m.header.Ns
}
func (m *v2ControlMessage) nr() uint16 {
	return m.header.Nr
}
func (m *v2ControlMessage) getAvps() []avp {
	return m.avps
}
func (m v2ControlMessage) getType() avpMsgType {
	if len(m.getAvps()) == 0 {
		return avpMsgTypeAck
	}
	avp := m.getAvps()[0]
	if avp.getType() != avpTypeMessage {
		panic("Invalid L2TPv2 message")
	}
	mt, err := avp.decodeMsgType()
	if err != nil {
		panic(fmt.Sprintf("Failed to decode AVP message type: %v", err))
	}
	return mt
}
func (m *v2ControlMessage) Tid() uint16 {
	return m.header.Tid
}
func (m *v2ControlMessage) Sid() uint16 {
	return m.header.Sid
}
func (m *v2ControlMessage) appendAvp(avp *avp) {
	m.avps = append(m.avps, *avp)
	m.header.Common.Len += uint16(avp.totalLen())
}
func (m *v2ControlMessage) setTransportSeqNum(ns, nr uint16) {
	m.header.Ns = ns
	m.header.Nr = nr
}
func (m *v2ControlMessage) toBytes() ([]byte, error) {
	buf := new(bytes.Buffer)
	if err := binary.Write(buf, binary.BigEndian, m.header); err != nil {
		return nil, err
	}
	for _, avp := range m.avps {
		if err := binary.Write(buf, binary.BigEndian, avp.header); err != nil {
			return nil, err
		}
		if err := binary.Write(buf, binary.BigEndian, avp.payload.data); err != nil {
			return nil, err
		}
	}
	return buf.Bytes(), nil
}
func (m *v2ControlMessage) validate() error {
	spec, err := getV2MsgSpec(m.getType())
	if err != nil {
		return err
	}
	return validateAvps(m.avps, spec)
}
func (m *v3ControlMessage) protocolVersion() ProtocolVersion {
	return ProtocolVersion3
}
func (m *v3ControlMessage) getLen() int {
	return int(m.header.Common.Len)
}
func (m *v3ControlMessage) ns() uint16 {
	return m.header.Ns
}
func (m *v3ControlMessage) nr() uint16 {
	return m.header.Nr
}
func (m *v3ControlMessage) getAvps() []avp {
	return m.avps
}
func (m v3ControlMessage) getType() avpMsgType {
	avp := m.getAvps()[0]
	if avp.getType() != avpTypeMessage {
		panic("Invalid L2TPv3 message")
	}
	mt, err := avp.decodeMsgType()
	if err != nil {
		panic(fmt.Sprintf("Failed to decode AVP message type: %v", err))
	}
	return mt
}
func (m *v3ControlMessage) ControlConnectionID() uint32 {
	return m.header.Ccid
}
func (m *v3ControlMessage) appendAvp(avp *avp) {
	m.avps = append(m.avps, *avp)
	m.header.Common.Len += uint16(avp.totalLen())
}
func (m *v3ControlMessage) setTransportSeqNum(ns, nr uint16) {
	m.header.Ns = ns
	m.header.Nr = nr
}
func (m *v3ControlMessage) toBytes() ([]byte, error) {
	buf := new(bytes.Buffer)
	if err := binary.Write(buf, binary.BigEndian, m.header); err != nil {
		return nil, err
	}
	for _, avp := range m.avps {
		if err := binary.Write(buf, binary.BigEndian, avp.header); err != nil {
			return nil, err
		}
		if err := binary.Write(buf, binary.BigEndian, avp.payload.data); err != nil {
			return nil, err
		}
	}
	return buf.Bytes(), nil
}
func (m *v3ControlMessage) validate() error {
	spec, err := getV3MsgSpec(m.getType())
	if err != nil {
		return err
	}
	return validateAvps(m.avps, spec)
}
func parseMessageBuffer(b []byte) (messages []controlMessage, err error) {
	r := bytes.NewReader(b)
	for r.Len() >= controlMessageMinLen {
		var ver ProtocolVersion
		var h l2tpCommonHeader
		var cursor int64
		if cursor, err = r.Seek(0, io.SeekCurrent); err != nil {
			return nil, errors.New("malformed message buffer: unable to determine current offset")
		}
		if err := binary.Read(r, binary.BigEndian, &h); err != nil {
			return nil, err
		}
		if int(h.Len-commonHeaderLen) > r.Len() {
			return nil, fmt.Errorf("malformed header: length %d exceeds buffer bounds of %d", h.Len, r.Len())
		}
		if ver, err = h.protocolVersion(); err != nil {
			return nil, err
		}
		if ver == ProtocolVersion2 {
			var msg *v2ControlMessage
			if msg, err = bytesToV2CtlMsg(b[cursor : cursor+int64(h.Len)]); err != nil {
				return nil, err
			}
			messages = append(messages, msg)
		} else if ver == ProtocolVersion3 {
			var msg *v3ControlMessage
			if msg, err = bytesToV3CtlMsg(b[cursor : cursor+int64(+h.Len)]); err != nil {
				return nil, err
			}
			messages = append(messages, msg)
		} else {
			panic("Unhandled protocol version")
		}
		if _, err := r.Seek(int64(h.Len), io.SeekCurrent); err != nil {
			return nil, errors.New("malformed message buffer: invalid length for current message")
		}
	}
	return messages, nil
}
func newV2ControlMessage(tid ControlConnID, sid ControlConnID, avps []avp) (msg *v2ControlMessage, err error) {
	if tid > v2TidSidMax {
		return nil, fmt.Errorf("v2 tunnel ID %v out of range", tid)
	}
	if sid > v2TidSidMax {
		return nil, fmt.Errorf("v2 session ID %v out of range", sid)
	}
	return &v2ControlMessage{
		header: *newL2tpV2MessageHeader(uint16(tid), uint16(sid), 0, 0, avpsLengthBytes(avps)),
		avps:   avps,
	}, nil
}
type avpIn struct {
	typ  avpType
	data interface{}
}
func buildV2Msg(ptid ControlConnID, psid ControlConnID, in []avpIn) (msg *v2ControlMessage, err error) {
	msg, err = newV2ControlMessage(ptid, psid, []avp{})
	if err != nil {
		return
	}
	for _, i := range in {
		avp, err := newAvp(vendorIDIetf, i.typ, i.data)
		if err != nil {
			return nil, fmt.Errorf("failed to create AVP %v: %v", i.typ, err)
		}
		msg.appendAvp(avp)
	}
	return
}