| /* |
| * Copyright 2015 Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.onlab.packet; |
| |
| import java.nio.ByteBuffer; |
| import static org.onlab.packet.PacketUtils.checkBufferLength; |
| |
| public class IGMPMembership extends IGMPGroup { |
| |
| // TODO should be an enum |
| public static final byte MODE_IS_INCLUDE = 0x1; |
| public static final byte MODE_IS_EXCLUDE = 0x2; |
| public static final byte CHANGE_TO_INCLUDE_MODE = 0x3; |
| public static final byte CHANGE_TO_EXCLUDE_MODE = 0x4; |
| public static final byte ALLOW_NEW_SOURCES = 0x5; |
| public static final byte BLOCK_OLD_SOURCES = 0x6; |
| |
| private final int minGroupRecordLen = Ip4Address.BYTE_LENGTH + 4; |
| |
| protected byte recordType; |
| protected byte auxDataLength = 0; |
| protected byte[] auxData; |
| |
| /** |
| * Constructor initialized with a multicast group address. |
| * |
| * @param gaddr A multicast group address. |
| */ |
| public IGMPMembership(Ip4Address gaddr) { |
| super(gaddr, 0); |
| } |
| |
| /** |
| * Default constructor. |
| */ |
| public IGMPMembership() { |
| super(); |
| } |
| |
| /** |
| * Gets the IGMP record type. |
| * |
| * @return record type |
| */ |
| public byte getRecordType() { |
| return recordType; |
| } |
| |
| /** |
| * Serialize this Membership Report. |
| * |
| * @param bb the ByteBuffer to write into, positioned at the next spot to be written to. |
| * @return serialized IGMP message. |
| */ |
| @Override |
| public byte[] serialize(ByteBuffer bb) { |
| |
| bb.put(recordType); |
| bb.put(auxDataLength); // reserved |
| bb.putShort((short) sources.size()); |
| bb.put(gaddr.toOctets()); |
| for (IpAddress ipaddr : sources) { |
| bb.put(ipaddr.toOctets()); |
| } |
| |
| if (auxDataLength > 0) { |
| bb.put(auxData); |
| } |
| |
| return bb.array(); |
| } |
| |
| /** |
| * Deserialize the IGMP Membership report packet. |
| * |
| * @param bb the ByteBuffer wrapping the serialized message. The position of the |
| * ByteBuffer should be pointing at the head of either message type. |
| * @return IGMP Group |
| * @throws DeserializationException if deserialization fails |
| */ |
| public IGMPGroup deserialize(ByteBuffer bb) throws DeserializationException { |
| |
| // Make sure there is enough buffer to read the header, |
| // including the number of sources |
| checkBufferLength(bb.remaining(), 0, minGroupRecordLen); |
| recordType = bb.get(); |
| auxDataLength = bb.get(); |
| int nsrcs = bb.getShort(); |
| |
| gaddr = Ip4Address.valueOf(bb.getInt()); |
| |
| |
| for (; nsrcs > 0; nsrcs--) { |
| // Make sure we have enough buffer to hold all of these sources |
| checkBufferLength(bb.remaining(), 0, Ip4Address.BYTE_LENGTH * nsrcs); |
| Ip4Address src = Ip4Address.valueOf(bb.getInt()); |
| this.sources.add(src); |
| } |
| |
| if (auxDataLength > 0) { |
| auxData = new byte[auxDataLength]; |
| bb.get(auxData, 0, auxDataLength); |
| } |
| return this; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see java.lang.Object#equals() |
| */ |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (!(obj instanceof IGMPMembership)) { |
| return false; |
| } |
| IGMPMembership other = (IGMPMembership) obj; |
| |
| if (!this.gaddr.equals(other.gaddr)) { |
| return false; |
| } |
| if (this.recordType != other.recordType) { |
| return false; |
| } |
| if (this.auxDataLength != other.auxDataLength) { |
| return false; |
| } |
| if (this.sources.size() != other.sources.size()) { |
| return false; |
| } |
| // TODO: make these tolerant of order |
| if (!this.sources.equals(other.sources)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see java.lang.Object#hashCode() |
| */ |
| @Override |
| public int hashCode() { |
| final int prime = 2521; |
| int result = super.hashCode(); |
| result = prime * result + this.gaddr.hashCode(); |
| result = prime * result + this.recordType; |
| result = prime * result + this.auxDataLength; |
| result = prime * result + this.sources.hashCode(); |
| return result; |
| } |
| } |