igmpv3.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  var (
  27  	// IGMPv3RoutersAddress is the address to send IGMPv3 reports to.
  28  	//
  29  	// As per RFC 3376 section 4.2.14,
  30  	//
  31  	//   Version 3 Reports are sent with an IP destination address of
  32  	//   224.0.0.22, to which all IGMPv3-capable multicast routers listen.
  33  	IGMPv3RoutersAddress = tcpip.AddrFrom4([4]byte{0xe0, 0x00, 0x00, 0x16})
  34  )
  35  
  36  const (
  37  	// IGMPv3QueryMinimumSize is the mimum size of a valid IGMPv3 query,
  38  	// as per RFC 3376 section 4.1.
  39  	IGMPv3QueryMinimumSize = 12
  40  
  41  	igmpv3QueryMaxRespCodeOffset     = 1
  42  	igmpv3QueryGroupAddressOffset    = 4
  43  	igmpv3QueryResvSQRVOffset        = 8
  44  	igmpv3QueryQRVMask               = 0b111
  45  	igmpv3QueryQQICOffset            = 9
  46  	igmpv3QueryNumberOfSourcesOffset = 10
  47  	igmpv3QuerySourcesOffset         = 12
  48  )
  49  
  50  // IGMPv3Query is an IGMPv3 query message.
  51  //
  52  // As per RFC 3376 section 4.1,
  53  //
  54  //	 0                   1                   2                   3
  55  //	 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
  56  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  57  //	|  Type = 0x11  | Max Resp Code |           Checksum            |
  58  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  59  //	|                         Group Address                         |
  60  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  61  //	| Resv  |S| QRV |     QQIC      |     Number of Sources (N)     |
  62  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  63  //	|                       Source Address [1]                      |
  64  //	+-                                                             -+
  65  //	|                       Source Address [2]                      |
  66  //	+-                              .                              -+
  67  //	.                               .                               .
  68  //	.                               .                               .
  69  //	+-                                                             -+
  70  //	|                       Source Address [N]                      |
  71  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  72  type IGMPv3Query IGMP
  73  
  74  // MaximumResponseCode returns the Maximum Response Code.
  75  func (i IGMPv3Query) MaximumResponseCode() uint8 {
  76  	return i[igmpv3QueryMaxRespCodeOffset]
  77  }
  78  
  79  // IGMPv3MaximumResponseDelay returns the Maximum Response Delay in an IGMPv3
  80  // Maximum Response Code.
  81  //
  82  // As per RFC 3376 section 4.1.1,
  83  //
  84  //	The Max Resp Code field specifies the maximum time allowed before
  85  //	sending a responding report.  The actual time allowed, called the Max
  86  //	Resp Time, is represented in units of 1/10 second and is derived from
  87  //	the Max Resp Code as follows:
  88  //
  89  //	If Max Resp Code < 128, Max Resp Time = Max Resp Code
  90  //
  91  //	If Max Resp Code >= 128, Max Resp Code represents a floating-point
  92  //	value as follows:
  93  //
  94  //	    0 1 2 3 4 5 6 7
  95  //	  +-+-+-+-+-+-+-+-+
  96  //	   |1| exp | mant  |
  97  //	   +-+-+-+-+-+-+-+-+
  98  //
  99  //	Max Resp Time = (mant | 0x10) << (exp + 3)
 100  //
 101  //	Small values of Max Resp Time allow IGMPv3 routers to tune the "leave
 102  //	latency" (the time between the moment the last host leaves a group
 103  //	and the moment the routing protocol is notified that there are no
 104  //	more members).  Larger values, especially in the exponential range,
 105  //	allow tuning of the burstiness of IGMP traffic on a network.
 106  func IGMPv3MaximumResponseDelay(codeRaw uint8) time.Duration {
 107  	code := uint16(codeRaw)
 108  	if code < 128 {
 109  		return DecisecondToDuration(code)
 110  	}
 111  
 112  	const mantBits = 4
 113  	const expMask = 0b111
 114  	exp := (code >> mantBits) & expMask
 115  	mant := code & ((1 << mantBits) - 1)
 116  	return DecisecondToDuration((mant | 0x10) << (exp + 3))
 117  }
 118  
 119  // GroupAddress returns the group address.
 120  func (i IGMPv3Query) GroupAddress() tcpip.Address {
 121  	return tcpip.AddrFrom4([4]byte(i[igmpv3QueryGroupAddressOffset:][:IPv4AddressSize]))
 122  }
 123  
 124  // QuerierRobustnessVariable returns the querier's robustness variable.
 125  func (i IGMPv3Query) QuerierRobustnessVariable() uint8 {
 126  	return i[igmpv3QueryResvSQRVOffset] & igmpv3QueryQRVMask
 127  }
 128  
 129  // QuerierQueryInterval returns the querier's query interval.
 130  func (i IGMPv3Query) QuerierQueryInterval() time.Duration {
 131  	return mldv2AndIGMPv3QuerierQueryCodeToInterval(i[igmpv3QueryQQICOffset])
 132  }
 133  
 134  // Sources returns an iterator over source addresses in the query.
 135  //
 136  // Returns false if the message cannot hold the expected number of sources.
 137  func (i IGMPv3Query) Sources() (AddressIterator, bool) {
 138  	return makeAddressIterator(
 139  		i[igmpv3QuerySourcesOffset:],
 140  		binary.BigEndian.Uint16(i[igmpv3QueryNumberOfSourcesOffset:]),
 141  		IPv4AddressSize,
 142  	)
 143  }
 144  
 145  // IGMPv3ReportRecordType is the type of an IGMPv3 multicast address record
 146  // found in an IGMPv3 report, as per RFC 3810 section 5.2.12.
 147  type IGMPv3ReportRecordType int
 148  
 149  // IGMPv3 multicast address record types, as per RFC 3810 section 5.2.12.
 150  const (
 151  	IGMPv3ReportRecordModeIsInclude       IGMPv3ReportRecordType = 1
 152  	IGMPv3ReportRecordModeIsExclude       IGMPv3ReportRecordType = 2
 153  	IGMPv3ReportRecordChangeToIncludeMode IGMPv3ReportRecordType = 3
 154  	IGMPv3ReportRecordChangeToExcludeMode IGMPv3ReportRecordType = 4
 155  	IGMPv3ReportRecordAllowNewSources     IGMPv3ReportRecordType = 5
 156  	IGMPv3ReportRecordBlockOldSources     IGMPv3ReportRecordType = 6
 157  )
 158  
 159  const (
 160  	igmpv3ReportGroupAddressRecordMinimumSize           = 8
 161  	igmpv3ReportGroupAddressRecordTypeOffset            = 0
 162  	igmpv3ReportGroupAddressRecordAuxDataLenOffset      = 1
 163  	igmpv3ReportGroupAddressRecordAuxDataLenUnits       = 4
 164  	igmpv3ReportGroupAddressRecordNumberOfSourcesOffset = 2
 165  	igmpv3ReportGroupAddressRecordGroupAddressOffset    = 4
 166  	igmpv3ReportGroupAddressRecordSourcesOffset         = 8
 167  )
 168  
 169  // IGMPv3ReportGroupAddressRecordSerializer is an IGMPv3 Multicast Address
 170  // Record serializer.
 171  //
 172  // As per RFC 3810 section 5.2, a Multicast Address Record has the following
 173  // internal format:
 174  //
 175  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 176  //	|  Record Type  |  Aux Data Len |     Number of Sources (N)     |
 177  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 178  //	|                                                               |
 179  //	*                                                               *
 180  //	|                                                               |
 181  //	*                       Multicast Address                       *
 182  //	|                                                               |
 183  //	*                                                               *
 184  //	|                                                               |
 185  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 186  //	|                                                               |
 187  //	*                                                               *
 188  //	|                                                               |
 189  //	*                       Source Address [1]                      *
 190  //	|                                                               |
 191  //	*                                                               *
 192  //	|                                                               |
 193  //	+-                                                             -+
 194  //	|                                                               |
 195  //	*                                                               *
 196  //	|                                                               |
 197  //	*                       Source Address [2]                      *
 198  //	|                                                               |
 199  //	*                                                               *
 200  //	|                                                               |
 201  //	+-                                                             -+
 202  //	.                               .                               .
 203  //	.                               .                               .
 204  //	.                               .                               .
 205  //	+-                                                             -+
 206  //	|                                                               |
 207  //	*                                                               *
 208  //	|                                                               |
 209  //	*                       Source Address [N]                      *
 210  //	|                                                               |
 211  //	*                                                               *
 212  //	|                                                               |
 213  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 214  //	|                                                               |
 215  //	.                                                               .
 216  //	.                         Auxiliary Data                        .
 217  //	.                                                               .
 218  //	|                                                               |
 219  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 220  type IGMPv3ReportGroupAddressRecordSerializer struct {
 221  	RecordType   IGMPv3ReportRecordType
 222  	GroupAddress tcpip.Address
 223  	Sources      []tcpip.Address
 224  }
 225  
 226  // Length returns the number of bytes this serializer would occupy.
 227  func (s *IGMPv3ReportGroupAddressRecordSerializer) Length() int {
 228  	return igmpv3ReportGroupAddressRecordSourcesOffset + len(s.Sources)*IPv4AddressSize
 229  }
 230  
 231  func copyIPv4Address(dst []byte, src tcpip.Address) {
 232  	srcBytes := src.As4()
 233  	if n := copy(dst, srcBytes[:]); n != IPv4AddressSize {
 234  		panic(fmt.Sprintf("got copy(...) = %d, want = %d", n, IPv4AddressSize))
 235  	}
 236  }
 237  
 238  // SerializeInto serializes the record into the buffer.
 239  //
 240  // Panics if the buffer does not have enough space to fit the record.
 241  func (s *IGMPv3ReportGroupAddressRecordSerializer) SerializeInto(b []byte) {
 242  	b[igmpv3ReportGroupAddressRecordTypeOffset] = byte(s.RecordType)
 243  	b[igmpv3ReportGroupAddressRecordAuxDataLenOffset] = 0
 244  	binary.BigEndian.PutUint16(b[igmpv3ReportGroupAddressRecordNumberOfSourcesOffset:], uint16(len(s.Sources)))
 245  	copyIPv4Address(b[igmpv3ReportGroupAddressRecordGroupAddressOffset:], s.GroupAddress)
 246  	b = b[igmpv3ReportGroupAddressRecordSourcesOffset:]
 247  	for _, source := range s.Sources {
 248  		copyIPv4Address(b, source)
 249  		b = b[IPv4AddressSize:]
 250  	}
 251  }
 252  
 253  const (
 254  	igmpv3ReportTypeOffset                        = 0
 255  	igmpv3ReportReserved1Offset                   = 1
 256  	igmpv3ReportReserved2Offset                   = 4
 257  	igmpv3ReportNumberOfGroupAddressRecordsOffset = 6
 258  	igmpv3ReportGroupAddressRecordsOffset         = 8
 259  )
 260  
 261  // IGMPv3ReportSerializer is an MLD Version 2 Report serializer.
 262  //
 263  // As per RFC 3810 section 5.2,
 264  //
 265  //	 0                   1                   2                   3
 266  //	 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
 267  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 268  //	|  Type = 143   |    Reserved   |           Checksum            |
 269  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 270  //	|           Reserved            |Nr of Mcast Address Records (M)|
 271  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 272  //	|                                                               |
 273  //	.                                                               .
 274  //	.                  Multicast Address Record [1]                 .
 275  //	.                                                               .
 276  //	|                                                               |
 277  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 278  //	|                                                               |
 279  //	.                                                               .
 280  //	.                  Multicast Address Record [2]                 .
 281  //	.                                                               .
 282  //	|                                                               |
 283  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 284  //	|                               .                               |
 285  //	.                               .                               .
 286  //	|                               .                               |
 287  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 288  //	|                                                               |
 289  //	.                                                               .
 290  //	.                  Multicast Address Record [M]                 .
 291  //	.                                                               .
 292  //	|                                                               |
 293  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 294  type IGMPv3ReportSerializer struct {
 295  	Records []IGMPv3ReportGroupAddressRecordSerializer
 296  }
 297  
 298  // Length returns the number of bytes this serializer would occupy.
 299  func (s *IGMPv3ReportSerializer) Length() int {
 300  	ret := igmpv3ReportGroupAddressRecordsOffset
 301  	for _, record := range s.Records {
 302  		ret += record.Length()
 303  	}
 304  	return ret
 305  }
 306  
 307  // SerializeInto serializes the report into the buffer.
 308  //
 309  // Panics if the buffer does not have enough space to fit the report.
 310  func (s *IGMPv3ReportSerializer) SerializeInto(b []byte) {
 311  	b[igmpv3ReportTypeOffset] = byte(IGMPv3MembershipReport)
 312  	b[igmpv3ReportReserved1Offset] = 0
 313  	binary.BigEndian.PutUint16(b[igmpv3ReportReserved2Offset:], 0)
 314  	binary.BigEndian.PutUint16(b[igmpv3ReportNumberOfGroupAddressRecordsOffset:], uint16(len(s.Records)))
 315  	recordsBytes := b[igmpv3ReportGroupAddressRecordsOffset:]
 316  	for _, record := range s.Records {
 317  		len := record.Length()
 318  		record.SerializeInto(recordsBytes[:len])
 319  		recordsBytes = recordsBytes[len:]
 320  	}
 321  	binary.BigEndian.PutUint16(b[igmpChecksumOffset:], IGMPCalculateChecksum(b))
 322  }
 323  
 324  // IGMPv3ReportGroupAddressRecord is an IGMPv3 record.
 325  //
 326  // As per RFC 3810 section 5.2, a Multicast Address Record has the following
 327  // internal format:
 328  //
 329  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 330  //	|  Record Type  |  Aux Data Len |     Number of Sources (N)     |
 331  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 332  //	|                                                               |
 333  //	*                                                               *
 334  //	|                                                               |
 335  //	*                       Multicast Address                       *
 336  //	|                                                               |
 337  //	*                                                               *
 338  //	|                                                               |
 339  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 340  //	|                                                               |
 341  //	*                                                               *
 342  //	|                                                               |
 343  //	*                       Source Address [1]                      *
 344  //	|                                                               |
 345  //	*                                                               *
 346  //	|                                                               |
 347  //	+-                                                             -+
 348  //	|                                                               |
 349  //	*                                                               *
 350  //	|                                                               |
 351  //	*                       Source Address [2]                      *
 352  //	|                                                               |
 353  //	*                                                               *
 354  //	|                                                               |
 355  //	+-                                                             -+
 356  //	.                               .                               .
 357  //	.                               .                               .
 358  //	.                               .                               .
 359  //	+-                                                             -+
 360  //	|                                                               |
 361  //	*                                                               *
 362  //	|                                                               |
 363  //	*                       Source Address [N]                      *
 364  //	|                                                               |
 365  //	*                                                               *
 366  //	|                                                               |
 367  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 368  //	|                                                               |
 369  //	.                                                               .
 370  //	.                         Auxiliary Data                        .
 371  //	.                                                               .
 372  //	|                                                               |
 373  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 374  type IGMPv3ReportGroupAddressRecord []byte
 375  
 376  // RecordType returns the type of this record.
 377  func (r IGMPv3ReportGroupAddressRecord) RecordType() IGMPv3ReportRecordType {
 378  	return IGMPv3ReportRecordType(r[igmpv3ReportGroupAddressRecordTypeOffset])
 379  }
 380  
 381  // AuxDataLen returns the length of the auxiliary data in this record.
 382  func (r IGMPv3ReportGroupAddressRecord) AuxDataLen() int {
 383  	return int(r[igmpv3ReportGroupAddressRecordAuxDataLenOffset]) * igmpv3ReportGroupAddressRecordAuxDataLenUnits
 384  }
 385  
 386  // numberOfSources returns the number of sources in this record.
 387  func (r IGMPv3ReportGroupAddressRecord) numberOfSources() uint16 {
 388  	return binary.BigEndian.Uint16(r[igmpv3ReportGroupAddressRecordNumberOfSourcesOffset:])
 389  }
 390  
 391  // GroupAddress returns the multicast address this record targets.
 392  func (r IGMPv3ReportGroupAddressRecord) GroupAddress() tcpip.Address {
 393  	return tcpip.AddrFrom4([4]byte(r[igmpv3ReportGroupAddressRecordGroupAddressOffset:][:IPv4AddressSize]))
 394  }
 395  
 396  // Sources returns an iterator over source addresses in the query.
 397  //
 398  // Returns false if the message cannot hold the expected number of sources.
 399  func (r IGMPv3ReportGroupAddressRecord) Sources() (AddressIterator, bool) {
 400  	expectedLen := int(r.numberOfSources()) * IPv4AddressSize
 401  	b := r[igmpv3ReportGroupAddressRecordSourcesOffset:]
 402  	if len(b) < expectedLen {
 403  		return AddressIterator{}, false
 404  	}
 405  	return AddressIterator{addressSize: IPv4AddressSize, buf: bytes.NewBuffer(b[:expectedLen])}, true
 406  }
 407  
 408  // IGMPv3Report is an IGMPv3 Report.
 409  //
 410  // As per RFC 3810 section 5.2,
 411  //
 412  //	 0                   1                   2                   3
 413  //	 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
 414  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 415  //	|  Type = 143   |    Reserved   |           Checksum            |
 416  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 417  //	|           Reserved            |Nr of Mcast Address Records (M)|
 418  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 419  //	|                                                               |
 420  //	.                                                               .
 421  //	.                  Multicast Address Record [1]                 .
 422  //	.                                                               .
 423  //	|                                                               |
 424  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 425  //	|                                                               |
 426  //	.                                                               .
 427  //	.                  Multicast Address Record [2]                 .
 428  //	.                                                               .
 429  //	|                                                               |
 430  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 431  //	|                               .                               |
 432  //	.                               .                               .
 433  //	|                               .                               |
 434  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 435  //	|                                                               |
 436  //	.                                                               .
 437  //	.                  Multicast Address Record [M]                 .
 438  //	.                                                               .
 439  //	|                                                               |
 440  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 441  type IGMPv3Report []byte
 442  
 443  // Checksum returns the checksum.
 444  func (i IGMPv3Report) Checksum() uint16 {
 445  	return binary.BigEndian.Uint16(i[igmpChecksumOffset:])
 446  }
 447  
 448  // IGMPv3ReportGroupAddressRecordIterator is an iterator over IGMPv3 Multicast
 449  // Address Records.
 450  type IGMPv3ReportGroupAddressRecordIterator struct {
 451  	recordsLeft uint16
 452  	buf         *bytes.Buffer
 453  }
 454  
 455  // IGMPv3ReportGroupAddressRecordIteratorNextDisposition is the possible
 456  // return values from IGMPv3ReportGroupAddressRecordIterator.Next.
 457  type IGMPv3ReportGroupAddressRecordIteratorNextDisposition int
 458  
 459  const (
 460  	// IGMPv3ReportGroupAddressRecordIteratorNextOk indicates that a multicast
 461  	// address record was yielded.
 462  	IGMPv3ReportGroupAddressRecordIteratorNextOk IGMPv3ReportGroupAddressRecordIteratorNextDisposition = iota
 463  
 464  	// IGMPv3ReportGroupAddressRecordIteratorNextDone indicates that the iterator
 465  	// has been exhausted.
 466  	IGMPv3ReportGroupAddressRecordIteratorNextDone
 467  
 468  	// IGMPv3ReportGroupAddressRecordIteratorNextErrBufferTooShort indicates
 469  	// that the iterator expected another record, but the buffer ended
 470  	// prematurely.
 471  	IGMPv3ReportGroupAddressRecordIteratorNextErrBufferTooShort
 472  )
 473  
 474  // Next returns the next IGMPv3 Multicast Address Record.
 475  func (it *IGMPv3ReportGroupAddressRecordIterator) Next() (IGMPv3ReportGroupAddressRecord, IGMPv3ReportGroupAddressRecordIteratorNextDisposition) {
 476  	if it.recordsLeft == 0 {
 477  		return IGMPv3ReportGroupAddressRecord{}, IGMPv3ReportGroupAddressRecordIteratorNextDone
 478  	}
 479  	if it.buf.Len() < igmpv3ReportGroupAddressRecordMinimumSize {
 480  		return IGMPv3ReportGroupAddressRecord{}, IGMPv3ReportGroupAddressRecordIteratorNextErrBufferTooShort
 481  	}
 482  
 483  	hdr := IGMPv3ReportGroupAddressRecord(it.buf.Bytes())
 484  	expectedLen := igmpv3ReportGroupAddressRecordMinimumSize +
 485  		int(hdr.AuxDataLen()) + int(hdr.numberOfSources())*IPv4AddressSize
 486  
 487  	bytes := it.buf.Next(expectedLen)
 488  	if len(bytes) < expectedLen {
 489  		return IGMPv3ReportGroupAddressRecord{}, IGMPv3ReportGroupAddressRecordIteratorNextErrBufferTooShort
 490  	}
 491  	it.recordsLeft--
 492  	return IGMPv3ReportGroupAddressRecord(bytes), IGMPv3ReportGroupAddressRecordIteratorNextOk
 493  }
 494  
 495  // GroupAddressRecords returns an iterator of IGMPv3 Multicast Address
 496  // Records.
 497  func (i IGMPv3Report) GroupAddressRecords() IGMPv3ReportGroupAddressRecordIterator {
 498  	return IGMPv3ReportGroupAddressRecordIterator{
 499  		recordsLeft: binary.BigEndian.Uint16(i[igmpv3ReportNumberOfGroupAddressRecordsOffset:]),
 500  		buf:         bytes.NewBuffer(i[igmpv3ReportGroupAddressRecordsOffset:]),
 501  	}
 502  }
 503