WIP [VOL-2811] - Incorporate preliminary onu-adapter-go code into opencord repo

- reason "discovery-mibsync-complete" reached (via full MibUpload only, received data won't be stored yet)
- first review comments of patchset #4 considered
 (please have a look into our inline-comments in Gerrit to know more about the current state)
- no refactoring done yet

Change-Id: Iac47817f8ce4bd28dd8132f530b0570d57ae99b8
Signed-off-by: Holger Hildebrandt <holger.hildebrandt@adtran.com>
diff --git a/vendor/github.com/google/gopacket/layers/mldv2.go b/vendor/github.com/google/gopacket/layers/mldv2.go
new file mode 100644
index 0000000..248cf74
--- /dev/null
+++ b/vendor/github.com/google/gopacket/layers/mldv2.go
@@ -0,0 +1,619 @@
+// Copyright 2018 GoPacket Authors. 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"
+	"math"
+	"net"
+	"time"
+
+	"github.com/google/gopacket"
+)
+
+const (
+	// S Flag bit is 1
+	mldv2STrue uint8 = 0x8
+
+	// S Flag value mask
+	//   mldv2STrue & mldv2SMask == mldv2STrue  // true
+	//          0x1 & mldv2SMask == mldv2STrue  // true
+	//          0x0 & mldv2SMask == mldv2STrue  // false
+	mldv2SMask uint8 = 0x8
+
+	// QRV value mask
+	mldv2QRVMask uint8 = 0x7
+)
+
+// MLDv2MulticastListenerQueryMessage are sent by multicast routers to query the
+// multicast listening state of neighboring interfaces.
+// https://tools.ietf.org/html/rfc3810#section-5.1
+//
+// Some information, like Maximum Response Code and Multicast Address are in the
+// previous layer LayerTypeMLDv1MulticastListenerQuery
+type MLDv2MulticastListenerQueryMessage struct {
+	BaseLayer
+	// 5.1.3. Maximum Response Delay COde
+	MaximumResponseCode uint16
+	// 5.1.5. Multicast Address
+	// Zero in general query
+	// Specific IPv6 multicast address otherwise
+	MulticastAddress net.IP
+	// 5.1.7. S Flag (Suppress Router-Side Processing)
+	SuppressRoutersideProcessing bool
+	// 5.1.8. QRV (Querier's Robustness Variable)
+	QueriersRobustnessVariable uint8
+	// 5.1.9. QQIC (Querier's Query Interval Code)
+	QueriersQueryIntervalCode uint8
+	// 5.1.10. Number of Sources (N)
+	NumberOfSources uint16
+	// 5.1.11 Source Address [i]
+	SourceAddresses []net.IP
+}
+
+// DecodeFromBytes decodes the given bytes into this layer.
+func (m *MLDv2MulticastListenerQueryMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
+	if len(data) < 24 {
+		df.SetTruncated()
+		return errors.New("ICMP layer less than 24 bytes for Multicast Listener Query Message V2")
+	}
+
+	m.MaximumResponseCode = binary.BigEndian.Uint16(data[0:2])
+	// ignore data[2:4] as per https://tools.ietf.org/html/rfc3810#section-5.1.4
+	m.MulticastAddress = data[4:20]
+	m.SuppressRoutersideProcessing = (data[20] & mldv2SMask) == mldv2STrue
+	m.QueriersRobustnessVariable = data[20] & mldv2QRVMask
+	m.QueriersQueryIntervalCode = data[21]
+
+	m.NumberOfSources = binary.BigEndian.Uint16(data[22:24])
+
+	var end int
+	for i := uint16(0); i < m.NumberOfSources; i++ {
+		begin := 24 + (int(i) * 16)
+		end = begin + 16
+
+		if end > len(data) {
+			df.SetTruncated()
+			return fmt.Errorf("ICMP layer less than %d bytes for Multicast Listener Query Message V2", end)
+		}
+
+		m.SourceAddresses = append(m.SourceAddresses, data[begin:end])
+	}
+
+	return nil
+}
+
+// NextLayerType returns the layer type contained by this DecodingLayer.
+func (*MLDv2MulticastListenerQueryMessage) NextLayerType() gopacket.LayerType {
+	return gopacket.LayerTypeZero
+}
+
+// SerializeTo writes the serialized form of this layer into the
+// SerializationBuffer, implementing gopacket.SerializableLayer.
+// See the docs for gopacket.SerializableLayer for more info.
+func (m *MLDv2MulticastListenerQueryMessage) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	if err := m.serializeSourceAddressesTo(b, opts); err != nil {
+		return err
+	}
+
+	buf, err := b.PrependBytes(24)
+	if err != nil {
+		return err
+	}
+
+	binary.BigEndian.PutUint16(buf[0:2], m.MaximumResponseCode)
+	copy(buf[2:4], []byte{0x00, 0x00}) // set reserved bytes to zero
+
+	ma16 := m.MulticastAddress.To16()
+	if ma16 == nil {
+		return fmt.Errorf("invalid MulticastAddress '%s'", m.MulticastAddress)
+	}
+	copy(buf[4:20], ma16)
+
+	byte20 := m.QueriersRobustnessVariable & mldv2QRVMask
+	if m.SuppressRoutersideProcessing {
+		byte20 |= mldv2STrue
+	} else {
+		byte20 &= ^mldv2STrue // the complement of mldv2STrue
+	}
+	byte20 &= 0x0F // set reserved bits to zero
+	buf[20] = byte20
+
+	binary.BigEndian.PutUint16(buf[22:24], m.NumberOfSources)
+	buf[21] = m.QueriersQueryIntervalCode
+
+	return nil
+}
+
+// writes each source address to the buffer preserving the order
+func (m *MLDv2MulticastListenerQueryMessage) serializeSourceAddressesTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	numberOfSourceAddresses := len(m.SourceAddresses)
+	if numberOfSourceAddresses > math.MaxUint16 {
+		return fmt.Errorf(
+			"there are more than %d source addresses, but 65535 is the maximum number of supported addresses",
+			numberOfSourceAddresses)
+	}
+
+	if opts.FixLengths {
+		m.NumberOfSources = uint16(numberOfSourceAddresses)
+	}
+
+	lastSAIdx := numberOfSourceAddresses - 1
+	for k := range m.SourceAddresses {
+		i := lastSAIdx - k // reverse order
+
+		buf, err := b.PrependBytes(16)
+		if err != nil {
+			return err
+		}
+
+		sa16 := m.SourceAddresses[i].To16()
+		if sa16 == nil {
+			return fmt.Errorf("invalid source address [%d] '%s'", i, m.SourceAddresses[i])
+		}
+		copy(buf[0:16], sa16)
+	}
+
+	return nil
+}
+
+// String sums this layer up nicely formatted
+func (m *MLDv2MulticastListenerQueryMessage) String() string {
+	return fmt.Sprintf(
+		"Maximum Response Code: %#x (%dms), Multicast Address: %s, Suppress Routerside Processing: %t, QRV: %#x, QQIC: %#x (%ds), Number of Source Address: %d (actual: %d), Source Addresses: %s",
+		m.MaximumResponseCode,
+		m.MaximumResponseDelay(),
+		m.MulticastAddress,
+		m.SuppressRoutersideProcessing,
+		m.QueriersRobustnessVariable,
+		m.QueriersQueryIntervalCode,
+		m.QQI()/time.Second,
+		m.NumberOfSources,
+		len(m.SourceAddresses),
+		m.SourceAddresses)
+}
+
+// LayerType returns LayerTypeMLDv2MulticastListenerQuery.
+func (*MLDv2MulticastListenerQueryMessage) LayerType() gopacket.LayerType {
+	return LayerTypeMLDv2MulticastListenerQuery
+}
+
+// CanDecode returns the set of layer types that this DecodingLayer can decode.
+func (*MLDv2MulticastListenerQueryMessage) CanDecode() gopacket.LayerClass {
+	return LayerTypeMLDv2MulticastListenerQuery
+}
+
+// QQI calculates the Querier's Query Interval based on the QQIC
+// according to https://tools.ietf.org/html/rfc3810#section-5.1.9
+func (m *MLDv2MulticastListenerQueryMessage) QQI() time.Duration {
+	data := m.QueriersQueryIntervalCode
+	if data < 128 {
+		return time.Second * time.Duration(data)
+	}
+
+	exp := uint16(data) & 0x70 >> 4
+	mant := uint16(data) & 0x0F
+	return time.Second * time.Duration(mant|0x1000<<(exp+3))
+}
+
+// SetQQI calculates and updates the Querier's Query Interval Code (QQIC)
+// according to https://tools.ietf.org/html/rfc3810#section-5.1.9
+func (m *MLDv2MulticastListenerQueryMessage) SetQQI(d time.Duration) error {
+	if d < 0 {
+		m.QueriersQueryIntervalCode = 0
+		return errors.New("QQI duration is negative")
+	}
+
+	if d == 0 {
+		m.QueriersQueryIntervalCode = 0
+		return nil
+	}
+
+	dms := d / time.Second
+	if dms < 128 {
+		m.QueriersQueryIntervalCode = uint8(dms)
+	}
+
+	if dms > 31744 { // mant=0xF, exp=0x7
+		m.QueriersQueryIntervalCode = 0xFF
+		return fmt.Errorf("QQI duration %ds is, maximum allowed is 31744s", dms)
+	}
+
+	value := uint16(dms) // ok, because 31744 < math.MaxUint16
+	exp := uint8(7)
+	for mask := uint16(0x4000); exp > 0; exp-- {
+		if mask&value != 0 {
+			break
+		}
+
+		mask >>= 1
+	}
+
+	mant := uint8(0x000F & (value >> (exp + 3)))
+	sig := uint8(0x10)
+	m.QueriersQueryIntervalCode = sig | exp<<4 | mant
+
+	return nil
+}
+
+// MaximumResponseDelay returns the Maximum Response Delay based on the
+// Maximum Response Code according to
+// https://tools.ietf.org/html/rfc3810#section-5.1.3
+func (m *MLDv2MulticastListenerQueryMessage) MaximumResponseDelay() time.Duration {
+	if m.MaximumResponseCode < 0x8000 {
+		return time.Duration(m.MaximumResponseCode)
+	}
+
+	exp := m.MaximumResponseCode & 0x7000 >> 12
+	mant := m.MaximumResponseCode & 0x0FFF
+
+	return time.Millisecond * time.Duration(mant|0x1000<<(exp+3))
+}
+
+// SetMLDv2MaximumResponseDelay updates the Maximum Response Code according to
+// https://tools.ietf.org/html/rfc3810#section-5.1.3
+func (m *MLDv2MulticastListenerQueryMessage) SetMLDv2MaximumResponseDelay(d time.Duration) error {
+	if d == 0 {
+		m.MaximumResponseCode = 0
+		return nil
+	}
+
+	if d < 0 {
+		return errors.New("maximum response delay must not be negative")
+	}
+
+	dms := d / time.Millisecond
+
+	if dms < 32768 {
+		m.MaximumResponseCode = uint16(dms)
+	}
+
+	if dms > 4193280 { // mant=0xFFF, exp=0x7
+		return fmt.Errorf("maximum response delay %dms is bigger the than maximum of 4193280ms", dms)
+	}
+
+	value := uint32(dms) // ok, because 4193280 < math.MaxUint32
+	exp := uint8(7)
+	for mask := uint32(0x40000000); exp > 0; exp-- {
+		if mask&value != 0 {
+			break
+		}
+
+		mask >>= 1
+	}
+
+	mant := uint16(0x00000FFF & (value >> (exp + 3)))
+	sig := uint16(0x1000)
+	m.MaximumResponseCode = sig | uint16(exp)<<12 | mant
+	return nil
+}
+
+// MLDv2MulticastListenerReportMessage is sent by an IP node to report the
+// current multicast listening state, or changes therein.
+// https://tools.ietf.org/html/rfc3810#section-5.2
+type MLDv2MulticastListenerReportMessage struct {
+	BaseLayer
+	// 5.2.3. Nr of Mcast Address Records
+	NumberOfMulticastAddressRecords uint16
+	// 5.2.4. Multicast Address Record [i]
+	MulticastAddressRecords []MLDv2MulticastAddressRecord
+}
+
+// DecodeFromBytes decodes the given bytes into this layer.
+func (m *MLDv2MulticastListenerReportMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
+	if len(data) < 4 {
+		df.SetTruncated()
+		return errors.New("ICMP layer less than 4 bytes for Multicast Listener Report Message V2")
+	}
+
+	// ignore data[0:2] as per RFC
+	// https://tools.ietf.org/html/rfc3810#section-5.2.1
+	m.NumberOfMulticastAddressRecords = binary.BigEndian.Uint16(data[2:4])
+
+	begin := 4
+	for i := uint16(0); i < m.NumberOfMulticastAddressRecords; i++ {
+		mar := MLDv2MulticastAddressRecord{}
+		read, err := mar.decode(data[begin:], df)
+		if err != nil {
+			return err
+		}
+
+		m.MulticastAddressRecords = append(m.MulticastAddressRecords, mar)
+
+		begin += read
+	}
+
+	return nil
+}
+
+// SerializeTo writes the serialized form of this layer into the
+// SerializationBuffer, implementing gopacket.SerializableLayer.
+// See the docs for gopacket.SerializableLayer for more info.
+func (m *MLDv2MulticastListenerReportMessage) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	lastItemIdx := len(m.MulticastAddressRecords) - 1
+	for k := range m.MulticastAddressRecords {
+		i := lastItemIdx - k // reverse order
+
+		err := m.MulticastAddressRecords[i].serializeTo(b, opts)
+		if err != nil {
+			return err
+		}
+	}
+
+	if opts.FixLengths {
+		numberOfMAR := len(m.MulticastAddressRecords)
+		if numberOfMAR > math.MaxUint16 {
+			return fmt.Errorf(
+				"%d multicast address records added, but the maximum is 65535",
+				numberOfMAR)
+		}
+
+		m.NumberOfMulticastAddressRecords = uint16(numberOfMAR)
+	}
+
+	buf, err := b.PrependBytes(4)
+	if err != nil {
+		return err
+	}
+
+	copy(buf[0:2], []byte{0x0, 0x0})
+	binary.BigEndian.PutUint16(buf[2:4], m.NumberOfMulticastAddressRecords)
+	return nil
+}
+
+// Sums this layer up nicely formatted
+func (m *MLDv2MulticastListenerReportMessage) String() string {
+	return fmt.Sprintf(
+		"Number of Mcast Addr Records: %d (actual %d), Multicast Address Records: %+v",
+		m.NumberOfMulticastAddressRecords,
+		len(m.MulticastAddressRecords),
+		m.MulticastAddressRecords)
+}
+
+// LayerType returns LayerTypeMLDv2MulticastListenerQuery.
+func (*MLDv2MulticastListenerReportMessage) LayerType() gopacket.LayerType {
+	return LayerTypeMLDv2MulticastListenerReport
+}
+
+// CanDecode returns the set of layer types that this DecodingLayer can decode.
+func (*MLDv2MulticastListenerReportMessage) CanDecode() gopacket.LayerClass {
+	return LayerTypeMLDv2MulticastListenerReport
+}
+
+// NextLayerType returns the layer type contained by this DecodingLayer.
+func (*MLDv2MulticastListenerReportMessage) NextLayerType() gopacket.LayerType {
+	return gopacket.LayerTypePayload
+}
+
+// MLDv2MulticastAddressRecordType holds the type of a
+// Multicast Address Record, according to
+// https://tools.ietf.org/html/rfc3810#section-5.2.5 and
+// https://tools.ietf.org/html/rfc3810#section-5.2.12
+type MLDv2MulticastAddressRecordType uint8
+
+const (
+	// MLDv2MulticastAddressRecordTypeModeIsIncluded stands for
+	// MODE_IS_INCLUDE - indicates that the interface has a filter
+	// mode of INCLUDE for the specified multicast address.
+	MLDv2MulticastAddressRecordTypeModeIsIncluded MLDv2MulticastAddressRecordType = 1
+	// MLDv2MulticastAddressRecordTypeModeIsExcluded stands for
+	// MODE_IS_EXCLUDE - indicates that the interface has a filter
+	// mode of EXCLUDE for the specified multicast address.
+	MLDv2MulticastAddressRecordTypeModeIsExcluded MLDv2MulticastAddressRecordType = 2
+	// MLDv2MulticastAddressRecordTypeChangeToIncludeMode stands for
+	// CHANGE_TO_INCLUDE_MODE - indicates that the interface has
+	// changed to INCLUDE filter mode for the specified multicast
+	// address.
+	MLDv2MulticastAddressRecordTypeChangeToIncludeMode MLDv2MulticastAddressRecordType = 3
+	// MLDv2MulticastAddressRecordTypeChangeToExcludeMode stands for
+	// CHANGE_TO_EXCLUDE_MODE - indicates that the interface has
+	// changed to EXCLUDE filter mode for the specified multicast
+	// address
+	MLDv2MulticastAddressRecordTypeChangeToExcludeMode MLDv2MulticastAddressRecordType = 4
+	// MLDv2MulticastAddressRecordTypeAllowNewSources stands for
+	// ALLOW_NEW_SOURCES - indicates that the Source Address [i]
+	// fields in this Multicast Address Record contain a list of
+	// the additional sources that the node wishes to listen to,
+	// for packets sent to the specified multicast address.
+	MLDv2MulticastAddressRecordTypeAllowNewSources MLDv2MulticastAddressRecordType = 5
+	// MLDv2MulticastAddressRecordTypeBlockOldSources stands for
+	// BLOCK_OLD_SOURCES - indicates that the Source Address [i]
+	// fields in this Multicast Address Record contain a list of
+	// the sources that the node no longer wishes to listen to,
+	// for packets sent to the specified multicast address.
+	MLDv2MulticastAddressRecordTypeBlockOldSources MLDv2MulticastAddressRecordType = 6
+)
+
+// Human readable record types
+// Naming follows https://tools.ietf.org/html/rfc3810#section-5.2.12
+func (m MLDv2MulticastAddressRecordType) String() string {
+	switch m {
+	case MLDv2MulticastAddressRecordTypeModeIsIncluded:
+		return "MODE_IS_INCLUDE"
+	case MLDv2MulticastAddressRecordTypeModeIsExcluded:
+		return "MODE_IS_EXCLUDE"
+	case MLDv2MulticastAddressRecordTypeChangeToIncludeMode:
+		return "CHANGE_TO_INCLUDE_MODE"
+	case MLDv2MulticastAddressRecordTypeChangeToExcludeMode:
+		return "CHANGE_TO_EXCLUDE_MODE"
+	case MLDv2MulticastAddressRecordTypeAllowNewSources:
+		return "ALLOW_NEW_SOURCES"
+	case MLDv2MulticastAddressRecordTypeBlockOldSources:
+		return "BLOCK_OLD_SOURCES"
+	default:
+		return fmt.Sprintf("UNKNOWN(%d)", m)
+	}
+}
+
+// MLDv2MulticastAddressRecord contains information on the sender listening to a
+// single multicast address on the interface the report is sent.
+// https://tools.ietf.org/html/rfc3810#section-5.2.4
+type MLDv2MulticastAddressRecord struct {
+	// 5.2.5. Record Type
+	RecordType MLDv2MulticastAddressRecordType
+	// 5.2.6. Auxiliary Data Length (number of 32-bit words)
+	AuxDataLen uint8
+	// 5.2.7. Number Of Sources (N)
+	N uint16
+	// 5.2.8. Multicast Address
+	MulticastAddress net.IP
+	// 5.2.9 Source Address [i]
+	SourceAddresses []net.IP
+	// 5.2.10 Auxiliary Data
+	AuxiliaryData []byte
+}
+
+// decodes a multicast address record from bytes
+func (m *MLDv2MulticastAddressRecord) decode(data []byte, df gopacket.DecodeFeedback) (int, error) {
+	if len(data) < 4 {
+		df.SetTruncated()
+		return 0, errors.New(
+			"Multicast Listener Report Message V2 layer less than 4 bytes for Multicast Address Record")
+	}
+
+	m.RecordType = MLDv2MulticastAddressRecordType(data[0])
+	m.AuxDataLen = data[1]
+	m.N = binary.BigEndian.Uint16(data[2:4])
+	m.MulticastAddress = data[4:20]
+
+	for i := uint16(0); i < m.N; i++ {
+		begin := 20 + (int(i) * 16)
+		end := begin + 16
+
+		if len(data) < end {
+			df.SetTruncated()
+			return begin, fmt.Errorf(
+				"Multicast Listener Report Message V2 layer less than %d bytes for Multicast Address Record", end)
+		}
+
+		m.SourceAddresses = append(m.SourceAddresses, data[begin:end])
+	}
+
+	expectedLengthWithouAuxData := 20 + (int(m.N) * 16)
+	expectedTotalLength := (int(m.AuxDataLen) * 4) + expectedLengthWithouAuxData // *4 because AuxDataLen are 32bit words
+	if len(data) < expectedTotalLength {
+		return expectedLengthWithouAuxData, fmt.Errorf(
+			"Multicast Listener Report Message V2 layer less than %d bytes for Multicast Address Record",
+			expectedLengthWithouAuxData)
+	}
+
+	m.AuxiliaryData = data[expectedLengthWithouAuxData:expectedTotalLength]
+
+	return expectedTotalLength, nil
+}
+
+// String sums this layer up nicely formatted
+func (m *MLDv2MulticastAddressRecord) String() string {
+	return fmt.Sprintf(
+		"RecordType: %d (%s), AuxDataLen: %d [32-bit words], N: %d, Multicast Address: %s, SourceAddresses: %s, Auxiliary Data: %#x",
+		m.RecordType,
+		m.RecordType.String(),
+		m.AuxDataLen,
+		m.N,
+		m.MulticastAddress.To16(),
+		m.SourceAddresses,
+		m.AuxiliaryData)
+}
+
+// serializes a multicast address record
+func (m *MLDv2MulticastAddressRecord) serializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	if err := m.serializeAuxiliaryDataTo(b, opts); err != nil {
+		return err
+	}
+
+	if err := m.serializeSourceAddressesTo(b, opts); err != nil {
+		return err
+	}
+
+	buf, err := b.PrependBytes(20)
+	if err != nil {
+		return err
+	}
+
+	buf[0] = uint8(m.RecordType)
+	buf[1] = m.AuxDataLen
+	binary.BigEndian.PutUint16(buf[2:4], m.N)
+
+	ma16 := m.MulticastAddress.To16()
+	if ma16 == nil {
+		return fmt.Errorf("invalid multicast address '%s'", m.MulticastAddress)
+	}
+	copy(buf[4:20], ma16)
+
+	return nil
+}
+
+// serializes the auxiliary data of a multicast address record
+func (m *MLDv2MulticastAddressRecord) serializeAuxiliaryDataTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	if remainder := len(m.AuxiliaryData) % 4; remainder != 0 {
+		zeroWord := []byte{0x0, 0x0, 0x0, 0x0}
+		m.AuxiliaryData = append(m.AuxiliaryData, zeroWord[:remainder]...)
+	}
+
+	if opts.FixLengths {
+		auxDataLen := len(m.AuxiliaryData) / 4
+
+		if auxDataLen > math.MaxUint8 {
+			return fmt.Errorf("auxilary data is %d 32-bit words, but the maximum is 255 32-bit words", auxDataLen)
+		}
+
+		m.AuxDataLen = uint8(auxDataLen)
+	}
+
+	buf, err := b.PrependBytes(len(m.AuxiliaryData))
+	if err != nil {
+		return err
+	}
+
+	copy(buf, m.AuxiliaryData)
+	return nil
+}
+
+// serializes the source addresses of a multicast address record preserving the order
+func (m *MLDv2MulticastAddressRecord) serializeSourceAddressesTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	if opts.FixLengths {
+		numberOfSourceAddresses := len(m.SourceAddresses)
+
+		if numberOfSourceAddresses > math.MaxUint16 {
+			return fmt.Errorf(
+				"%d source addresses added, but the maximum is 65535",
+				numberOfSourceAddresses)
+		}
+
+		m.N = uint16(numberOfSourceAddresses)
+	}
+
+	lastItemIdx := len(m.SourceAddresses) - 1
+	for k := range m.SourceAddresses {
+		i := lastItemIdx - k // reverse order
+
+		buf, err := b.PrependBytes(16)
+		if err != nil {
+			return err
+		}
+
+		sa16 := m.SourceAddresses[i].To16()
+		if sa16 == nil {
+			return fmt.Errorf("invalid source address [%d] '%s'", i, m.SourceAddresses[i])
+		}
+		copy(buf, sa16)
+	}
+
+	return nil
+}
+
+func decodeMLDv2MulticastListenerReport(data []byte, p gopacket.PacketBuilder) error {
+	m := &MLDv2MulticastListenerReportMessage{}
+	return decodingLayerDecoder(m, data, p)
+}
+
+func decodeMLDv2MulticastListenerQuery(data []byte, p gopacket.PacketBuilder) error {
+	m := &MLDv2MulticastListenerQueryMessage{}
+	return decodingLayerDecoder(m, data, p)
+}