github.com/gopacket/gopacket@v1.1.0/layers/mldv2.go (about) 1 // Copyright 2018 GoPacket Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file in the root of the source 5 // tree. 6 7 package layers 8 9 import ( 10 "encoding/binary" 11 "errors" 12 "fmt" 13 "math" 14 "net" 15 "time" 16 17 "github.com/gopacket/gopacket" 18 ) 19 20 const ( 21 // S Flag bit is 1 22 mldv2STrue uint8 = 0x8 23 24 // S Flag value mask 25 // mldv2STrue & mldv2SMask == mldv2STrue // true 26 // 0x1 & mldv2SMask == mldv2STrue // true 27 // 0x0 & mldv2SMask == mldv2STrue // false 28 mldv2SMask uint8 = 0x8 29 30 // QRV value mask 31 mldv2QRVMask uint8 = 0x7 32 ) 33 34 // MLDv2MulticastListenerQueryMessage are sent by multicast routers to query the 35 // multicast listening state of neighboring interfaces. 36 // https://tools.ietf.org/html/rfc3810#section-5.1 37 // 38 // Some information, like Maximum Response Code and Multicast Address are in the 39 // previous layer LayerTypeMLDv1MulticastListenerQuery 40 type MLDv2MulticastListenerQueryMessage struct { 41 BaseLayer 42 // 5.1.3. Maximum Response Delay COde 43 MaximumResponseCode uint16 44 // 5.1.5. Multicast Address 45 // Zero in general query 46 // Specific IPv6 multicast address otherwise 47 MulticastAddress net.IP 48 // 5.1.7. S Flag (Suppress Router-Side Processing) 49 SuppressRoutersideProcessing bool 50 // 5.1.8. QRV (Querier's Robustness Variable) 51 QueriersRobustnessVariable uint8 52 // 5.1.9. QQIC (Querier's Query Interval Code) 53 QueriersQueryIntervalCode uint8 54 // 5.1.10. Number of Sources (N) 55 NumberOfSources uint16 56 // 5.1.11 Source Address [i] 57 SourceAddresses []net.IP 58 } 59 60 // DecodeFromBytes decodes the given bytes into this layer. 61 func (m *MLDv2MulticastListenerQueryMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { 62 if len(data) < 24 { 63 df.SetTruncated() 64 return errors.New("ICMP layer less than 24 bytes for Multicast Listener Query Message V2") 65 } 66 67 m.MaximumResponseCode = binary.BigEndian.Uint16(data[0:2]) 68 // ignore data[2:4] as per https://tools.ietf.org/html/rfc3810#section-5.1.4 69 m.MulticastAddress = data[4:20] 70 m.SuppressRoutersideProcessing = (data[20] & mldv2SMask) == mldv2STrue 71 m.QueriersRobustnessVariable = data[20] & mldv2QRVMask 72 m.QueriersQueryIntervalCode = data[21] 73 74 m.NumberOfSources = binary.BigEndian.Uint16(data[22:24]) 75 76 var end int 77 for i := uint16(0); i < m.NumberOfSources; i++ { 78 begin := 24 + (int(i) * 16) 79 end = begin + 16 80 81 if end > len(data) { 82 df.SetTruncated() 83 return fmt.Errorf("ICMP layer less than %d bytes for Multicast Listener Query Message V2", end) 84 } 85 86 m.SourceAddresses = append(m.SourceAddresses, data[begin:end]) 87 } 88 89 return nil 90 } 91 92 // NextLayerType returns the layer type contained by this DecodingLayer. 93 func (*MLDv2MulticastListenerQueryMessage) NextLayerType() gopacket.LayerType { 94 return gopacket.LayerTypeZero 95 } 96 97 // SerializeTo writes the serialized form of this layer into the 98 // SerializationBuffer, implementing gopacket.SerializableLayer. 99 // See the docs for gopacket.SerializableLayer for more info. 100 func (m *MLDv2MulticastListenerQueryMessage) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { 101 if err := m.serializeSourceAddressesTo(b, opts); err != nil { 102 return err 103 } 104 105 buf, err := b.PrependBytes(24) 106 if err != nil { 107 return err 108 } 109 110 binary.BigEndian.PutUint16(buf[0:2], m.MaximumResponseCode) 111 copy(buf[2:4], []byte{0x00, 0x00}) // set reserved bytes to zero 112 113 ma16 := m.MulticastAddress.To16() 114 if ma16 == nil { 115 return fmt.Errorf("invalid MulticastAddress '%s'", m.MulticastAddress) 116 } 117 copy(buf[4:20], ma16) 118 119 byte20 := m.QueriersRobustnessVariable & mldv2QRVMask 120 if m.SuppressRoutersideProcessing { 121 byte20 |= mldv2STrue 122 } else { 123 byte20 &= ^mldv2STrue // the complement of mldv2STrue 124 } 125 byte20 &= 0x0F // set reserved bits to zero 126 buf[20] = byte20 127 128 binary.BigEndian.PutUint16(buf[22:24], m.NumberOfSources) 129 buf[21] = m.QueriersQueryIntervalCode 130 131 return nil 132 } 133 134 // writes each source address to the buffer preserving the order 135 func (m *MLDv2MulticastListenerQueryMessage) serializeSourceAddressesTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { 136 numberOfSourceAddresses := len(m.SourceAddresses) 137 if numberOfSourceAddresses > math.MaxUint16 { 138 return fmt.Errorf( 139 "there are more than %d source addresses, but 65535 is the maximum number of supported addresses", 140 numberOfSourceAddresses) 141 } 142 143 if opts.FixLengths { 144 m.NumberOfSources = uint16(numberOfSourceAddresses) 145 } 146 147 lastSAIdx := numberOfSourceAddresses - 1 148 for k := range m.SourceAddresses { 149 i := lastSAIdx - k // reverse order 150 151 buf, err := b.PrependBytes(16) 152 if err != nil { 153 return err 154 } 155 156 sa16 := m.SourceAddresses[i].To16() 157 if sa16 == nil { 158 return fmt.Errorf("invalid source address [%d] '%s'", i, m.SourceAddresses[i]) 159 } 160 copy(buf[0:16], sa16) 161 } 162 163 return nil 164 } 165 166 // String sums this layer up nicely formatted 167 func (m *MLDv2MulticastListenerQueryMessage) String() string { 168 return fmt.Sprintf( 169 "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", 170 m.MaximumResponseCode, 171 m.MaximumResponseDelay(), 172 m.MulticastAddress, 173 m.SuppressRoutersideProcessing, 174 m.QueriersRobustnessVariable, 175 m.QueriersQueryIntervalCode, 176 m.QQI()/time.Second, 177 m.NumberOfSources, 178 len(m.SourceAddresses), 179 m.SourceAddresses) 180 } 181 182 // LayerType returns LayerTypeMLDv2MulticastListenerQuery. 183 func (*MLDv2MulticastListenerQueryMessage) LayerType() gopacket.LayerType { 184 return LayerTypeMLDv2MulticastListenerQuery 185 } 186 187 // CanDecode returns the set of layer types that this DecodingLayer can decode. 188 func (*MLDv2MulticastListenerQueryMessage) CanDecode() gopacket.LayerClass { 189 return LayerTypeMLDv2MulticastListenerQuery 190 } 191 192 // QQI calculates the Querier's Query Interval based on the QQIC 193 // according to https://tools.ietf.org/html/rfc3810#section-5.1.9 194 func (m *MLDv2MulticastListenerQueryMessage) QQI() time.Duration { 195 data := m.QueriersQueryIntervalCode 196 if data < 128 { 197 return time.Second * time.Duration(data) 198 } 199 200 exp := uint16(data) & 0x70 >> 4 201 mant := uint16(data) & 0x0F 202 return time.Second * time.Duration(mant|0x1000<<(exp+3)) 203 } 204 205 // SetQQI calculates and updates the Querier's Query Interval Code (QQIC) 206 // according to https://tools.ietf.org/html/rfc3810#section-5.1.9 207 func (m *MLDv2MulticastListenerQueryMessage) SetQQI(d time.Duration) error { 208 if d < 0 { 209 m.QueriersQueryIntervalCode = 0 210 return errors.New("QQI duration is negative") 211 } 212 213 if d == 0 { 214 m.QueriersQueryIntervalCode = 0 215 return nil 216 } 217 218 dms := d / time.Second 219 if dms < 128 { 220 m.QueriersQueryIntervalCode = uint8(dms) 221 } 222 223 if dms > 31744 { // mant=0xF, exp=0x7 224 m.QueriersQueryIntervalCode = 0xFF 225 return fmt.Errorf("QQI duration %ds is, maximum allowed is 31744s", dms) 226 } 227 228 value := uint16(dms) // ok, because 31744 < math.MaxUint16 229 exp := uint8(7) 230 for mask := uint16(0x4000); exp > 0; exp-- { 231 if mask&value != 0 { 232 break 233 } 234 235 mask >>= 1 236 } 237 238 mant := uint8(0x000F & (value >> (exp + 3))) 239 sig := uint8(0x10) 240 m.QueriersQueryIntervalCode = sig | exp<<4 | mant 241 242 return nil 243 } 244 245 // MaximumResponseDelay returns the Maximum Response Delay based on the 246 // Maximum Response Code according to 247 // https://tools.ietf.org/html/rfc3810#section-5.1.3 248 func (m *MLDv2MulticastListenerQueryMessage) MaximumResponseDelay() time.Duration { 249 if m.MaximumResponseCode < 0x8000 { 250 return time.Duration(m.MaximumResponseCode) 251 } 252 253 exp := m.MaximumResponseCode & 0x7000 >> 12 254 mant := m.MaximumResponseCode & 0x0FFF 255 256 return time.Millisecond * time.Duration(mant|0x1000<<(exp+3)) 257 } 258 259 // SetMLDv2MaximumResponseDelay updates the Maximum Response Code according to 260 // https://tools.ietf.org/html/rfc3810#section-5.1.3 261 func (m *MLDv2MulticastListenerQueryMessage) SetMLDv2MaximumResponseDelay(d time.Duration) error { 262 if d == 0 { 263 m.MaximumResponseCode = 0 264 return nil 265 } 266 267 if d < 0 { 268 return errors.New("maximum response delay must not be negative") 269 } 270 271 dms := d / time.Millisecond 272 273 if dms < 32768 { 274 m.MaximumResponseCode = uint16(dms) 275 } 276 277 if dms > 4193280 { // mant=0xFFF, exp=0x7 278 return fmt.Errorf("maximum response delay %dms is bigger the than maximum of 4193280ms", dms) 279 } 280 281 value := uint32(dms) // ok, because 4193280 < math.MaxUint32 282 exp := uint8(7) 283 for mask := uint32(0x40000000); exp > 0; exp-- { 284 if mask&value != 0 { 285 break 286 } 287 288 mask >>= 1 289 } 290 291 mant := uint16(0x00000FFF & (value >> (exp + 3))) 292 sig := uint16(0x1000) 293 m.MaximumResponseCode = sig | uint16(exp)<<12 | mant 294 return nil 295 } 296 297 // MLDv2MulticastListenerReportMessage is sent by an IP node to report the 298 // current multicast listening state, or changes therein. 299 // https://tools.ietf.org/html/rfc3810#section-5.2 300 type MLDv2MulticastListenerReportMessage struct { 301 BaseLayer 302 // 5.2.3. Nr of Mcast Address Records 303 NumberOfMulticastAddressRecords uint16 304 // 5.2.4. Multicast Address Record [i] 305 MulticastAddressRecords []MLDv2MulticastAddressRecord 306 } 307 308 // DecodeFromBytes decodes the given bytes into this layer. 309 func (m *MLDv2MulticastListenerReportMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { 310 if len(data) < 4 { 311 df.SetTruncated() 312 return errors.New("ICMP layer less than 4 bytes for Multicast Listener Report Message V2") 313 } 314 315 // ignore data[0:2] as per RFC 316 // https://tools.ietf.org/html/rfc3810#section-5.2.1 317 m.NumberOfMulticastAddressRecords = binary.BigEndian.Uint16(data[2:4]) 318 319 begin := 4 320 for i := uint16(0); i < m.NumberOfMulticastAddressRecords; i++ { 321 mar := MLDv2MulticastAddressRecord{} 322 read, err := mar.decode(data[begin:], df) 323 if err != nil { 324 return err 325 } 326 327 m.MulticastAddressRecords = append(m.MulticastAddressRecords, mar) 328 329 begin += read 330 } 331 332 return nil 333 } 334 335 // SerializeTo writes the serialized form of this layer into the 336 // SerializationBuffer, implementing gopacket.SerializableLayer. 337 // See the docs for gopacket.SerializableLayer for more info. 338 func (m *MLDv2MulticastListenerReportMessage) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { 339 lastItemIdx := len(m.MulticastAddressRecords) - 1 340 for k := range m.MulticastAddressRecords { 341 i := lastItemIdx - k // reverse order 342 343 err := m.MulticastAddressRecords[i].serializeTo(b, opts) 344 if err != nil { 345 return err 346 } 347 } 348 349 if opts.FixLengths { 350 numberOfMAR := len(m.MulticastAddressRecords) 351 if numberOfMAR > math.MaxUint16 { 352 return fmt.Errorf( 353 "%d multicast address records added, but the maximum is 65535", 354 numberOfMAR) 355 } 356 357 m.NumberOfMulticastAddressRecords = uint16(numberOfMAR) 358 } 359 360 buf, err := b.PrependBytes(4) 361 if err != nil { 362 return err 363 } 364 365 copy(buf[0:2], []byte{0x0, 0x0}) 366 binary.BigEndian.PutUint16(buf[2:4], m.NumberOfMulticastAddressRecords) 367 return nil 368 } 369 370 // Sums this layer up nicely formatted 371 func (m *MLDv2MulticastListenerReportMessage) String() string { 372 return fmt.Sprintf( 373 "Number of Mcast Addr Records: %d (actual %d), Multicast Address Records: %+v", 374 m.NumberOfMulticastAddressRecords, 375 len(m.MulticastAddressRecords), 376 m.MulticastAddressRecords) 377 } 378 379 // LayerType returns LayerTypeMLDv2MulticastListenerQuery. 380 func (*MLDv2MulticastListenerReportMessage) LayerType() gopacket.LayerType { 381 return LayerTypeMLDv2MulticastListenerReport 382 } 383 384 // CanDecode returns the set of layer types that this DecodingLayer can decode. 385 func (*MLDv2MulticastListenerReportMessage) CanDecode() gopacket.LayerClass { 386 return LayerTypeMLDv2MulticastListenerReport 387 } 388 389 // NextLayerType returns the layer type contained by this DecodingLayer. 390 func (*MLDv2MulticastListenerReportMessage) NextLayerType() gopacket.LayerType { 391 return gopacket.LayerTypePayload 392 } 393 394 // MLDv2MulticastAddressRecordType holds the type of a 395 // Multicast Address Record, according to 396 // https://tools.ietf.org/html/rfc3810#section-5.2.5 and 397 // https://tools.ietf.org/html/rfc3810#section-5.2.12 398 type MLDv2MulticastAddressRecordType uint8 399 400 const ( 401 // MLDv2MulticastAddressRecordTypeModeIsIncluded stands for 402 // MODE_IS_INCLUDE - indicates that the interface has a filter 403 // mode of INCLUDE for the specified multicast address. 404 MLDv2MulticastAddressRecordTypeModeIsIncluded MLDv2MulticastAddressRecordType = 1 405 // MLDv2MulticastAddressRecordTypeModeIsExcluded stands for 406 // MODE_IS_EXCLUDE - indicates that the interface has a filter 407 // mode of EXCLUDE for the specified multicast address. 408 MLDv2MulticastAddressRecordTypeModeIsExcluded MLDv2MulticastAddressRecordType = 2 409 // MLDv2MulticastAddressRecordTypeChangeToIncludeMode stands for 410 // CHANGE_TO_INCLUDE_MODE - indicates that the interface has 411 // changed to INCLUDE filter mode for the specified multicast 412 // address. 413 MLDv2MulticastAddressRecordTypeChangeToIncludeMode MLDv2MulticastAddressRecordType = 3 414 // MLDv2MulticastAddressRecordTypeChangeToExcludeMode stands for 415 // CHANGE_TO_EXCLUDE_MODE - indicates that the interface has 416 // changed to EXCLUDE filter mode for the specified multicast 417 // address 418 MLDv2MulticastAddressRecordTypeChangeToExcludeMode MLDv2MulticastAddressRecordType = 4 419 // MLDv2MulticastAddressRecordTypeAllowNewSources stands for 420 // ALLOW_NEW_SOURCES - indicates that the Source Address [i] 421 // fields in this Multicast Address Record contain a list of 422 // the additional sources that the node wishes to listen to, 423 // for packets sent to the specified multicast address. 424 MLDv2MulticastAddressRecordTypeAllowNewSources MLDv2MulticastAddressRecordType = 5 425 // MLDv2MulticastAddressRecordTypeBlockOldSources stands for 426 // BLOCK_OLD_SOURCES - indicates that the Source Address [i] 427 // fields in this Multicast Address Record contain a list of 428 // the sources that the node no longer wishes to listen to, 429 // for packets sent to the specified multicast address. 430 MLDv2MulticastAddressRecordTypeBlockOldSources MLDv2MulticastAddressRecordType = 6 431 ) 432 433 // Human readable record types 434 // Naming follows https://tools.ietf.org/html/rfc3810#section-5.2.12 435 func (m MLDv2MulticastAddressRecordType) String() string { 436 switch m { 437 case MLDv2MulticastAddressRecordTypeModeIsIncluded: 438 return "MODE_IS_INCLUDE" 439 case MLDv2MulticastAddressRecordTypeModeIsExcluded: 440 return "MODE_IS_EXCLUDE" 441 case MLDv2MulticastAddressRecordTypeChangeToIncludeMode: 442 return "CHANGE_TO_INCLUDE_MODE" 443 case MLDv2MulticastAddressRecordTypeChangeToExcludeMode: 444 return "CHANGE_TO_EXCLUDE_MODE" 445 case MLDv2MulticastAddressRecordTypeAllowNewSources: 446 return "ALLOW_NEW_SOURCES" 447 case MLDv2MulticastAddressRecordTypeBlockOldSources: 448 return "BLOCK_OLD_SOURCES" 449 default: 450 return fmt.Sprintf("UNKNOWN(%d)", m) 451 } 452 } 453 454 // MLDv2MulticastAddressRecord contains information on the sender listening to a 455 // single multicast address on the interface the report is sent. 456 // https://tools.ietf.org/html/rfc3810#section-5.2.4 457 type MLDv2MulticastAddressRecord struct { 458 // 5.2.5. Record Type 459 RecordType MLDv2MulticastAddressRecordType 460 // 5.2.6. Auxiliary Data Length (number of 32-bit words) 461 AuxDataLen uint8 462 // 5.2.7. Number Of Sources (N) 463 N uint16 464 // 5.2.8. Multicast Address 465 MulticastAddress net.IP 466 // 5.2.9 Source Address [i] 467 SourceAddresses []net.IP 468 // 5.2.10 Auxiliary Data 469 AuxiliaryData []byte 470 } 471 472 // decodes a multicast address record from bytes 473 func (m *MLDv2MulticastAddressRecord) decode(data []byte, df gopacket.DecodeFeedback) (int, error) { 474 if len(data) < 20 { 475 df.SetTruncated() 476 return 0, errors.New( 477 "Multicast Listener Report Message V2 layer less than 4 bytes for Multicast Address Record") 478 } 479 480 m.RecordType = MLDv2MulticastAddressRecordType(data[0]) 481 m.AuxDataLen = data[1] 482 m.N = binary.BigEndian.Uint16(data[2:4]) 483 m.MulticastAddress = data[4:20] 484 485 for i := uint16(0); i < m.N; i++ { 486 begin := 20 + (int(i) * 16) 487 end := begin + 16 488 489 if len(data) < end { 490 df.SetTruncated() 491 return begin, fmt.Errorf( 492 "Multicast Listener Report Message V2 layer less than %d bytes for Multicast Address Record", end) 493 } 494 495 m.SourceAddresses = append(m.SourceAddresses, data[begin:end]) 496 } 497 498 expectedLengthWithouAuxData := 20 + (int(m.N) * 16) 499 expectedTotalLength := (int(m.AuxDataLen) * 4) + expectedLengthWithouAuxData // *4 because AuxDataLen are 32bit words 500 if len(data) < expectedTotalLength { 501 return expectedLengthWithouAuxData, fmt.Errorf( 502 "Multicast Listener Report Message V2 layer less than %d bytes for Multicast Address Record", 503 expectedLengthWithouAuxData) 504 } 505 506 m.AuxiliaryData = data[expectedLengthWithouAuxData:expectedTotalLength] 507 508 return expectedTotalLength, nil 509 } 510 511 // String sums this layer up nicely formatted 512 func (m *MLDv2MulticastAddressRecord) String() string { 513 return fmt.Sprintf( 514 "RecordType: %d (%s), AuxDataLen: %d [32-bit words], N: %d, Multicast Address: %s, SourceAddresses: %s, Auxiliary Data: %#x", 515 m.RecordType, 516 m.RecordType.String(), 517 m.AuxDataLen, 518 m.N, 519 m.MulticastAddress.To16(), 520 m.SourceAddresses, 521 m.AuxiliaryData) 522 } 523 524 // serializes a multicast address record 525 func (m *MLDv2MulticastAddressRecord) serializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { 526 if err := m.serializeAuxiliaryDataTo(b, opts); err != nil { 527 return err 528 } 529 530 if err := m.serializeSourceAddressesTo(b, opts); err != nil { 531 return err 532 } 533 534 buf, err := b.PrependBytes(20) 535 if err != nil { 536 return err 537 } 538 539 buf[0] = uint8(m.RecordType) 540 buf[1] = m.AuxDataLen 541 binary.BigEndian.PutUint16(buf[2:4], m.N) 542 543 ma16 := m.MulticastAddress.To16() 544 if ma16 == nil { 545 return fmt.Errorf("invalid multicast address '%s'", m.MulticastAddress) 546 } 547 copy(buf[4:20], ma16) 548 549 return nil 550 } 551 552 // serializes the auxiliary data of a multicast address record 553 func (m *MLDv2MulticastAddressRecord) serializeAuxiliaryDataTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { 554 if remainder := len(m.AuxiliaryData) % 4; remainder != 0 { 555 zeroWord := []byte{0x0, 0x0, 0x0, 0x0} 556 m.AuxiliaryData = append(m.AuxiliaryData, zeroWord[:remainder]...) 557 } 558 559 if opts.FixLengths { 560 auxDataLen := len(m.AuxiliaryData) / 4 561 562 if auxDataLen > math.MaxUint8 { 563 return fmt.Errorf("auxilary data is %d 32-bit words, but the maximum is 255 32-bit words", auxDataLen) 564 } 565 566 m.AuxDataLen = uint8(auxDataLen) 567 } 568 569 buf, err := b.PrependBytes(len(m.AuxiliaryData)) 570 if err != nil { 571 return err 572 } 573 574 copy(buf, m.AuxiliaryData) 575 return nil 576 } 577 578 // serializes the source addresses of a multicast address record preserving the order 579 func (m *MLDv2MulticastAddressRecord) serializeSourceAddressesTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { 580 if opts.FixLengths { 581 numberOfSourceAddresses := len(m.SourceAddresses) 582 583 if numberOfSourceAddresses > math.MaxUint16 { 584 return fmt.Errorf( 585 "%d source addresses added, but the maximum is 65535", 586 numberOfSourceAddresses) 587 } 588 589 m.N = uint16(numberOfSourceAddresses) 590 } 591 592 lastItemIdx := len(m.SourceAddresses) - 1 593 for k := range m.SourceAddresses { 594 i := lastItemIdx - k // reverse order 595 596 buf, err := b.PrependBytes(16) 597 if err != nil { 598 return err 599 } 600 601 sa16 := m.SourceAddresses[i].To16() 602 if sa16 == nil { 603 return fmt.Errorf("invalid source address [%d] '%s'", i, m.SourceAddresses[i]) 604 } 605 copy(buf, sa16) 606 } 607 608 return nil 609 } 610 611 func decodeMLDv2MulticastListenerReport(data []byte, p gopacket.PacketBuilder) error { 612 m := &MLDv2MulticastListenerReportMessage{} 613 return decodingLayerDecoder(m, data, p) 614 } 615 616 func decodeMLDv2MulticastListenerQuery(data []byte, p gopacket.PacketBuilder) error { 617 m := &MLDv2MulticastListenerQueryMessage{} 618 return decodingLayerDecoder(m, data, p) 619 }