mldv2.go raw

   1  // Copyright 2022 The gVisor Authors.
   2  //
   3  // Licensed under the Apache License, Version 2.0 (the "License");
   4  // you may not use this file except in compliance with the License.
   5  // You may obtain a copy of the License at
   6  //
   7  //     http://www.apache.org/licenses/LICENSE-2.0
   8  //
   9  // Unless required by applicable law or agreed to in writing, software
  10  // distributed under the License is distributed on an "AS IS" BASIS,
  11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12  // See the License for the specific language governing permissions and
  13  // limitations under the License.
  14  
  15  package header
  16  
  17  import (
  18  	"bytes"
  19  	"encoding/binary"
  20  	"fmt"
  21  	"time"
  22  
  23  	"gvisor.dev/gvisor/pkg/tcpip"
  24  )
  25  
  26  const (
  27  	// MLDv2QueryMinimumSize is the minimum size for an MLDv2 message.
  28  	MLDv2QueryMinimumSize = 24
  29  
  30  	mldv2QueryMaximumResponseCodeOffset = 0
  31  	mldv2QueryResvSQRVOffset            = 20
  32  	mldv2QueryQRVMask                   = 0b111
  33  	mldv2QueryQQICOffset                = 21
  34  	// mldv2QueryNumberOfSourcesOffset is the offset to the Number of Sources
  35  	// field within MLDv2Query.
  36  	mldv2QueryNumberOfSourcesOffset = 22
  37  
  38  	// MLDv2ReportMinimumSize is the minimum size of an MLDv2 report.
  39  	MLDv2ReportMinimumSize = 24
  40  
  41  	// mldv2QuerySourcesOffset is the offset to the Sources field within
  42  	// MLDv2Query.
  43  	mldv2QuerySourcesOffset = 24
  44  )
  45  
  46  var (
  47  	// MLDv2RoutersAddress is the address to send MLDv2 reports to.
  48  	//
  49  	// As per RFC 3810 section 5.2.14,
  50  	//
  51  	//   Version 2 Multicast Listener Reports are sent with an IP destination
  52  	//   address of FF02:0:0:0:0:0:0:16, to which all MLDv2-capable multicast
  53  	//   routers listen (see section 11 for IANA considerations related to
  54  	//   this special destination address).
  55  	MLDv2RoutersAddress = tcpip.AddrFrom16([16]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16})
  56  )
  57  
  58  // MLDv2Query is a Multicast Listener Discovery Version 2 Query message in an
  59  // ICMPv6 packet.
  60  //
  61  // MLDv2Query will only contain the body of an ICMPv6 packet.
  62  //
  63  // As per RFC 3810 section 5.1, MLDv2 Query messages have the following format
  64  // (MLDv2Query only holds the bytes after the first four bytes in the diagram
  65  // below):
  66  //
  67  //	 0                   1                   2                   3
  68  //	 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  69  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  70  //	|  Type = 130   |      Code     |           Checksum            |
  71  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  72  //	|    Maximum Response Code      |           Reserved            |
  73  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  74  //	|                                                               |
  75  //	*                                                               *
  76  //	|                                                               |
  77  //	*                       Multicast Address                       *
  78  //	|                                                               |
  79  //	*                                                               *
  80  //	|                                                               |
  81  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  82  //	| Resv  |S| QRV |     QQIC      |     Number of Sources (N)     |
  83  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  84  //	|                                                               |
  85  //	*                                                               *
  86  //	|                                                               |
  87  //	*                       Source Address [1]                      *
  88  //	|                                                               |
  89  //	*                                                               *
  90  //	|                                                               |
  91  //	+-                                                             -+
  92  //	|                                                               |
  93  //	*                                                               *
  94  //	|                                                               |
  95  //	*                       Source Address [2]                      *
  96  //	|                                                               |
  97  //	*                                                               *
  98  //	|                                                               |
  99  //	+-                              .                              -+
 100  //	.                               .                               .
 101  //	.                               .                               .
 102  //	+-                                                             -+
 103  //	|                                                               |
 104  //	*                                                               *
 105  //	|                                                               |
 106  //	*                       Source Address [N]                      *
 107  //	|                                                               |
 108  //	*                                                               *
 109  //	|                                                               |
 110  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 111  type MLDv2Query MLD
 112  
 113  // MaximumResponseCode returns the Maximum Response Code
 114  func (m MLDv2Query) MaximumResponseCode() uint16 {
 115  	return binary.BigEndian.Uint16(m[mldv2QueryMaximumResponseCodeOffset:])
 116  }
 117  
 118  // MLDv2MaximumResponseDelay returns the Maximum Response Delay in an MLDv2
 119  // Maximum Response Code.
 120  //
 121  // As per RFC 3810 section 5.1.3,
 122  //
 123  //	The Maximum Response Code field specifies the maximum time allowed
 124  //	before sending a responding Report.  The actual time allowed, called
 125  //	the Maximum Response Delay, is represented in units of milliseconds,
 126  //	and is derived from the Maximum Response Code as follows:
 127  //
 128  //	If Maximum Response Code < 32768,
 129  //	   Maximum Response Delay = Maximum Response Code
 130  //
 131  //	If Maximum Response Code >=32768, Maximum Response Code represents a
 132  //	floating-point value as follows:
 133  //
 134  //	    0 1 2 3 4 5 6 7 8 9 A B C D E F
 135  //	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 136  //	   |1| exp |          mant         |
 137  //	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 138  //
 139  //	Maximum Response Delay = (mant | 0x1000) << (exp+3)
 140  //
 141  //	Small values of Maximum Response Delay allow MLDv2 routers to tune
 142  //	the "leave latency" (the time between the moment the last node on a
 143  //	link ceases to listen to a specific multicast address and the moment
 144  //	the routing protocol is notified that there are no more listeners for
 145  //	that address).  Larger values, especially in the exponential range,
 146  //	allow the tuning of the burstiness of MLD traffic on a link.
 147  func MLDv2MaximumResponseDelay(codeRaw uint16) time.Duration {
 148  	code := time.Duration(codeRaw)
 149  	if code < 32768 {
 150  		return code * time.Millisecond
 151  	}
 152  
 153  	const mantBits = 12
 154  	const expMask = 0b111
 155  	exp := (code >> mantBits) & expMask
 156  	mant := code & ((1 << mantBits) - 1)
 157  	return (mant | 0x1000) << (exp + 3) * time.Millisecond
 158  }
 159  
 160  // MulticastAddress returns the Multicast Address.
 161  func (m MLDv2Query) MulticastAddress() tcpip.Address {
 162  	// As per RFC 2710 section 3.5:
 163  	//
 164  	//   In a Query message, the Multicast Address field is set to zero when
 165  	//   sending a General Query, and set to a specific IPv6 multicast address
 166  	//   when sending a Multicast-Address-Specific Query.
 167  	//
 168  	//   In a Report or Done message, the Multicast Address field holds a
 169  	//   specific IPv6 multicast address to which the message sender is
 170  	//   listening or is ceasing to listen, respectively.
 171  	return tcpip.AddrFrom16([16]byte(m[mldMulticastAddressOffset:][:IPv6AddressSize]))
 172  }
 173  
 174  // QuerierRobustnessVariable returns the querier's robustness variable.
 175  func (m MLDv2Query) QuerierRobustnessVariable() uint8 {
 176  	return m[mldv2QueryResvSQRVOffset] & mldv2QueryQRVMask
 177  }
 178  
 179  // QuerierQueryInterval returns the querier's query interval.
 180  func (m MLDv2Query) QuerierQueryInterval() time.Duration {
 181  	return mldv2AndIGMPv3QuerierQueryCodeToInterval(m[mldv2QueryQQICOffset])
 182  }
 183  
 184  // Sources returns an iterator over source addresses in the query.
 185  //
 186  // Returns false if the message cannot hold the expected number of sources.
 187  func (m MLDv2Query) Sources() (AddressIterator, bool) {
 188  	return makeAddressIterator(
 189  		m[mldv2QuerySourcesOffset:],
 190  		binary.BigEndian.Uint16(m[mldv2QueryNumberOfSourcesOffset:]),
 191  		IPv6AddressSize,
 192  	)
 193  }
 194  
 195  // MLDv2ReportRecordType is the type of an MLDv2 multicast address record
 196  // found in an MLDv2 report, as per RFC 3810 section 5.2.12.
 197  type MLDv2ReportRecordType int
 198  
 199  // MLDv2 multicast address record types, as per RFC 3810 section 5.2.12.
 200  const (
 201  	MLDv2ReportRecordModeIsInclude       MLDv2ReportRecordType = 1
 202  	MLDv2ReportRecordModeIsExclude       MLDv2ReportRecordType = 2
 203  	MLDv2ReportRecordChangeToIncludeMode MLDv2ReportRecordType = 3
 204  	MLDv2ReportRecordChangeToExcludeMode MLDv2ReportRecordType = 4
 205  	MLDv2ReportRecordAllowNewSources     MLDv2ReportRecordType = 5
 206  	MLDv2ReportRecordBlockOldSources     MLDv2ReportRecordType = 6
 207  )
 208  
 209  const (
 210  	mldv2ReportMulticastAddressRecordMinimumSize            = 20
 211  	mldv2ReportMulticastAddressRecordTypeOffset             = 0
 212  	mldv2ReportMulticastAddressRecordAuxDataLenOffset       = 1
 213  	mldv2ReportMulticastAddressRecordAuxDataLenUnits        = 4
 214  	mldv2ReportMulticastAddressRecordNumberOfSourcesOffset  = 2
 215  	mldv2ReportMulticastAddressRecordMulticastAddressOffset = 4
 216  	mldv2ReportMulticastAddressRecordSourcesOffset          = 20
 217  )
 218  
 219  // MLDv2ReportMulticastAddressRecordSerializer is an MLDv2 Multicast Address
 220  // Record serializer.
 221  //
 222  // As per RFC 3810 section 5.2, a Multicast Address Record has the following
 223  // internal format:
 224  //
 225  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 226  //	|  Record Type  |  Aux Data Len |     Number of Sources (N)     |
 227  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 228  //	|                                                               |
 229  //	*                                                               *
 230  //	|                                                               |
 231  //	*                       Multicast Address                       *
 232  //	|                                                               |
 233  //	*                                                               *
 234  //	|                                                               |
 235  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 236  //	|                                                               |
 237  //	*                                                               *
 238  //	|                                                               |
 239  //	*                       Source Address [1]                      *
 240  //	|                                                               |
 241  //	*                                                               *
 242  //	|                                                               |
 243  //	+-                                                             -+
 244  //	|                                                               |
 245  //	*                                                               *
 246  //	|                                                               |
 247  //	*                       Source Address [2]                      *
 248  //	|                                                               |
 249  //	*                                                               *
 250  //	|                                                               |
 251  //	+-                                                             -+
 252  //	.                               .                               .
 253  //	.                               .                               .
 254  //	.                               .                               .
 255  //	+-                                                             -+
 256  //	|                                                               |
 257  //	*                                                               *
 258  //	|                                                               |
 259  //	*                       Source Address [N]                      *
 260  //	|                                                               |
 261  //	*                                                               *
 262  //	|                                                               |
 263  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 264  //	|                                                               |
 265  //	.                                                               .
 266  //	.                         Auxiliary Data                        .
 267  //	.                                                               .
 268  //	|                                                               |
 269  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 270  type MLDv2ReportMulticastAddressRecordSerializer struct {
 271  	RecordType       MLDv2ReportRecordType
 272  	MulticastAddress tcpip.Address
 273  	Sources          []tcpip.Address
 274  }
 275  
 276  // Length returns the number of bytes this serializer would occupy.
 277  func (s *MLDv2ReportMulticastAddressRecordSerializer) Length() int {
 278  	return mldv2ReportMulticastAddressRecordSourcesOffset + len(s.Sources)*IPv6AddressSize
 279  }
 280  
 281  func copyIPv6Address(dst []byte, src tcpip.Address) {
 282  	if n := copy(dst, src.AsSlice()); n != IPv6AddressSize {
 283  		panic(fmt.Sprintf("got copy(...) = %d, want = %d", n, IPv6AddressSize))
 284  	}
 285  }
 286  
 287  // SerializeInto serializes the record into the buffer.
 288  //
 289  // Panics if the buffer does not have enough space to fit the record.
 290  func (s *MLDv2ReportMulticastAddressRecordSerializer) SerializeInto(b []byte) {
 291  	b[mldv2ReportMulticastAddressRecordTypeOffset] = byte(s.RecordType)
 292  	b[mldv2ReportMulticastAddressRecordAuxDataLenOffset] = 0
 293  	binary.BigEndian.PutUint16(b[mldv2ReportMulticastAddressRecordNumberOfSourcesOffset:], uint16(len(s.Sources)))
 294  	copyIPv6Address(b[mldv2ReportMulticastAddressRecordMulticastAddressOffset:], s.MulticastAddress)
 295  	b = b[mldv2ReportMulticastAddressRecordSourcesOffset:]
 296  	for _, source := range s.Sources {
 297  		copyIPv6Address(b, source)
 298  		b = b[IPv6AddressSize:]
 299  	}
 300  }
 301  
 302  const (
 303  	mldv2ReportReservedOffset                        = 0
 304  	mldv2ReportNumberOfMulticastAddressRecordsOffset = 2
 305  	mldv2ReportMulticastAddressRecordsOffset         = 4
 306  )
 307  
 308  // MLDv2ReportSerializer is an MLD Version 2 Report serializer.
 309  //
 310  // As per RFC 3810 section 5.2,
 311  //
 312  //	 0                   1                   2                   3
 313  //	 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 314  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 315  //	|  Type = 143   |    Reserved   |           Checksum            |
 316  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 317  //	|           Reserved            |Nr of Mcast Address Records (M)|
 318  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 319  //	|                                                               |
 320  //	.                                                               .
 321  //	.                  Multicast Address Record [1]                 .
 322  //	.                                                               .
 323  //	|                                                               |
 324  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 325  //	|                                                               |
 326  //	.                                                               .
 327  //	.                  Multicast Address Record [2]                 .
 328  //	.                                                               .
 329  //	|                                                               |
 330  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 331  //	|                               .                               |
 332  //	.                               .                               .
 333  //	|                               .                               |
 334  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 335  //	|                                                               |
 336  //	.                                                               .
 337  //	.                  Multicast Address Record [M]                 .
 338  //	.                                                               .
 339  //	|                                                               |
 340  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 341  type MLDv2ReportSerializer struct {
 342  	Records []MLDv2ReportMulticastAddressRecordSerializer
 343  }
 344  
 345  // Length returns the number of bytes this serializer would occupy.
 346  func (s *MLDv2ReportSerializer) Length() int {
 347  	ret := mldv2ReportMulticastAddressRecordsOffset
 348  	for _, record := range s.Records {
 349  		ret += record.Length()
 350  	}
 351  	return ret
 352  }
 353  
 354  // SerializeInto serializes the report into the buffer.
 355  //
 356  // Panics if the buffer does not have enough space to fit the report.
 357  func (s *MLDv2ReportSerializer) SerializeInto(b []byte) {
 358  	binary.BigEndian.PutUint16(b[mldv2ReportReservedOffset:], 0)
 359  	binary.BigEndian.PutUint16(b[mldv2ReportNumberOfMulticastAddressRecordsOffset:], uint16(len(s.Records)))
 360  	b = b[mldv2ReportMulticastAddressRecordsOffset:]
 361  	for _, record := range s.Records {
 362  		len := record.Length()
 363  		record.SerializeInto(b[:len])
 364  		b = b[len:]
 365  	}
 366  }
 367  
 368  // MLDv2ReportMulticastAddressRecord is an MLDv2 record.
 369  //
 370  // As per RFC 3810 section 5.2, a Multicast Address Record has the following
 371  // internal format:
 372  //
 373  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 374  //	|  Record Type  |  Aux Data Len |     Number of Sources (N)     |
 375  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 376  //	|                                                               |
 377  //	*                                                               *
 378  //	|                                                               |
 379  //	*                       Multicast Address                       *
 380  //	|                                                               |
 381  //	*                                                               *
 382  //	|                                                               |
 383  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 384  //	|                                                               |
 385  //	*                                                               *
 386  //	|                                                               |
 387  //	*                       Source Address [1]                      *
 388  //	|                                                               |
 389  //	*                                                               *
 390  //	|                                                               |
 391  //	+-                                                             -+
 392  //	|                                                               |
 393  //	*                                                               *
 394  //	|                                                               |
 395  //	*                       Source Address [2]                      *
 396  //	|                                                               |
 397  //	*                                                               *
 398  //	|                                                               |
 399  //	+-                                                             -+
 400  //	.                               .                               .
 401  //	.                               .                               .
 402  //	.                               .                               .
 403  //	+-                                                             -+
 404  //	|                                                               |
 405  //	*                                                               *
 406  //	|                                                               |
 407  //	*                       Source Address [N]                      *
 408  //	|                                                               |
 409  //	*                                                               *
 410  //	|                                                               |
 411  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 412  //	|                                                               |
 413  //	.                                                               .
 414  //	.                         Auxiliary Data                        .
 415  //	.                                                               .
 416  //	|                                                               |
 417  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 418  type MLDv2ReportMulticastAddressRecord []byte
 419  
 420  // RecordType returns the type of this record.
 421  func (r MLDv2ReportMulticastAddressRecord) RecordType() MLDv2ReportRecordType {
 422  	return MLDv2ReportRecordType(r[mldv2ReportMulticastAddressRecordTypeOffset])
 423  }
 424  
 425  // AuxDataLen returns the length of the auxiliary data in this record.
 426  func (r MLDv2ReportMulticastAddressRecord) AuxDataLen() int {
 427  	return int(r[mldv2ReportMulticastAddressRecordAuxDataLenOffset]) * mldv2ReportMulticastAddressRecordAuxDataLenUnits
 428  }
 429  
 430  // numberOfSources returns the number of sources in this record.
 431  func (r MLDv2ReportMulticastAddressRecord) numberOfSources() uint16 {
 432  	return binary.BigEndian.Uint16(r[mldv2ReportMulticastAddressRecordNumberOfSourcesOffset:])
 433  }
 434  
 435  // MulticastAddress returns the multicast address this record targets.
 436  func (r MLDv2ReportMulticastAddressRecord) MulticastAddress() tcpip.Address {
 437  	return tcpip.AddrFrom16([16]byte(r[mldv2ReportMulticastAddressRecordMulticastAddressOffset:][:IPv6AddressSize]))
 438  }
 439  
 440  // Sources returns an iterator over source addresses in the query.
 441  //
 442  // Returns false if the message cannot hold the expected number of sources.
 443  func (r MLDv2ReportMulticastAddressRecord) Sources() (AddressIterator, bool) {
 444  	expectedLen := int(r.numberOfSources()) * IPv6AddressSize
 445  	b := r[mldv2ReportMulticastAddressRecordSourcesOffset:]
 446  	if len(b) < expectedLen {
 447  		return AddressIterator{}, false
 448  	}
 449  	return AddressIterator{addressSize: IPv6AddressSize, buf: bytes.NewBuffer(b[:expectedLen])}, true
 450  }
 451  
 452  // MLDv2Report is an MLDv2 Report.
 453  //
 454  // As per RFC 3810 section 5.2,
 455  //
 456  //	 0                   1                   2                   3
 457  //	 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 458  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 459  //	|  Type = 143   |    Reserved   |           Checksum            |
 460  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 461  //	|           Reserved            |Nr of Mcast Address Records (M)|
 462  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 463  //	|                                                               |
 464  //	.                                                               .
 465  //	.                  Multicast Address Record [1]                 .
 466  //	.                                                               .
 467  //	|                                                               |
 468  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 469  //	|                                                               |
 470  //	.                                                               .
 471  //	.                  Multicast Address Record [2]                 .
 472  //	.                                                               .
 473  //	|                                                               |
 474  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 475  //	|                               .                               |
 476  //	.                               .                               .
 477  //	|                               .                               |
 478  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 479  //	|                                                               |
 480  //	.                                                               .
 481  //	.                  Multicast Address Record [M]                 .
 482  //	.                                                               .
 483  //	|                                                               |
 484  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 485  type MLDv2Report []byte
 486  
 487  // MLDv2ReportMulticastAddressRecordIterator is an iterator over MLDv2 Multicast
 488  // Address Records.
 489  type MLDv2ReportMulticastAddressRecordIterator struct {
 490  	recordsLeft uint16
 491  	buf         *bytes.Buffer
 492  }
 493  
 494  // MLDv2ReportMulticastAddressRecordIteratorNextDisposition is the possible
 495  // return values from MLDv2ReportMulticastAddressRecordIterator.Next.
 496  type MLDv2ReportMulticastAddressRecordIteratorNextDisposition int
 497  
 498  const (
 499  	// MLDv2ReportMulticastAddressRecordIteratorNextOk indicates that a multicast
 500  	// address record was yielded.
 501  	MLDv2ReportMulticastAddressRecordIteratorNextOk MLDv2ReportMulticastAddressRecordIteratorNextDisposition = iota
 502  
 503  	// MLDv2ReportMulticastAddressRecordIteratorNextDone indicates that the iterator
 504  	// has been exhausted.
 505  	MLDv2ReportMulticastAddressRecordIteratorNextDone
 506  
 507  	// MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort indicates
 508  	// that the iterator expected another record, but the buffer ended
 509  	// prematurely.
 510  	MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort
 511  )
 512  
 513  // Next returns the next MLDv2 Multicast Address Record.
 514  func (it *MLDv2ReportMulticastAddressRecordIterator) Next() (MLDv2ReportMulticastAddressRecord, MLDv2ReportMulticastAddressRecordIteratorNextDisposition) {
 515  	if it.recordsLeft == 0 {
 516  		return MLDv2ReportMulticastAddressRecord{}, MLDv2ReportMulticastAddressRecordIteratorNextDone
 517  	}
 518  	if it.buf.Len() < mldv2ReportMulticastAddressRecordMinimumSize {
 519  		return MLDv2ReportMulticastAddressRecord{}, MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort
 520  	}
 521  
 522  	hdr := MLDv2ReportMulticastAddressRecord(it.buf.Bytes())
 523  	expectedLen := mldv2ReportMulticastAddressRecordMinimumSize +
 524  		int(hdr.AuxDataLen()) + int(hdr.numberOfSources())*IPv6AddressSize
 525  
 526  	bytes := it.buf.Next(expectedLen)
 527  	if len(bytes) < expectedLen {
 528  		return MLDv2ReportMulticastAddressRecord{}, MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort
 529  	}
 530  	it.recordsLeft--
 531  	return MLDv2ReportMulticastAddressRecord(bytes), MLDv2ReportMulticastAddressRecordIteratorNextOk
 532  }
 533  
 534  // MulticastAddressRecords returns an iterator of MLDv2 Multicast Address
 535  // Records.
 536  func (m MLDv2Report) MulticastAddressRecords() MLDv2ReportMulticastAddressRecordIterator {
 537  	return MLDv2ReportMulticastAddressRecordIterator{
 538  		recordsLeft: binary.BigEndian.Uint16(m[mldv2ReportNumberOfMulticastAddressRecordsOffset:]),
 539  		buf:         bytes.NewBuffer(m[mldv2ReportMulticastAddressRecordsOffset:]),
 540  	}
 541  }
 542