blob: b44aa09956cfa68bb98ce7b84d8c0e72da2cc62a [file] [log] [blame]
Rusty Eddy1da61a22015-09-01 00:48:58 +00001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onlab.packet;
17
18import java.nio.ByteBuffer;
19import static org.onlab.packet.PacketUtils.checkBufferLength;
20
21public class IGMPMembership extends IGMPGroup {
22
Jonathan Hart6ccfc5a2016-02-12 19:26:02 -080023 // TODO should be an enum
Rusty Eddy1da61a22015-09-01 00:48:58 +000024 public static final byte MODE_IS_INCLUDE = 0x1;
25 public static final byte MODE_IS_EXCLUDE = 0x2;
26 public static final byte CHANGE_TO_INCLUDE_MODE = 0x3;
27 public static final byte CHANGE_TO_EXCLUDE_MODE = 0x4;
28 public static final byte ALLOW_NEW_SOURCES = 0x5;
29 public static final byte BLOCK_OLD_SOURCES = 0x6;
30
31 private final int minGroupRecordLen = Ip4Address.BYTE_LENGTH + 4;
32
33 protected byte recordType;
34 protected byte auxDataLength = 0;
35 protected byte[] auxData;
36
37 /**
38 * Constructor initialized with a multicast group address.
39 *
40 * @param gaddr A multicast group address.
41 */
42 public IGMPMembership(Ip4Address gaddr) {
43 super(gaddr, 0);
44 }
45
46 /**
47 * Default constructor.
48 */
49 public IGMPMembership() {
50 super();
51 }
52
53 /**
Jonathan Hart6ccfc5a2016-02-12 19:26:02 -080054 * Gets the IGMP record type.
55 *
56 * @return record type
57 */
58 public byte getRecordType() {
59 return recordType;
60 }
61
62 /**
Rusty Eddy1da61a22015-09-01 00:48:58 +000063 * Serialize this Membership Report.
64 *
65 * @param bb the ByteBuffer to write into, positioned at the next spot to be written to.
66 * @return serialized IGMP message.
67 */
68 @Override
69 public byte[] serialize(ByteBuffer bb) {
70
71 bb.put(recordType);
72 bb.put(auxDataLength); // reserved
73 bb.putShort((short) sources.size());
74 bb.put(gaddr.toOctets());
75 for (IpAddress ipaddr : sources) {
76 bb.put(ipaddr.toOctets());
77 }
78
79 if (auxDataLength > 0) {
80 bb.put(auxData);
81 }
82
83 return bb.array();
84 }
85
86 /**
87 * Deserialize the IGMP Membership report packet.
88 *
89 * @param bb the ByteBuffer wrapping the serialized message. The position of the
90 * ByteBuffer should be pointing at the head of either message type.
Ray Milkey9b36d812015-09-09 15:24:54 -070091 * @return IGMP Group
92 * @throws DeserializationException if deserialization fails
Rusty Eddy1da61a22015-09-01 00:48:58 +000093 */
94 public IGMPGroup deserialize(ByteBuffer bb) throws DeserializationException {
95
96 // Make sure there is enough buffer to read the header,
97 // including the number of sources
98 checkBufferLength(bb.remaining(), 0, minGroupRecordLen);
99 recordType = bb.get();
100 auxDataLength = bb.get();
101 int nsrcs = bb.getShort();
102
103 gaddr = Ip4Address.valueOf(bb.getInt());
104
alshabib64a8b9e2016-03-02 17:21:37 -0800105
Rusty Eddy1da61a22015-09-01 00:48:58 +0000106 for (; nsrcs > 0; nsrcs--) {
alshabib64a8b9e2016-03-02 17:21:37 -0800107 // Make sure we have enough buffer to hold all of these sources
108 checkBufferLength(bb.remaining(), 0, Ip4Address.BYTE_LENGTH * nsrcs);
Rusty Eddy1da61a22015-09-01 00:48:58 +0000109 Ip4Address src = Ip4Address.valueOf(bb.getInt());
110 this.sources.add(src);
111 }
112
113 if (auxDataLength > 0) {
114 auxData = new byte[auxDataLength];
115 bb.get(auxData, 0, auxDataLength);
116 }
117 return this;
118 }
119
120 /*
121 * (non-Javadoc)
122 *
123 * @see java.lang.Object#equals()
124 */
125 public boolean equals(Object obj) {
126 if (this == obj) {
127 return true;
128 }
129 if (!(obj instanceof IGMPMembership)) {
130 return false;
131 }
132 IGMPMembership other = (IGMPMembership) obj;
133
134 if (!this.gaddr.equals(other.gaddr)) {
135 return false;
136 }
137 if (this.recordType != other.recordType) {
138 return false;
139 }
140 if (this.auxDataLength != other.auxDataLength) {
141 return false;
142 }
143 if (this.sources.size() != other.sources.size()) {
144 return false;
145 }
146 // TODO: make these tolerant of order
147 if (!this.sources.equals(other.sources)) {
148 return false;
149 }
150
151 return true;
152 }
153
154 /*
155 * (non-Javadoc)
156 *
157 * @see java.lang.Object#hashCode()
158 */
159 @Override
160 public int hashCode() {
161 final int prime = 2521;
162 int result = super.hashCode();
163 result = prime * result + this.gaddr.hashCode();
164 result = prime * result + this.recordType;
165 result = prime * result + this.auxDataLength;
166 result = prime * result + this.sources.hashCode();
167 return result;
168 }
Ray Milkey9b36d812015-09-09 15:24:54 -0700169}