d00841535bbcf7f5297c30d68a2e9ef0040d1e04
[govpp.git] / vendor / github.com / google / gopacket / layers / igmp.go
1 // Copyright 2012 Google, Inc. All rights reserved.
2 // Copyright 2009-2011 Andreas Krennmair. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style license
5 // that can be found in the LICENSE file in the root of the source
6 // tree.
7
8 package layers
9
10 import (
11         "encoding/binary"
12         "errors"
13         "net"
14         "time"
15
16         "github.com/google/gopacket"
17 )
18
19 type IGMPType uint8
20
21 const (
22         IGMPMembershipQuery    IGMPType = 0x11 // General or group specific query
23         IGMPMembershipReportV1 IGMPType = 0x12 // Version 1 Membership Report
24         IGMPMembershipReportV2 IGMPType = 0x16 // Version 2 Membership Report
25         IGMPLeaveGroup         IGMPType = 0x17 // Leave Group
26         IGMPMembershipReportV3 IGMPType = 0x22 // Version 3 Membership Report
27 )
28
29 // String conversions for IGMP message types
30 func (i IGMPType) String() string {
31         switch i {
32         case IGMPMembershipQuery:
33                 return "IGMP Membership Query"
34         case IGMPMembershipReportV1:
35                 return "IGMPv1 Membership Report"
36         case IGMPMembershipReportV2:
37                 return "IGMPv2 Membership Report"
38         case IGMPMembershipReportV3:
39                 return "IGMPv3 Membership Report"
40         case IGMPLeaveGroup:
41                 return "Leave Group"
42         default:
43                 return ""
44         }
45 }
46
47 type IGMPv3GroupRecordType uint8
48
49 const (
50         IGMPIsIn  IGMPv3GroupRecordType = 0x01 // Type MODE_IS_INCLUDE, source addresses x
51         IGMPIsEx  IGMPv3GroupRecordType = 0x02 // Type MODE_IS_EXCLUDE, source addresses x
52         IGMPToIn  IGMPv3GroupRecordType = 0x03 // Type CHANGE_TO_INCLUDE_MODE, source addresses x
53         IGMPToEx  IGMPv3GroupRecordType = 0x04 // Type CHANGE_TO_EXCLUDE_MODE, source addresses x
54         IGMPAllow IGMPv3GroupRecordType = 0x05 // Type ALLOW_NEW_SOURCES, source addresses x
55         IGMPBlock IGMPv3GroupRecordType = 0x06 // Type BLOCK_OLD_SOURCES, source addresses x
56 )
57
58 func (i IGMPv3GroupRecordType) String() string {
59         switch i {
60         case IGMPIsIn:
61                 return "MODE_IS_INCLUDE"
62         case IGMPIsEx:
63                 return "MODE_IS_EXCLUDE"
64         case IGMPToIn:
65                 return "CHANGE_TO_INCLUDE_MODE"
66         case IGMPToEx:
67                 return "CHANGE_TO_EXCLUDE_MODE"
68         case IGMPAllow:
69                 return "ALLOW_NEW_SOURCES"
70         case IGMPBlock:
71                 return "BLOCK_OLD_SOURCES"
72         default:
73                 return ""
74         }
75 }
76
77 // IGMP represents an IGMPv3 message.
78 type IGMP struct {
79         BaseLayer
80         Type                    IGMPType
81         MaxResponseTime         time.Duration
82         Checksum                uint16
83         GroupAddress            net.IP
84         SupressRouterProcessing bool
85         RobustnessValue         uint8
86         IntervalTime            time.Duration
87         SourceAddresses         []net.IP
88         NumberOfGroupRecords    uint16
89         NumberOfSources         uint16
90         GroupRecords            []IGMPv3GroupRecord
91         Version                 uint8 // IGMP protocol version
92 }
93
94 // IGMPv1or2 stores header details for an IGMPv1 or IGMPv2 packet.
95 //
96 //  0                   1                   2                   3
97 //  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
98 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99 // |      Type     | Max Resp Time |           Checksum            |
100 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101 // |                         Group Address                         |
102 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103 type IGMPv1or2 struct {
104         BaseLayer
105         Type            IGMPType      // IGMP message type
106         MaxResponseTime time.Duration // meaningful only in Membership Query messages
107         Checksum        uint16        // 16-bit checksum of entire ip payload
108         GroupAddress    net.IP        // either 0 or an IP multicast address
109         Version         uint8
110 }
111
112 // decodeResponse dissects IGMPv1 or IGMPv2 packet.
113 func (i *IGMPv1or2) decodeResponse(data []byte) error {
114         if len(data) < 8 {
115                 return errors.New("IGMP packet too small")
116         }
117
118         i.MaxResponseTime = igmpTimeDecode(data[1])
119         i.Checksum = binary.BigEndian.Uint16(data[2:4])
120         i.GroupAddress = net.IP(data[4:8])
121
122         return nil
123 }
124
125 //  0                   1                   2                   3
126 //  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
127 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
128 // |  Type = 0x22  |    Reserved   |           Checksum            |
129 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
130 // |           Reserved            |  Number of Group Records (M)  |
131 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
132 // |                                                               |
133 // .                        Group Record [1]                       .
134 // |                                                               |
135 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
136 // |                                                               |
137 // .                        Group Record [2]                       .
138 // |                                                               |
139 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
140 // |                                                               |
141 // .                        Group Record [M]                       .
142 // |                                                               |
143 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
144
145 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
146 // |  Record Type  |  Aux Data Len |     Number of Sources (N)     |
147 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
148 // |                       Multicast Address                       |
149 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
150 // |                       Source Address [1]                      |
151 // +-                                                             -+
152 // |                       Source Address [2]                      |
153 // +-                                                             -+
154 // |                       Source Address [N]                      |
155 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
156 // |                                                               |
157 // .                         Auxiliary Data                        .
158 // |                                                               |
159 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160
161 // IGMPv3GroupRecord stores individual group records for a V3 Membership Report message.
162 type IGMPv3GroupRecord struct {
163         Type             IGMPv3GroupRecordType
164         AuxDataLen       uint8 // this should always be 0 as per IGMPv3 spec.
165         NumberOfSources  uint16
166         MulticastAddress net.IP
167         SourceAddresses  []net.IP
168         AuxData          uint32 // NOT USED
169 }
170
171 func (i *IGMP) decodeIGMPv3MembershipReport(data []byte) error {
172         if len(data) < 8 {
173                 return errors.New("IGMPv3 Membership Report too small #1")
174         }
175
176         i.Checksum = binary.BigEndian.Uint16(data[2:4])
177         i.NumberOfGroupRecords = binary.BigEndian.Uint16(data[6:8])
178
179         recordOffset := 8
180         for j := 0; j < int(i.NumberOfGroupRecords); j++ {
181                 if len(data) < recordOffset+8 {
182                         return errors.New("IGMPv3 Membership Report too small #2")
183                 }
184
185                 var gr IGMPv3GroupRecord
186                 gr.Type = IGMPv3GroupRecordType(data[recordOffset])
187                 gr.AuxDataLen = data[recordOffset+1]
188                 gr.NumberOfSources = binary.BigEndian.Uint16(data[recordOffset+2 : recordOffset+4])
189                 gr.MulticastAddress = net.IP(data[recordOffset+4 : recordOffset+8])
190
191                 if len(data) < recordOffset+8+int(gr.NumberOfSources)*4 {
192                         return errors.New("IGMPv3 Membership Report too small #3")
193                 }
194
195                 // append source address records.
196                 for i := 0; i < int(gr.NumberOfSources); i++ {
197                         sourceAddr := net.IP(data[recordOffset+8+i*4 : recordOffset+12+i*4])
198                         gr.SourceAddresses = append(gr.SourceAddresses, sourceAddr)
199                 }
200
201                 i.GroupRecords = append(i.GroupRecords, gr)
202                 recordOffset += 8 + 4*int(gr.NumberOfSources)
203         }
204         return nil
205 }
206
207 //  0                   1                   2                   3
208 //  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
209 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
210 // |  Type = 0x11  | Max Resp Code |           Checksum            |
211 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
212 // |                         Group Address                         |
213 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
214 // | Resv  |S| QRV |     QQIC      |     Number of Sources (N)     |
215 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
216 // |                       Source Address [1]                      |
217 // +-                                                             -+
218 // |                       Source Address [2]                      |
219 // +-                              .                              -+
220 // |                       Source Address [N]                      |
221 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
222 //
223 // decodeIGMPv3MembershipQuery parses the IGMPv3 message of type 0x11
224 func (i *IGMP) decodeIGMPv3MembershipQuery(data []byte) error {
225         if len(data) < 12 {
226                 return errors.New("IGMPv3 Membership Query too small #1")
227         }
228
229         i.MaxResponseTime = igmpTimeDecode(data[1])
230         i.Checksum = binary.BigEndian.Uint16(data[2:4])
231         i.SupressRouterProcessing = data[8]&0x8 != 0
232         i.GroupAddress = net.IP(data[4:8])
233         i.RobustnessValue = data[8] & 0x7
234         i.IntervalTime = igmpTimeDecode(data[9])
235         i.NumberOfSources = binary.BigEndian.Uint16(data[10:12])
236
237         if len(data) < 12+int(i.NumberOfSources)*4 {
238                 return errors.New("IGMPv3 Membership Query too small #2")
239         }
240
241         for j := 0; j < int(i.NumberOfSources); j++ {
242                 i.SourceAddresses = append(i.SourceAddresses, net.IP(data[12+j*4:16+j*4]))
243         }
244
245         return nil
246 }
247
248 // igmpTimeDecode decodes the duration created by the given byte, using the
249 // algorithm in http://www.rfc-base.org/txt/rfc-3376.txt section 4.1.1.
250 func igmpTimeDecode(t uint8) time.Duration {
251         if t&0x80 == 0 {
252                 return time.Millisecond * 100 * time.Duration(t)
253         }
254         mant := (t & 0x70) >> 4
255         exp := t & 0x0F
256         return time.Millisecond * 100 * time.Duration((mant|0x10)<<(exp+3))
257 }
258
259 // LayerType returns LayerTypeIGMP for the V1,2,3 message protocol formats.
260 func (i *IGMP) LayerType() gopacket.LayerType      { return LayerTypeIGMP }
261 func (i *IGMPv1or2) LayerType() gopacket.LayerType { return LayerTypeIGMP }
262
263 func (i *IGMPv1or2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
264         if len(data) < 8 {
265                 return errors.New("IGMP Packet too small")
266         }
267
268         i.Type = IGMPType(data[0])
269         i.MaxResponseTime = igmpTimeDecode(data[1])
270         i.Checksum = binary.BigEndian.Uint16(data[2:4])
271         i.GroupAddress = net.IP(data[4:8])
272
273         return nil
274 }
275
276 func (i *IGMPv1or2) NextLayerType() gopacket.LayerType {
277         return gopacket.LayerTypeZero
278 }
279
280 func (i *IGMPv1or2) CanDecode() gopacket.LayerClass {
281         return LayerTypeIGMP
282 }
283
284 // DecodeFromBytes decodes the given bytes into this layer.
285 func (i *IGMP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
286         if len(data) < 1 {
287                 return errors.New("IGMP packet is too small")
288         }
289
290         // common IGMP header values between versions 1..3 of IGMP specification..
291         i.Type = IGMPType(data[0])
292
293         switch i.Type {
294         case IGMPMembershipQuery:
295                 i.decodeIGMPv3MembershipQuery(data)
296         case IGMPMembershipReportV3:
297                 i.decodeIGMPv3MembershipReport(data)
298         default:
299                 return errors.New("unsupported IGMP type")
300         }
301
302         return nil
303 }
304
305 // CanDecode returns the set of layer types that this DecodingLayer can decode.
306 func (i *IGMP) CanDecode() gopacket.LayerClass {
307         return LayerTypeIGMP
308 }
309
310 // NextLayerType returns the layer type contained by this DecodingLayer.
311 func (i *IGMP) NextLayerType() gopacket.LayerType {
312         return gopacket.LayerTypeZero
313 }
314
315 // decodeIGMP will parse IGMP v1,2 or 3 protocols. Checks against the
316 // IGMP type are performed against byte[0], logic then iniitalizes and
317 // passes the appropriate struct (IGMP or IGMPv1or2) to
318 // decodingLayerDecoder.
319 func decodeIGMP(data []byte, p gopacket.PacketBuilder) error {
320         if len(data) < 1 {
321                 return errors.New("IGMP packet is too small")
322         }
323
324         // byte 0 contains IGMP message type.
325         switch IGMPType(data[0]) {
326         case IGMPMembershipQuery:
327                 // IGMPv3 Membership Query payload is >= 12
328                 if len(data) >= 12 {
329                         i := &IGMP{Version: 3}
330                         return decodingLayerDecoder(i, data, p)
331                 } else if len(data) == 8 {
332                         i := &IGMPv1or2{}
333                         if data[1] == 0x00 {
334                                 i.Version = 1 // IGMPv1 has a query length of 8 and MaxResp = 0
335                         } else {
336                                 i.Version = 2 // IGMPv2 has a query length of 8 and MaxResp != 0
337                         }
338
339                         return decodingLayerDecoder(i, data, p)
340                 }
341         case IGMPMembershipReportV3:
342                 i := &IGMP{Version: 3}
343                 return decodingLayerDecoder(i, data, p)
344         case IGMPMembershipReportV1:
345                 i := &IGMPv1or2{Version: 1}
346                 return decodingLayerDecoder(i, data, p)
347         case IGMPLeaveGroup, IGMPMembershipReportV2:
348                 // leave group and Query Report v2 used in IGMPv2 only.
349                 i := &IGMPv1or2{Version: 2}
350                 return decodingLayerDecoder(i, data, p)
351         default:
352         }
353
354         return errors.New("Unable to determine IGMP type.")
355 }