--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.opendaylight</artifactId>
+ <version>1.4.2-SNAPSHOT</version>
+ <relativePath>../opendaylight</relativePath>
+ </parent>
+
+ <artifactId>liblldp</artifactId>
+ <version>0.8.1-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Import-Package>org.slf4j,
+ org.apache.commons.lang3.builder,
+ org.apache.commons.lang3.tuple
+ </Import-Package>
+ <Export-Package>
+ org.opendaylight.controller.liblldp</Export-Package>
+ </instructions>
+ <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+ </scm>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+/**
+ *
+ */
+package org.opendaylight.controller.liblldp;
+
+import java.util.Arrays;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * BitBufferHelper class that provides utility methods to
+ * - fetch specific bits from a serialized stream of bits
+ * - convert bits to primitive data type - like short, int, long
+ * - store bits in specified location in stream of bits
+ * - convert primitive data types to stream of bits
+ */
+public abstract class BitBufferHelper {
+ protected static final Logger logger = LoggerFactory
+ .getLogger(BitBufferHelper.class);
+
+ public static final long ByteMask = 0xFF;
+
+ // Getters
+ // data: array where data are stored
+ // startOffset: bit from where to start reading
+ // numBits: number of bits to read
+ // All this function return an exception if overflow or underflow
+
+ /**
+ * Returns the first byte from the byte array
+ * @param byte[] data
+ * @return byte value
+ */
+ public static byte getByte(byte[] data) {
+ if ((data.length * NetUtils.NumBitsInAByte) > Byte.SIZE) {
+ try {
+ throw new BufferException(
+ "Container is too small for the number of requested bits");
+ } catch (BufferException e) {
+ logger.error("", e);
+ }
+ }
+ return (data[0]);
+ }
+
+ /**
+ * Returns the short value for the byte array passed.
+ * Size of byte array is restricted to Short.SIZE
+ * @param byte[] data
+ * @return short value
+ */
+ public static short getShort(byte[] data) {
+ if (data.length > Short.SIZE) {
+ try {
+ throw new BufferException(
+ "Container is too small for the number of requested bits");
+ } catch (BufferException e) {
+ logger.error("", e);
+ }
+ }
+ return (short) toNumber(data);
+ }
+
+ /**
+ * Returns the int value for the byte array passed.
+ * Size of byte array is restricted to Integer.SIZE
+ * @param byte[] data
+ * @return int - the integer value of byte array
+ */
+ public static int getInt(byte[] data) {
+ if (data.length > Integer.SIZE) {
+ try {
+ throw new BufferException(
+ "Container is too small for the number of requested bits");
+ } catch (BufferException e) {
+ logger.error("", e);
+ }
+ }
+ return (int) toNumber(data);
+ }
+
+ /**
+ * Returns the long value for the byte array passed.
+ * Size of byte array is restricted to Long.SIZE
+ * @param byte[] data
+ * @return long - the integer value of byte array
+ */
+ public static long getLong(byte[] data) {
+ if (data.length > Long.SIZE) {
+ try {
+ throw new BufferException(
+ "Container is too small for the number of requested bits");
+ } catch (Exception e) {
+ logger.error("", e);
+ }
+ }
+ return (long) toNumber(data);
+ }
+
+ /**
+ * Returns the short value for the last numBits of the byte array passed.
+ * Size of numBits is restricted to Short.SIZE
+ * @param byte[] data
+ * @param int - numBits
+ * @return short - the short value of byte array
+ */
+ public static short getShort(byte[] data, int numBits) {
+ if (numBits > Short.SIZE) {
+ try {
+ throw new BufferException(
+ "Container is too small for the number of requested bits");
+ } catch (BufferException e) {
+ logger.error("", e);
+ }
+ }
+ int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
+ byte[] bits = null;
+ try {
+ bits = BitBufferHelper.getBits(data, startOffset, numBits);
+ } catch (BufferException e) {
+ logger.error("", e);
+ }
+ return (short) toNumber(bits, numBits);
+ }
+
+ /**
+ * Returns the int value for the last numBits of the byte array passed.
+ * Size of numBits is restricted to Integer.SIZE
+ * @param byte[] data
+ * @param int - numBits
+ * @return int - the integer value of byte array
+ */
+ public static int getInt(byte[] data, int numBits) {
+ if (numBits > Integer.SIZE) {
+ try {
+ throw new BufferException(
+ "Container is too small for the number of requested bits");
+ } catch (BufferException e) {
+ logger.error("", e);
+ }
+ }
+ int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
+ byte[] bits = null;
+ try {
+ bits = BitBufferHelper.getBits(data, startOffset, numBits);
+ } catch (BufferException e) {
+ logger.error("", e);
+ }
+ return (int) toNumber(bits, numBits);
+ }
+
+ /**
+ * Returns the long value for the last numBits of the byte array passed.
+ * Size of numBits is restricted to Long.SIZE
+ * @param byte[] data
+ * @param int - numBits
+ * @return long - the integer value of byte array
+ */
+ public static long getLong(byte[] data, int numBits) {
+ if (numBits > Long.SIZE) {
+ try {
+ throw new BufferException(
+ "Container is too small for the number of requested bits");
+ } catch (BufferException e) {
+ logger.error("", e);
+ }
+ }
+ if (numBits > data.length * NetUtils.NumBitsInAByte) {
+ try {
+ throw new BufferException(
+ "Trying to read more bits than contained in the data buffer");
+ } catch (BufferException e) {
+ logger.error("", e);
+ }
+ }
+ int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
+ byte[] bits = null;
+ try {
+ bits = BitBufferHelper.getBits(data, startOffset, numBits);
+ } catch (BufferException e) {
+ logger.error("", e);
+ }
+ return (long) toNumber(bits, numBits);
+ }
+
+ /**
+ * Reads the specified number of bits from the passed byte array
+ * starting to read from the specified offset
+ * The bits read are stored in a byte array which size is dictated
+ * by the number of bits to be stored.
+ * The bits are stored in the byte array LSB aligned.
+ *
+ * Ex.
+ * Read 7 bits at offset 10
+ * 0 9 10 16 17
+ * 0101000010 | 0000101 | 1111001010010101011
+ * will be returned as {0,0,0,0,0,1,0,1}
+ *
+ * @param byte[] data
+ * @param int startOffset - offset to start fetching bits from data from
+ * @param int numBits - number of bits to be fetched from data
+ * @return byte [] - LSB aligned bits
+ *
+ * @throws BufferException
+ * when the startOffset and numBits parameters are not congruent
+ * with the data buffer size
+ */
+ public static byte[] getBits(byte[] data, int startOffset, int numBits)
+ throws BufferException {
+
+ int startByteOffset = 0;
+ int valfromcurr, valfromnext;
+ int extranumBits = numBits % NetUtils.NumBitsInAByte;
+ int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte;
+ int numBytes = (numBits % NetUtils.NumBitsInAByte != 0) ? 1 + numBits
+ / NetUtils.NumBitsInAByte : numBits / NetUtils.NumBitsInAByte;
+ byte[] shiftedBytes = new byte[numBytes];
+ startByteOffset = startOffset / NetUtils.NumBitsInAByte;
+ byte[] bytes = new byte[numBytes];
+ if (numBits == 0) {
+ return bytes;
+ }
+
+ checkExceptions(data, startOffset, numBits);
+
+ if (extraOffsetBits == 0) {
+ if (extranumBits == 0) {
+ System.arraycopy(data, startByteOffset, bytes, 0, numBytes);
+ return bytes;
+ } else {
+ System.arraycopy(data, startByteOffset, bytes, 0, numBytes - 1);
+ bytes[numBytes - 1] = (byte) ((int) data[startByteOffset
+ + numBytes - 1] & getMSBMask(extranumBits));
+ }
+ } else {
+ int i;
+ for (i = 0; i < numBits / NetUtils.NumBitsInAByte; i++) {
+ // Reading numBytes starting from offset
+ valfromcurr = (data[startByteOffset + i])
+ & getLSBMask(NetUtils.NumBitsInAByte - extraOffsetBits);
+ valfromnext = (data[startByteOffset + i + 1])
+ & getMSBMask(extraOffsetBits);
+ bytes[i] = (byte) (valfromcurr << (extraOffsetBits) | (valfromnext >> (NetUtils.NumBitsInAByte - extraOffsetBits)));
+ }
+ // Now adding the rest of the bits if any
+ if (extranumBits != 0) {
+ if (extranumBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) {
+ valfromnext = (byte) (data[startByteOffset + i] & ((getMSBMask(extranumBits)) >> extraOffsetBits));
+ bytes[i] = (byte) (valfromnext << extraOffsetBits);
+ } else if (extranumBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) {
+ valfromcurr = (data[startByteOffset + i])
+ & getLSBMask(NetUtils.NumBitsInAByte
+ - extraOffsetBits);
+ bytes[i] = (byte) (valfromcurr << extraOffsetBits);
+ } else {
+ valfromcurr = (data[startByteOffset + i])
+ & getLSBMask(NetUtils.NumBitsInAByte
+ - extraOffsetBits);
+ valfromnext = (data[startByteOffset + i + 1])
+ & (getMSBMask(extranumBits
+ - (NetUtils.NumBitsInAByte - extraOffsetBits)));
+ bytes[i] = (byte) (valfromcurr << (extraOffsetBits) | (valfromnext >> (NetUtils.NumBitsInAByte - extraOffsetBits)));
+ }
+
+ }
+ }
+ // Aligns the bits to LSB
+ shiftedBytes = shiftBitsToLSB(bytes, numBits);
+ return shiftedBytes;
+ }
+
+ // Setters
+ // data: array where data will be stored
+ // input: the data that need to be stored in the data array
+ // startOffset: bit from where to start writing
+ // numBits: number of bits to read
+
+ /**
+ * Bits are expected to be stored in the input byte array from LSB
+ * @param byte[] - data to set the input byte
+ * @param byte - input byte to be inserted
+ * @param startOffset - offset of data[] to start inserting byte from
+ * @param numBits - number of bits of input to be inserted into data[]
+ *
+ * @throws BufferException
+ * when the input, startOffset and numBits are not congruent
+ * with the data buffer size
+ */
+ public static void setByte(byte[] data, byte input, int startOffset,
+ int numBits) throws BufferException {
+ byte[] inputByteArray = new byte[1];
+ Arrays.fill(inputByteArray, 0, 1, input);
+ setBytes(data, inputByteArray, startOffset, numBits);
+ }
+
+ /**
+ * Bits are expected to be stored in the input byte array from LSB
+ * @param byte[] - data to set the input byte
+ * @param byte[] - input bytes to be inserted
+ * @param startOffset - offset of data[] to start inserting byte from
+ * @param numBits - number of bits of input to be inserted into data[]
+ * @return void
+ * @throws BufferException
+ * when the startOffset and numBits parameters are not congruent
+ * with data and input buffers' size
+ */
+ public static void setBytes(byte[] data, byte[] input, int startOffset,
+ int numBits) throws BufferException {
+ checkExceptions(data, startOffset, numBits);
+ insertBits(data, input, startOffset, numBits);
+ }
+
+ /**
+ * Returns numBits 1's in the MSB position
+ *
+ * @param numBits
+ * @return
+ */
+ public static int getMSBMask(int numBits) {
+ int mask = 0;
+ for (int i = 0; i < numBits; i++) {
+ mask = mask | (1 << (7 - i));
+ }
+ return mask;
+ }
+
+ /**
+ * Returns numBits 1's in the LSB position
+ *
+ * @param numBits
+ * @return
+ */
+ public static int getLSBMask(int numBits) {
+ int mask = 0;
+ for (int i = 0; i < numBits; i++) {
+ mask = mask | (1 << i);
+ }
+ return mask;
+ }
+
+ /**
+ * Returns the numerical value of the byte array passed
+ *
+ * @param byte[] - array
+ * @return long - numerical value of byte array passed
+ */
+ static public long toNumber(byte[] array) {
+ long ret = 0;
+ long length = array.length;
+ int value = 0;
+ for (int i = 0; i < length; i++) {
+ value = array[i];
+ if (value < 0)
+ value += 256;
+ ret = ret
+ | (long) ((long) value << ((length - i - 1) * NetUtils.NumBitsInAByte));
+ }
+ return ret;
+ }
+
+ /**
+ * Returns the numerical value of the last numBits (LSB bits) of the byte
+ * array passed
+ *
+ * @param byte[] - array
+ * @param int - numBits
+ * @return long - numerical value of byte array passed
+ */
+ static public long toNumber(byte[] array, int numBits) {
+ int length = numBits / NetUtils.NumBitsInAByte;
+ int bitsRest = numBits % NetUtils.NumBitsInAByte;
+ int startOffset = array.length - length;
+ long ret = 0;
+ int value = 0;
+
+ value = array[startOffset - 1] & getLSBMask(bitsRest);
+ value = (array[startOffset - 1] < 0) ? (array[startOffset - 1] + 256)
+ : array[startOffset - 1];
+ ret = ret
+ | (value << ((array.length - startOffset) * NetUtils.NumBitsInAByte));
+
+ for (int i = startOffset; i < array.length; i++) {
+ value = array[i];
+ if (value < 0)
+ value += 256;
+ ret = ret
+ | (long) ((long) value << ((array.length - i - 1) * NetUtils.NumBitsInAByte));
+ }
+
+ return ret;
+ }
+
+ /**
+ * Accepts a number as input and returns its value in byte form in LSB
+ * aligned form example: input = 5000 [1001110001000] bytes = 19, -120
+ * [00010011] [10001000]
+ *
+ * @param Number
+ * @return byte[]
+ *
+ */
+
+ public static byte[] toByteArray(Number input) {
+ Class<? extends Number> dataType = input.getClass();
+ short size = 0;
+ long longValue = input.longValue();
+
+ if (dataType == Byte.class || dataType == byte.class) {
+ size = Byte.SIZE;
+ } else if (dataType == Short.class || dataType == short.class) {
+ size = Short.SIZE;
+ } else if (dataType == Integer.class || dataType == int.class) {
+ size = Integer.SIZE;
+ } else if (dataType == Long.class || dataType == long.class) {
+ size = Long.SIZE;
+ } else {
+ throw new IllegalArgumentException(
+ "Parameter must one of the following: Short/Int/Long\n");
+ }
+
+ int length = size / NetUtils.NumBitsInAByte;
+ byte bytes[] = new byte[length];
+
+ // Getting the bytes from input value
+ for (int i = 0; i < length; i++) {
+ bytes[i] = (byte) ((longValue >> (NetUtils.NumBitsInAByte * (length
+ - i - 1))) & ByteMask);
+ }
+ return bytes;
+ }
+
+ /**
+ * Accepts a number as input and returns its value in byte form in MSB
+ * aligned form example: input = 5000 [1001110001000] bytes = -114, 64
+ * [10011100] [01000000]
+ *
+ * @param Number
+ * input
+ * @param int numBits - the number of bits to be returned
+ * @return byte[]
+ *
+ */
+ public static byte[] toByteArray(Number input, int numBits) {
+ Class<? extends Number> dataType = input.getClass();
+ short size = 0;
+ long longValue = input.longValue();
+
+ if (dataType == Short.class) {
+ size = Short.SIZE;
+ } else if (dataType == Integer.class) {
+ size = Integer.SIZE;
+ } else if (dataType == Long.class) {
+ size = Long.SIZE;
+ } else {
+ throw new IllegalArgumentException(
+ "Parameter must one of the following: Short/Int/Long\n");
+ }
+
+ int length = size / NetUtils.NumBitsInAByte;
+ byte bytes[] = new byte[length];
+ byte[] inputbytes = new byte[length];
+ byte shiftedBytes[];
+
+ // Getting the bytes from input value
+ for (int i = 0; i < length; i++) {
+ bytes[i] = (byte) ((longValue >> (NetUtils.NumBitsInAByte * (length
+ - i - 1))) & ByteMask);
+ }
+
+ if ((bytes[0] == 0 && dataType == Long.class)
+ || (bytes[0] == 0 && dataType == Integer.class)) {
+ int index = 0;
+ for (index = 0; index < length; ++index) {
+ if (bytes[index] != 0) {
+ bytes[0] = bytes[index];
+ break;
+ }
+ }
+ System.arraycopy(bytes, index, inputbytes, 0, length - index);
+ Arrays.fill(bytes, length - index + 1, length - 1, (byte) 0);
+ } else {
+ System.arraycopy(bytes, 0, inputbytes, 0, length);
+ }
+
+ shiftedBytes = shiftBitsToMSB(inputbytes, numBits);
+
+ return shiftedBytes;
+ }
+
+ /**
+ * Takes an LSB aligned byte array and returned the LSB numBits in a MSB
+ * aligned byte array
+ *
+ * @param inputbytes
+ * @param numBits
+ * @return
+ */
+ /**
+ * It aligns the last numBits bits to the head of the byte array following
+ * them with numBits % 8 zero bits.
+ *
+ * Example: For inputbytes = [00000111][01110001] and numBits = 12 it
+ * returns: shiftedBytes = [01110111][00010000]
+ *
+ * @param byte[] inputBytes
+ * @param int numBits - number of bits to be left aligned
+ * @return byte[]
+ */
+ public static byte[] shiftBitsToMSB(byte[] inputBytes, int numBits) {
+ int numBitstoShiftBy = 0, leadZeroesMSB = 8, numEndRestBits = 0;
+ int size = inputBytes.length;
+ byte[] shiftedBytes = new byte[size];
+ int i;
+
+ for (i = 0; i < Byte.SIZE; i++) {
+ if (((byte) (inputBytes[0] & getMSBMask(i + 1))) != 0) {
+ leadZeroesMSB = i;
+ break;
+ }
+ }
+
+ if (numBits % NetUtils.NumBitsInAByte == 0) {
+ numBitstoShiftBy = 0;
+ } else {
+ numBitstoShiftBy = ((NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte)) < leadZeroesMSB) ? (NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte))
+ : leadZeroesMSB;
+ }
+ if (numBitstoShiftBy == 0) {
+ return inputBytes;
+ }
+
+ if (numBits < NetUtils.NumBitsInAByte) {
+ // inputbytes.length = 1 OR read less than a byte
+ shiftedBytes[0] = (byte) ((inputBytes[0] & getLSBMask(numBits)) << numBitstoShiftBy);
+ } else {
+ // # of bits to read from last byte
+ numEndRestBits = NetUtils.NumBitsInAByte
+ - (inputBytes.length * NetUtils.NumBitsInAByte - numBits - numBitstoShiftBy);
+
+ for (i = 0; i < (size - 1); i++) {
+ if ((i + 1) == (size - 1)) {
+ if (numEndRestBits > numBitstoShiftBy) {
+ shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (numEndRestBits - numBitstoShiftBy)));
+ shiftedBytes[i + 1] = (byte) ((inputBytes[i + 1] & getLSBMask(numEndRestBits
+ - numBitstoShiftBy)) << numBitstoShiftBy);
+ } else
+ shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numEndRestBits)) >> (NetUtils.NumBitsInAByte - numEndRestBits)));
+ }
+ shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (NetUtils.NumBitsInAByte - numBitstoShiftBy));
+ }
+
+ }
+ return shiftedBytes;
+ }
+
+ /**
+ * It aligns the first numBits bits to the right end of the byte array
+ * preceding them with numBits % 8 zero bits.
+ *
+ * Example: For inputbytes = [01110111][00010000] and numBits = 12 it
+ * returns: shiftedBytes = [00000111][01110001]
+ *
+ * @param byte[] inputBytes
+ * @param int numBits - number of bits to be right aligned
+ * @return byte[]
+ */
+ public static byte[] shiftBitsToLSB(byte[] inputBytes, int numBits) {
+ int numBytes = inputBytes.length;
+ int numBitstoShift = numBits % NetUtils.NumBitsInAByte;
+ byte[] shiftedBytes = new byte[numBytes];
+ int inputLsb = 0, inputMsb = 0;
+
+ if (numBitstoShift == 0) {
+ return inputBytes;
+ }
+
+ for (int i = 1; i < numBytes; i++) {
+ inputLsb = inputBytes[i - 1]
+ & getLSBMask(NetUtils.NumBitsInAByte - numBitstoShift);
+ inputLsb = (inputLsb < 0) ? (inputLsb + 256) : inputLsb;
+ inputMsb = inputBytes[i] & getMSBMask(numBitstoShift);
+ inputMsb = (inputBytes[i] < 0) ? (inputBytes[i] + 256)
+ : inputBytes[i];
+ shiftedBytes[i] = (byte) ((inputLsb << numBitstoShift) | (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift)));
+ }
+ inputMsb = inputBytes[0] & (getMSBMask(numBitstoShift));
+ inputMsb = (inputMsb < 0) ? (inputMsb + 256) : inputMsb;
+ shiftedBytes[0] = (byte) (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift));
+ return shiftedBytes;
+ }
+
+ /**
+ * Insert in the data buffer at position dictated by the offset the number
+ * of bits specified from the input data byte array. The input byte array
+ * has the bits stored starting from the LSB
+ *
+ * @param byte[] data
+ * @param byte[] inputdata
+ * @param int startOffset
+ * @param int numBits
+ */
+ public static void insertBits(byte[] data, byte[] inputdataLSB,
+ int startOffset, int numBits) {
+ byte[] inputdata = shiftBitsToMSB(inputdataLSB, numBits); // Align to
+ // MSB the
+ // passed byte
+ // array
+ int numBytes = numBits / NetUtils.NumBitsInAByte;
+ int startByteOffset = startOffset / NetUtils.NumBitsInAByte;
+ int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte;
+ int extranumBits = numBits % NetUtils.NumBitsInAByte;
+ int RestBits = numBits % NetUtils.NumBitsInAByte;
+ int InputMSBbits = 0, InputLSBbits = 0;
+ int i;
+
+ if (numBits == 0) {
+ return;
+ }
+
+ if (extraOffsetBits == 0) {
+ if (extranumBits == 0) {
+ numBytes = numBits / NetUtils.NumBitsInAByte;
+ System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
+ } else {
+ System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
+ data[startByteOffset + numBytes] = (byte) (data[startByteOffset
+ + numBytes] | (inputdata[numBytes] & getMSBMask(extranumBits)));
+ }
+ } else {
+ for (i = 0; i < numBytes; i++) {
+ if (i != 0)
+ InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
+ InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
+ - extraOffsetBits)));
+ InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
+ : InputMSBbits + 256;
+ data[startByteOffset + i] = (byte) (data[startByteOffset + i]
+ | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
+ InputMSBbits = InputLSBbits = 0;
+ }
+ if (RestBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) {
+ if (numBytes != 0)
+ InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
+ InputMSBbits = (byte) (inputdata[i] & (getMSBMask(RestBits)));
+ InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
+ : InputMSBbits + 256;
+ data[startByteOffset + i] = (byte) ((data[startByteOffset + i])
+ | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
+ } else if (RestBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) {
+ if (numBytes != 0)
+ InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
+ InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
+ - extraOffsetBits)));
+ InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
+ : InputMSBbits + 256;
+ data[startByteOffset + i] = (byte) (data[startByteOffset + i]
+ | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
+ } else {
+ if (numBytes != 0)
+ InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
+ InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
+ - extraOffsetBits)));
+ InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
+ : InputMSBbits + 256;
+ data[startByteOffset + i] = (byte) (data[startByteOffset + i]
+ | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
+
+ InputLSBbits = (inputdata[i] & (getLSBMask(RestBits
+ - (NetUtils.NumBitsInAByte - extraOffsetBits)) << (NetUtils.NumBitsInAByte - RestBits)));
+ data[startByteOffset + i + 1] = (byte) (data[startByteOffset
+ + i + 1] | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)));
+ }
+ }
+ }
+
+ /**
+ * Checks for overflow and underflow exceptions
+ * @param data
+ * @param startOffset
+ * @param numBits
+ * @throws PacketException when the startOffset and numBits parameters
+ * are not congruent with the data buffer's size
+ */
+ public static void checkExceptions(byte[] data, int startOffset, int numBits)
+ throws BufferException {
+ int endOffsetByte;
+ int startByteOffset;
+ endOffsetByte = startOffset
+ / NetUtils.NumBitsInAByte
+ + numBits
+ / NetUtils.NumBitsInAByte
+ + ((numBits % NetUtils.NumBitsInAByte != 0) ? 1 : ((startOffset
+ % NetUtils.NumBitsInAByte != 0) ? 1 : 0));
+ startByteOffset = startOffset / NetUtils.NumBitsInAByte;
+
+ if (data == null) {
+ throw new BufferException("data[] is null\n");
+ }
+
+ if ((startOffset < 0) || (startByteOffset >= data.length)
+ || (endOffsetByte > data.length) || (numBits < 0)
+ || (numBits > NetUtils.NumBitsInAByte * data.length)) {
+ throw new BufferException(
+ "Illegal arguement/out of bound exception - data.length = "
+ + data.length + " startOffset = " + startOffset
+ + " numBits " + numBits);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.liblldp;
+
+/**
+ * Describes an exception that is raised during BitBufferHelper operations.
+ */
+public class BufferException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public BufferException(String message) {
+ super(message);
+ }
+}
--- /dev/null
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+/**
+ * @file ConstructionException.java
+ *
+ *
+ * @brief Describe an exception that is raised when a construction
+ * for a Node/NodeConnector/Edge or any of the SAL basic object fails
+ * because input passed are not valid or compatible
+ *
+ *
+ */
+package org.opendaylight.controller.liblldp;
+
+public class ConstructionException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public ConstructionException(String message) {
+ super(message);
+ }
+}
--- /dev/null
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @file DataLinkAddress.java
+ *
+ * @brief Abstract base class for a Datalink Address
+ *
+ */
+
+/**
+ * Abstract base class for a Datalink Address
+ *
+ */
+@XmlRootElement
+abstract public class DataLinkAddress implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private String name;
+
+ public DataLinkAddress() {
+
+ }
+
+ /**
+ * Constructor of super class
+ *
+ * @param name Create a new DataLink, not for general use but
+ * available only for sub classes
+ *
+ * @return constructed object
+ */
+ protected DataLinkAddress(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Used to copy the DataLinkAddress in a polymorphic way
+ *
+ *
+ * @return A clone of this DataLinkAddress
+ */
+ @Override
+ abstract public DataLinkAddress clone();
+
+ /**
+ * Allow to distinguish among different data link addresses
+ *
+ *
+ * @return Name of the DataLinkAdress we are working on
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ DataLinkAddress other = (DataLinkAddress) obj;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "DataLinkAddress [name=" + name + "]";
+ }
+}
--- /dev/null
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The enum contains the most common 802.3 ethernet types and 802.2 + SNAP protocol ids
+ *
+ *
+ *
+ */
+public enum EtherTypes {
+ PVSTP("PVSTP", 0x010B), // 802.2 + SNAP (Spanning Tree)
+ CDP("CDP", 0x2000), // 802.2 + SNAP
+ VTP("VTP", 0x2003), // 802.2 + SNAP
+ IPv4("IPv4", 0x800), ARP("ARP", 0x806), RARP("Reverse ARP", 0x8035), VLANTAGGED(
+ "VLAN Tagged", 0x8100), // 802.1Q
+ IPv6("IPv6", 0x86DD), MPLSUCAST("MPLS Unicast", 0x8847), MPLSMCAST(
+ "MPLS Multicast", 0x8848), QINQ("QINQ", 0x88A8), // Standard 802.1ad QinQ
+ LLDP("LLDP", 0x88CC), OLDQINQ("Old QINQ", 0x9100), // Old non-standard QinQ
+ CISCOQINQ("Cisco QINQ", 0x9200); // Cisco non-standard QinQ
+
+ private static final String regexNumberString = "^[0-9]+$";
+ private String description;
+ private int number;
+
+ private EtherTypes(String description, int number) {
+ this.description = description;
+ this.number = number;
+ }
+
+ public String toString() {
+ return description;
+ }
+
+ public int intValue() {
+ return number;
+ }
+
+ public short shortValue() {
+ return ((Integer) number).shortValue();
+ }
+
+ public static String getEtherTypeName(int number) {
+ return getEtherTypeInternal(number);
+ }
+
+ public static String getEtherTypeName(short number) {
+ return getEtherTypeInternal((int) number & 0xffff);
+ }
+
+ public static String getEtherTypeName(byte number) {
+ return getEtherTypeInternal((int) number & 0xff);
+ }
+
+ private static String getEtherTypeInternal(int number) {
+ for (EtherTypes type : EtherTypes.values()) {
+ if (type.number == number) {
+ return type.toString();
+ }
+ }
+ return "0x" + Integer.toHexString(number);
+ }
+
+ public static short getEtherTypeNumberShort(String name) {
+ if (name.matches(regexNumberString)) {
+ return Short.valueOf(name);
+ }
+ for (EtherTypes type : EtherTypes.values()) {
+ if (type.description.equalsIgnoreCase(name)) {
+ return type.shortValue();
+ }
+ }
+ return 0;
+ }
+
+ public static int getEtherTypeNumberInt(String name) {
+ if (name.matches(regexNumberString)) {
+ return Integer.valueOf(name);
+ }
+ for (EtherTypes type : EtherTypes.values()) {
+ if (type.description.equalsIgnoreCase(name)) {
+ return type.intValue();
+ }
+ }
+ return 0;
+ }
+
+ public static List<String> getEtherTypesNameList() {
+ List<String> ethertypesList = new ArrayList<String>();
+ for (EtherTypes type : EtherTypes.values()) {
+ ethertypesList.add(type.toString());
+ }
+ return ethertypesList;
+ }
+
+ public static EtherTypes loadFromString(String string) {
+ int intType = Integer.parseInt(string);
+
+ for (EtherTypes type : EtherTypes.values()) {
+ if (type.number == intType) {
+ return type;
+ }
+ }
+ return null;
+ }
+
+}
--- /dev/null
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+
+/**
+ * Class that represents the Ethernet frame objects
+ */
+public class Ethernet extends Packet {
+ private static final String DMAC = "DestinationMACAddress";
+ private static final String SMAC = "SourceMACAddress";
+ private static final String ETHT = "EtherType";
+
+ // TODO: This has to be outside and it should be possible for osgi
+ // to add new coming packet classes
+ public static final Map<Short, Class<? extends Packet>> etherTypeClassMap;
+ static {
+ etherTypeClassMap = new HashMap<Short, Class<? extends Packet>>();
+ etherTypeClassMap.put(EtherTypes.LLDP.shortValue(), LLDP.class);
+ }
+ private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
+ private static final long serialVersionUID = 1L;
+ {
+ put(DMAC, new ImmutablePair<Integer, Integer>(0, 48));
+ put(SMAC, new ImmutablePair<Integer, Integer>(48, 48));
+ put(ETHT, new ImmutablePair<Integer, Integer>(96, 16));
+ }
+ };
+ private final Map<String, byte[]> fieldValues;
+
+ /**
+ * Default constructor that creates and sets the HashMap
+ */
+ public Ethernet() {
+ super();
+ fieldValues = new HashMap<String, byte[]>();
+ hdrFieldCoordMap = fieldCoordinates;
+ hdrFieldsMap = fieldValues;
+ }
+
+ /**
+ * Constructor that sets the access level for the packet and
+ * creates and sets the HashMap
+ */
+ public Ethernet(boolean writeAccess) {
+ super(writeAccess);
+ fieldValues = new HashMap<String, byte[]>();
+ hdrFieldCoordMap = fieldCoordinates;
+ hdrFieldsMap = fieldValues;
+ }
+
+ @Override
+ public void setHeaderField(String headerField, byte[] readValue) {
+ if (headerField.equals(ETHT)) {
+ payloadClass = etherTypeClassMap.get(BitBufferHelper
+ .getShort(readValue));
+ }
+ hdrFieldsMap.put(headerField, readValue);
+ }
+
+ /**
+ * Gets the destination MAC address stored
+ * @return byte[] - the destinationMACAddress
+ */
+ public byte[] getDestinationMACAddress() {
+ return fieldValues.get(DMAC);
+ }
+
+ /**
+ * Gets the source MAC address stored
+ * @return byte[] - the sourceMACAddress
+ */
+ public byte[] getSourceMACAddress() {
+ return fieldValues.get(SMAC);
+ }
+
+ /**
+ * Gets the etherType stored
+ * @return short - the etherType
+ */
+ public short getEtherType() {
+ return BitBufferHelper.getShort(fieldValues.get(ETHT));
+ }
+
+ public boolean isBroadcast(){
+ return NetUtils.isBroadcastMACAddr(getDestinationMACAddress());
+ }
+
+ public boolean isMulticast(){
+ return NetUtils.isMulticastMACAddr(getDestinationMACAddress());
+ }
+
+ /**
+ * Sets the destination MAC address for the current Ethernet object instance
+ * @param byte[] - the destinationMACAddress to set
+ */
+ public Ethernet setDestinationMACAddress(byte[] destinationMACAddress) {
+ fieldValues.put(DMAC, destinationMACAddress);
+ return this;
+ }
+
+ /**
+ * Sets the source MAC address for the current Ethernet object instance
+ * @param byte[] - the sourceMACAddress to set
+ */
+ public Ethernet setSourceMACAddress(byte[] sourceMACAddress) {
+ fieldValues.put(SMAC, sourceMACAddress);
+ return this;
+ }
+
+ /**
+ * Sets the etherType for the current Ethernet object instance
+ * @param short - the etherType to set
+ */
+ public Ethernet setEtherType(short etherType) {
+ byte[] ethType = BitBufferHelper.toByteArray(etherType);
+ fieldValues.put(ETHT, ethType);
+ return this;
+ }
+
+}
--- /dev/null
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.util.Arrays;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class EthernetAddress extends DataLinkAddress {
+ private static final long serialVersionUID = 1L;
+ @XmlTransient
+ private byte[] macAddress;
+
+ public static final EthernetAddress BROADCASTMAC = createWellKnownAddress(new byte[] {
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff });
+
+ public static final EthernetAddress INVALIDHOST = BROADCASTMAC;
+
+ public static final String addressName = "Ethernet MAC Address";
+ public static final int SIZE = 6;
+
+ private static final EthernetAddress createWellKnownAddress(byte[] mac) {
+ try {
+ return new EthernetAddress(mac);
+ } catch (ConstructionException ce) {
+ return null;
+ }
+ }
+
+ /* Private constructor to satisfy JAXB */
+ @SuppressWarnings("unused")
+ private EthernetAddress() {
+ }
+
+ /**
+ * Public constructor for an Ethernet MAC address starting from
+ * the byte constituing the address, the constructor validate the
+ * size of the arrive to make sure it met the expected size
+ *
+ * @param macAddress A byte array in big endian format
+ * representing the Ethernet MAC Address
+ *
+ * @return The constructed object if valid
+ */
+ public EthernetAddress(byte[] macAddress) throws ConstructionException {
+ super(addressName);
+
+ if (macAddress == null) {
+ throw new ConstructionException("Null input parameter passed");
+ }
+
+ if (macAddress.length != SIZE) {
+ throw new ConstructionException(
+ "Wrong size of passed byte array, expected:" + SIZE
+ + " got:" + macAddress.length);
+ }
+ this.macAddress = new byte[SIZE];
+ System.arraycopy(macAddress, 0, this.macAddress, 0, SIZE);
+ }
+
+ public EthernetAddress clone() {
+ try {
+ return new EthernetAddress(this.macAddress.clone());
+ } catch (ConstructionException ce) {
+ return null;
+ }
+ }
+
+ /**
+ * Return the Ethernet Mac address in byte array format
+ *
+ * @return The Ethernet Mac address in byte array format
+ */
+ public byte[] getValue() {
+ return this.macAddress;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Arrays.hashCode(macAddress);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ EthernetAddress other = (EthernetAddress) obj;
+ if (!Arrays.equals(macAddress, other.macAddress))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "EthernetAddress [macAddress=" + HexEncode.bytesToHexStringFormat(macAddress)
+ + "]";
+ }
+
+ @XmlElement(name = "macAddress")
+ public String getMacAddress() {
+ return HexEncode.bytesToHexStringFormat(macAddress);
+ }
+}
--- /dev/null
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.math.BigInteger;
+
+/**
+ * The class provides methods to convert hex encode strings
+ *
+ *
+ */
+public class HexEncode {
+ /**
+ * This method converts byte array into String format without ":" inserted.
+ *
+ * @param bytes
+ * The byte array to convert to string
+ * @return The hexadecimal representation of the byte array. If bytes is
+ * null, "null" string is returned
+ */
+ public static String bytesToHexString(byte[] bytes) {
+
+ if (bytes == null) {
+ return "null";
+ }
+
+ String ret = "";
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < bytes.length; i++) {
+ if (i > 0) {
+ ret += ":";
+ }
+ short u8byte = (short) (bytes[i] & 0xff);
+ String tmp = Integer.toHexString(u8byte);
+ if (tmp.length() == 1) {
+ buf.append("0");
+ }
+ buf.append(tmp);
+ }
+ ret = buf.toString();
+ return ret;
+ }
+
+ public static String longToHexString(long val) {
+ char arr[] = Long.toHexString(val).toCharArray();
+ StringBuffer buf = new StringBuffer();
+ // prepend the right number of leading zeros
+ int i = 0;
+ for (; i < (16 - arr.length); i++) {
+ buf.append("0");
+ if ((i & 0x01) == 1) {
+ buf.append(":");
+ }
+ }
+ for (int j = 0; j < arr.length; j++) {
+ buf.append(arr[j]);
+ if ((((i + j) & 0x01) == 1) && (j < (arr.length - 1))) {
+ buf.append(":");
+ }
+ }
+ return buf.toString();
+ }
+
+
+ public static byte[] bytesFromHexString(String values) {
+ String target = "";
+ if (values != null) {
+ target = values;
+ }
+ String[] octets = target.split(":");
+
+ byte[] ret = new byte[octets.length];
+ for (int i = 0; i < octets.length; i++) {
+ ret[i] = Integer.valueOf(octets[i], 16).byteValue();
+ }
+ return ret;
+ }
+
+ public static long stringToLong(String values) {
+ long value = new BigInteger(values.replaceAll(":", ""), 16).longValue();
+ return value;
+ }
+
+ /**
+ * This method converts byte array into HexString format with ":" inserted.
+ */
+ public static String bytesToHexStringFormat(byte[] bytes) {
+ if (bytes == null) {
+ return "null";
+ }
+ String ret = "";
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < bytes.length; i++) {
+ if (i > 0) {
+ buf.append(":");
+ }
+ short u8byte = (short) (bytes[i] & 0xff);
+ String tmp = Integer.toHexString(u8byte);
+ if (tmp.length() == 1) {
+ buf.append("0");
+ }
+ buf.append(tmp);
+ }
+ ret = buf.toString();
+ return ret;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class that represents the LLDP frame objects
+ */
+
+public class LLDP extends Packet {
+ private static final String CHASSISID = "ChassisId";
+ private static final String SYSTEMNAMEID = "SystemNameID";
+ private static final String PORTID = "PortId";
+ private static final String TTL = "TTL";
+ private static final int LLDPDefaultTlvs = 4;
+ private static LLDPTLV emptyTLV = new LLDPTLV().setLength((short) 0)
+ .setType((byte) 0);
+ public static final byte[] LLDPMulticastMac = { 1, (byte) 0x80,
+ (byte) 0xc2, 0, 0, (byte) 0xe };
+ private Map<Byte, LLDPTLV> tlvList;
+
+ /**
+ * Default constructor that creates the tlvList LinkedHashMap
+ */
+ public LLDP() {
+ super();
+ tlvList = new LinkedHashMap<Byte, LLDPTLV>(LLDPDefaultTlvs);
+ }
+
+ /**
+ * Constructor that creates the tlvList LinkedHashMap and sets the write
+ * access for the same
+ */
+ public LLDP(boolean writeAccess) {
+ super(writeAccess);
+ tlvList = new LinkedHashMap<Byte, LLDPTLV>(LLDPDefaultTlvs); // Mandatory
+ // TLVs
+ }
+
+ /**
+ * @param String
+ * - description of the type of TLV
+ * @return byte - type of TLV
+ */
+ private byte getType(String typeDesc) {
+ if (typeDesc.equals(CHASSISID)) {
+ return LLDPTLV.TLVType.ChassisID.getValue();
+ } else if (typeDesc.equals(PORTID)) {
+ return LLDPTLV.TLVType.PortID.getValue();
+ } else if (typeDesc.equals(TTL)) {
+ return LLDPTLV.TLVType.TTL.getValue();
+ } else {
+ return LLDPTLV.TLVType.Unknown.getValue();
+ }
+ }
+
+ /**
+ * @param String
+ * - description of the type of TLV
+ * @return LLDPTLV - full TLV
+ */
+ public LLDPTLV getTLV(String type) {
+ return tlvList.get(getType(type));
+ }
+
+ /**
+ * @param String
+ * - description of the type of TLV
+ * @param LLDPTLV
+ * - tlv to set
+ * @return void
+ */
+ public void setTLV(String type, LLDPTLV tlv) {
+ tlvList.put(getType(type), tlv);
+ }
+
+ /**
+ * @return the chassisId TLV
+ */
+ public LLDPTLV getChassisId() {
+ return getTLV(CHASSISID);
+ }
+
+ /**
+ * @param LLDPTLV
+ * - the chassisId to set
+ */
+ public LLDP setChassisId(LLDPTLV chassisId) {
+ tlvList.put(getType(CHASSISID), chassisId);
+ return this;
+ }
+
+ /**
+ * @return the SystemName TLV
+ */
+ public LLDPTLV getSystemNameId() {
+ return getTLV(SYSTEMNAMEID);
+ }
+
+ /**
+ * @param LLDPTLV
+ * - the chassisId to set
+ */
+ public LLDP setSystemNameId(LLDPTLV systemNameId) {
+ tlvList.put(getType(SYSTEMNAMEID), systemNameId);
+ return this;
+ }
+
+ /**
+ * @return LLDPTLV - the portId TLV
+ */
+ public LLDPTLV getPortId() {
+ return tlvList.get(getType(PORTID));
+ }
+
+ /**
+ * @param LLDPTLV
+ * - the portId to set
+ * @return LLDP
+ */
+ public LLDP setPortId(LLDPTLV portId) {
+ tlvList.put(getType(PORTID), portId);
+ return this;
+ }
+
+ /**
+ * @return LLDPTLV - the ttl TLV
+ */
+ public LLDPTLV getTtl() {
+ return tlvList.get(getType(TTL));
+ }
+
+ /**
+ * @param LLDPTLV
+ * - the ttl to set
+ * @return LLDP
+ */
+ public LLDP setTtl(LLDPTLV ttl) {
+ tlvList.put(getType(TTL), ttl);
+ return this;
+ }
+
+ /**
+ * @return the optionalTLVList
+ */
+ public List<LLDPTLV> getOptionalTLVList() {
+ List<LLDPTLV> list = new ArrayList<LLDPTLV>();
+ for (Map.Entry<Byte, LLDPTLV> entry : tlvList.entrySet()) {
+ byte type = entry.getKey();
+ if ((type == LLDPTLV.TLVType.ChassisID.getValue())
+ || (type == LLDPTLV.TLVType.PortID.getValue())
+ || (type == LLDPTLV.TLVType.TTL.getValue())) {
+ continue;
+ } else {
+ list.add(entry.getValue());
+ }
+ }
+ return list;
+ }
+
+ /**
+ * @param optionalTLVList
+ * the optionalTLVList to set
+ * @return LLDP
+ */
+ public LLDP setOptionalTLVList(List<LLDPTLV> optionalTLVList) {
+ for (LLDPTLV tlv : optionalTLVList) {
+ tlvList.put(tlv.getType(), tlv);
+ }
+ return this;
+ }
+
+ @Override
+ public Packet deserialize(byte[] data, int bitOffset, int size)
+ throws PacketException {
+ int lldpOffset = bitOffset; // LLDP start
+ int lldpSize = size; // LLDP size
+
+ if (logger.isTraceEnabled()) {
+ logger.trace("LLDP: {} (offset {} bitsize {})", new Object[] {
+ HexEncode.bytesToHexString(data), lldpOffset, lldpSize });
+ }
+ /*
+ * Deserialize the TLVs until we reach the end of the packet
+ */
+ while (lldpSize > 0) {
+ LLDPTLV tlv = new LLDPTLV();
+ tlv.deserialize(data, lldpOffset, lldpSize);
+ if (tlv.getType() == 0 && tlv.getLength() == 0) {
+ break;
+ }
+ int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits
+ lldpOffset += tlvSize;
+ lldpSize -= tlvSize;
+ this.tlvList.put(tlv.getType(), tlv);
+ }
+ return this;
+ }
+
+ @Override
+ public byte[] serialize() throws PacketException {
+ int startOffset = 0;
+ byte[] serializedBytes = new byte[getLLDPPacketLength()];
+
+ for (Map.Entry<Byte, LLDPTLV> entry : tlvList.entrySet()) {
+ LLDPTLV tlv = entry.getValue();
+ int numBits = tlv.getTLVSize();
+ try {
+ BitBufferHelper.setBytes(serializedBytes, tlv.serialize(),
+ startOffset, numBits);
+ } catch (BufferException e) {
+ throw new PacketException(e.getMessage());
+ }
+ startOffset += numBits;
+ }
+ // Now add the empty LLDPTLV at the end
+ try {
+ BitBufferHelper.setBytes(serializedBytes,
+ LLDP.emptyTLV.serialize(), startOffset,
+ LLDP.emptyTLV.getTLVSize());
+ } catch (BufferException e) {
+ throw new PacketException(e.getMessage());
+ }
+
+ if (logger.isTraceEnabled()) {
+ logger.trace("LLDP: serialized: {}",
+ HexEncode.bytesToHexString(serializedBytes));
+ }
+ return serializedBytes;
+ }
+
+ /**
+ * Returns the size of LLDP packet in bytes
+ *
+ * @return int - LLDP Packet size in bytes
+ */
+ private int getLLDPPacketLength() {
+ int len = 0;
+ LLDPTLV tlv;
+
+ for (Map.Entry<Byte, LLDPTLV> entry : this.tlvList.entrySet()) {
+ tlv = entry.getValue();
+ len += tlv.getTLVSize();
+ }
+ len += LLDP.emptyTLV.getTLVSize();
+
+ return len / NetUtils.NumBitsInAByte;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.MutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+
+/**
+ * Class that represents the LLDPTLV objects
+ */
+
+public class LLDPTLV extends Packet {
+ private static final String TYPE = "Type";
+ private static final String LENGTH = "Length";
+ private static final String VALUE = "Value";
+ private static final int LLDPTLVFields = 3;
+ public static final byte[] OFOUI = new byte[] { (byte) 0x00, (byte) 0x26,
+ (byte) 0xe1 }; // OpenFlow OUI
+ public static final byte[] customTlvSubType = new byte[] { 0 };
+ public static final int customTlvOffset = OFOUI.length
+ + customTlvSubType.length;
+ public static final byte chassisIDSubType[] = new byte[] { 4 }; // MAC address for the system
+ public static final byte portIDSubType[] = new byte[] { 7 }; // locally assigned
+
+ public enum TLVType {
+ Unknown((byte) 0), ChassisID((byte) 1), PortID((byte) 2), TTL((byte) 3), PortDesc(
+ (byte) 4), SystemName((byte) 5), SystemDesc((byte) 6), Custom(
+ (byte) 127);
+
+ private byte value;
+
+ private TLVType(byte value) {
+ this.value = value;
+ }
+
+ public byte getValue() {
+ return value;
+ }
+ }
+
+ private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
+ private static final long serialVersionUID = 1L;
+
+ {
+ put(TYPE, new MutablePair<Integer, Integer>(0, 7));
+ put(LENGTH, new MutablePair<Integer, Integer>(7, 9));
+ put(VALUE, new MutablePair<Integer, Integer>(16, 0));
+ }
+ };
+
+ protected Map<String, byte[]> fieldValues;
+
+ /**
+ * Default constructor that creates and sets the hash map values and sets
+ * the payload to null
+ */
+ public LLDPTLV() {
+ payload = null;
+ fieldValues = new HashMap<String, byte[]>(LLDPTLVFields);
+ hdrFieldCoordMap = fieldCoordinates;
+ hdrFieldsMap = fieldValues;
+ }
+
+ /**
+ * Constructor that writes the passed LLDPTLV values to the hdrFieldsMap
+ */
+ public LLDPTLV(LLDPTLV other) {
+ for (Map.Entry<String, byte[]> entry : other.hdrFieldsMap.entrySet()) {
+ this.hdrFieldsMap.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * @return int - the length of TLV
+ */
+ public int getLength() {
+ return (int) BitBufferHelper.toNumber(fieldValues.get(LENGTH),
+ fieldCoordinates.get(LENGTH).getRight().intValue());
+ }
+
+ /**
+ * @return byte - the type of TLV
+ */
+ public byte getType() {
+ return BitBufferHelper.getByte(fieldValues.get(TYPE));
+ }
+
+ /**
+ * @return byte[] - the value field of TLV
+ */
+ public byte[] getValue() {
+ return fieldValues.get(VALUE);
+ }
+
+ /**
+ * @param byte - the type to set
+ * @return LLDPTLV
+ */
+ public LLDPTLV setType(byte type) {
+ byte[] lldpTLVtype = { type };
+ fieldValues.put(TYPE, lldpTLVtype);
+ return this;
+ }
+
+ /**
+ * @param short - the length to set
+ * @return LLDPTLV
+ */
+ public LLDPTLV setLength(short length) {
+ fieldValues.put(LENGTH, BitBufferHelper.toByteArray(length));
+ return this;
+ }
+
+ /**
+ * @param byte[] - the value to set
+ * @return LLDPTLV
+ */
+ public LLDPTLV setValue(byte[] value) {
+ fieldValues.put(VALUE, value);
+ return this;
+ }
+
+ @Override
+ public void setHeaderField(String headerField, byte[] readValue) {
+ hdrFieldsMap.put(headerField, readValue);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result
+ + ((fieldValues == null) ? 0 : fieldValues.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!super.equals(obj)) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ LLDPTLV other = (LLDPTLV) obj;
+ if (fieldValues == null) {
+ if (other.fieldValues != null) {
+ return false;
+ }
+ } else if (!fieldValues.equals(other.fieldValues)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int getfieldnumBits(String fieldName) {
+ if (fieldName.equals(VALUE)) {
+ return (NetUtils.NumBitsInAByte * BitBufferHelper.getShort(
+ fieldValues.get(LENGTH), fieldCoordinates.get(LENGTH)
+ .getRight().intValue()));
+ }
+ return fieldCoordinates.get(fieldName).getRight();
+ }
+
+ /**
+ * Returns the size in bits of the whole TLV
+ *
+ * @return int - size in bits of full TLV
+ */
+ public int getTLVSize() {
+ return (LLDPTLV.fieldCoordinates.get(TYPE).getRight() + // static
+ LLDPTLV.fieldCoordinates.get(LENGTH).getRight() + // static
+ getfieldnumBits(VALUE)); // variable
+ }
+
+ /**
+ * Creates the SystemName TLV value
+ *
+ * @param nodeId
+ * node identifier string
+ * @return the SystemName TLV value in byte array
+ */
+ static public byte[] createSystemNameTLVValue(String nodeId) {
+ byte[] nid = nodeId.getBytes();
+ return nid;
+ }
+
+ /**
+ * Creates the ChassisID TLV value including the subtype and ChassisID
+ * string
+ *
+ * @param nodeId
+ * node identifier string
+ * @return the ChassisID TLV value in byte array
+ */
+ static public byte[] createChassisIDTLVValue(String nodeId) {
+ byte[] nid = HexEncode.bytesFromHexString(nodeId);
+ byte[] cid = new byte[6];
+ int srcPos = 0, dstPos = 0;
+
+ if (nid.length > cid.length) {
+ srcPos = nid.length - cid.length;
+ } else {
+ dstPos = cid.length - nid.length;
+ }
+ System.arraycopy(nid, srcPos, cid, dstPos, cid.length);
+
+ byte[] cidValue = new byte[cid.length + chassisIDSubType.length];
+
+ System.arraycopy(chassisIDSubType, 0, cidValue, 0,
+ chassisIDSubType.length);
+ System.arraycopy(cid, 0, cidValue, chassisIDSubType.length, cid.length);
+
+ return cidValue;
+ }
+
+ /**
+ * Creates the PortID TLV value including the subtype and PortID string
+ *
+ * @param portId
+ * port identifier string
+ * @return the PortID TLV value in byte array
+ */
+ static public byte[] createPortIDTLVValue(String portId) {
+ byte[] pid = portId.getBytes(Charset.defaultCharset());
+ byte[] pidValue = new byte[pid.length + portIDSubType.length];
+
+ System.arraycopy(portIDSubType, 0, pidValue, 0, portIDSubType.length);
+ System.arraycopy(pid, 0, pidValue, portIDSubType.length, pid.length);
+
+ return pidValue;
+ }
+
+ /**
+ * Creates the custom TLV value including OUI, subtype and custom string
+ *
+ * @param portId
+ * port identifier string
+ * @return the custom TLV value in byte array
+ */
+ static public byte[] createCustomTLVValue(String customString) {
+ byte[] customArray = customString.getBytes(Charset.defaultCharset());
+ byte[] customValue = new byte[customTlvOffset + customArray.length];
+
+ System.arraycopy(OFOUI, 0, customValue, 0, OFOUI.length);
+ System.arraycopy(customTlvSubType, 0, customValue, OFOUI.length,
+ customTlvSubType.length);
+ System.arraycopy(customArray, 0, customValue, customTlvOffset,
+ customArray.length);
+
+ return customValue;
+ }
+
+ /**
+ * Retrieves the string from TLV value and returns it in HexString format
+ *
+ * @param tlvValue
+ * the TLV value
+ * @param tlvLen
+ * the TLV length
+ * @return the HexString
+ */
+ static public String getHexStringValue(byte[] tlvValue, int tlvLen) {
+ byte[] cidBytes = new byte[tlvLen - chassisIDSubType.length];
+ System.arraycopy(tlvValue, chassisIDSubType.length, cidBytes, 0,
+ cidBytes.length);
+ return HexEncode.bytesToHexStringFormat(cidBytes);
+ }
+
+ /**
+ * Retrieves the string from TLV value
+ *
+ * @param tlvValue
+ * the TLV value
+ * @param tlvLen
+ * the TLV length
+ * @return the string
+ */
+ static public String getStringValue(byte[] tlvValue, int tlvLen) {
+ byte[] pidSubType = new byte[portIDSubType.length];
+ byte[] pidBytes = new byte[tlvLen - portIDSubType.length];
+ System.arraycopy(tlvValue, 0, pidSubType, 0,
+ pidSubType.length);
+ System.arraycopy(tlvValue, portIDSubType.length, pidBytes, 0,
+ pidBytes.length);
+ if (pidSubType[0] == (byte) 0x3) {
+ return HexEncode.bytesToHexStringFormat(pidBytes);
+ } else {
+ return (new String(pidBytes, Charset.defaultCharset()));
+ }
+ }
+
+ /**
+ * Retrieves the custom string from the Custom TLV value which includes OUI,
+ * subtype and custom string
+ *
+ * @param customTlvValue
+ * the custom TLV value
+ * @param customTlvLen
+ * the custom TLV length
+ * @return the custom string
+ */
+ static public String getCustomString(byte[] customTlvValue, int customTlvLen) {
+ String customString = "";
+ byte[] vendor = new byte[3];
+ System.arraycopy(customTlvValue, 0, vendor, 0, vendor.length);
+ if (Arrays.equals(vendor, LLDPTLV.OFOUI)) {
+ int customArrayLength = customTlvLen - customTlvOffset;
+ byte[] customArray = new byte[customArrayLength];
+ System.arraycopy(customTlvValue, customTlvOffset, customArray, 0,
+ customArrayLength);
+ try {
+ customString = new String(customArray, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ }
+ }
+
+ return customString;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class containing the common utility functions needed for operating on
+ * networking data structures
+ */
+public abstract class NetUtils {
+ protected static final Logger logger = LoggerFactory.getLogger(NetUtils.class);
+ /**
+ * Constant holding the number of bits in a byte
+ */
+ public static final int NumBitsInAByte = 8;
+
+ /**
+ * Constant holding the number of bytes in MAC Address
+ */
+ public static final int MACAddrLengthInBytes = 6;
+
+ /**
+ * Constant holding the number of words in MAC Address
+ */
+ public static final int MACAddrLengthInWords = 3;
+
+ /**
+ * Constant holding the broadcast MAC address
+ */
+ private static final byte[] BroadcastMACAddr = {-1, -1, -1, -1, -1, -1};
+
+ /**
+ * Converts a 4 bytes array into an integer number
+ *
+ * @param ba
+ * the 4 bytes long byte array
+ * @return the integer number
+ */
+ public static int byteArray4ToInt(byte[] ba) {
+ if (ba == null || ba.length != 4) {
+ return 0;
+ }
+ return (0xff & ba[0]) << 24 | (0xff & ba[1]) << 16 | (0xff & ba[2]) << 8 | (0xff & ba[3]);
+ }
+
+ /**
+ * Converts a 6 bytes array into a long number MAC addresses.
+ *
+ * @param ba
+ * The 6 bytes long byte array.
+ * @return The long number.
+ * Zero is returned if {@code ba} is {@code null} or
+ * the length of it is not six.
+ */
+ public static long byteArray6ToLong(byte[] ba) {
+ if (ba == null || ba.length != MACAddrLengthInBytes) {
+ return 0L;
+ }
+ long num = 0L;
+ int i = 0;
+ do {
+ num <<= NumBitsInAByte;
+ num |= 0xff & ba[i];
+ i++;
+ } while (i < MACAddrLengthInBytes);
+ return num;
+ }
+
+ /**
+ * Converts a long number to a 6 bytes array for MAC addresses.
+ *
+ * @param addr
+ * The long number.
+ * @return The byte array.
+ */
+ public static byte[] longToByteArray6(long addr){
+ byte[] mac = new byte[MACAddrLengthInBytes];
+ int i = MACAddrLengthInBytes - 1;
+ do {
+ mac[i] = (byte) addr;
+ addr >>>= NumBitsInAByte;
+ i--;
+ } while (i >= 0);
+ return mac;
+ }
+
+ /**
+ * Converts an integer number into a 4 bytes array
+ *
+ * @param i
+ * the integer number
+ * @return the byte array
+ */
+ public static byte[] intToByteArray4(int i) {
+ return new byte[] { (byte) ((i >> 24) & 0xff), (byte) ((i >> 16) & 0xff), (byte) ((i >> 8) & 0xff),
+ (byte) (i & 0xff) };
+ }
+
+ /**
+ * Converts an IP address passed as integer value into the respective
+ * InetAddress object
+ *
+ * @param address
+ * the IP address in integer form
+ * @return the IP address in InetAddress form
+ */
+ public static InetAddress getInetAddress(int address) {
+ InetAddress ip = null;
+ try {
+ ip = InetAddress.getByAddress(NetUtils.intToByteArray4(address));
+ } catch (UnknownHostException e) {
+ logger.error("", e);
+ }
+ return ip;
+ }
+
+ /**
+ * Return the InetAddress Network Mask given the length of the prefix bit
+ * mask. The prefix bit mask indicates the contiguous leading bits that are
+ * NOT masked out. Example: A prefix bit mask length of 8 will give an
+ * InetAddress Network Mask of 255.0.0.0
+ *
+ * @param prefixMaskLength
+ * integer representing the length of the prefix network mask
+ * @param isV6
+ * boolean representing the IP version of the returned address
+ * @return
+ */
+ public static InetAddress getInetNetworkMask(int prefixMaskLength, boolean isV6) {
+ if (prefixMaskLength < 0 || (!isV6 && prefixMaskLength > 32) || (isV6 && prefixMaskLength > 128)) {
+ return null;
+ }
+ byte v4Address[] = { 0, 0, 0, 0 };
+ byte v6Address[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ byte address[] = (isV6) ? v6Address : v4Address;
+ int numBytes = prefixMaskLength / 8;
+ int numBits = prefixMaskLength % 8;
+ int i = 0;
+ for (; i < numBytes; i++) {
+ address[i] = (byte) 0xff;
+ }
+ if (numBits > 0) {
+ int rem = 0;
+ for (int j = 0; j < numBits; j++) {
+ rem |= 1 << (7 - j);
+ }
+ address[i] = (byte) rem;
+ }
+
+ try {
+ return InetAddress.getByAddress(address);
+ } catch (UnknownHostException e) {
+ logger.error("", e);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the prefix size in bits of the specified subnet mask. Example:
+ * For the subnet mask ff.ff.ff.e0 it returns 25 while for ff.00.00.00 it
+ * returns 8. If the passed subnetMask array is null, 0 is returned.
+ *
+ * @param subnetMask
+ * the subnet mask as byte array
+ * @return the prefix length as number of bits
+ */
+ public static int getSubnetMaskLength(byte[] subnetMask) {
+ int maskLength = 0;
+ if (subnetMask != null && (subnetMask.length == 4 || subnetMask.length == 16)) {
+ int index = 0;
+ while (index < subnetMask.length && subnetMask[index] == (byte) 0xFF) {
+ maskLength += NetUtils.NumBitsInAByte;
+ index++;
+ }
+ if (index != subnetMask.length) {
+ int bits = NetUtils.NumBitsInAByte - 1;
+ while (bits >= 0 && (subnetMask[index] & 1 << bits) != 0) {
+ bits--;
+ maskLength++;
+ }
+ }
+ }
+ return maskLength;
+ }
+
+ /**
+ * Returns the prefix size in bits of the specified subnet mask. Example:
+ * For the subnet mask 255.255.255.128 it returns 25 while for 255.0.0.0 it
+ * returns 8. If the passed subnetMask object is null, 0 is returned
+ *
+ * @param subnetMask
+ * the subnet mask as InetAddress
+ * @return the prefix length as number of bits
+ */
+ public static int getSubnetMaskLength(InetAddress subnetMask) {
+ return subnetMask == null ? 0 : NetUtils.getSubnetMaskLength(subnetMask.getAddress());
+ }
+
+ /**
+ * Given an IP address and a prefix network mask length, it returns the
+ * equivalent subnet prefix IP address Example: for ip = "172.28.30.254" and
+ * maskLen = 25 it will return "172.28.30.128"
+ *
+ * @param ip
+ * the IP address in InetAddress form
+ * @param maskLen
+ * the length of the prefix network mask
+ * @return the subnet prefix IP address in InetAddress form
+ */
+ public static InetAddress getSubnetPrefix(InetAddress ip, int maskLen) {
+ int bytes = maskLen / 8;
+ int bits = maskLen % 8;
+ byte modifiedByte;
+ byte[] sn = ip.getAddress();
+ if (bits > 0) {
+ modifiedByte = (byte) (sn[bytes] >> (8 - bits));
+ sn[bytes] = (byte) (modifiedByte << (8 - bits));
+ bytes++;
+ }
+ for (; bytes < sn.length; bytes++) {
+ sn[bytes] = (byte) (0);
+ }
+ try {
+ return InetAddress.getByAddress(sn);
+ } catch (UnknownHostException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Checks if the test address and mask conflicts with the filter address and
+ * mask
+ *
+ * For example:
+ * testAddress: 172.28.2.23
+ * testMask: 255.255.255.0
+ * filterAddress: 172.28.1.10
+ * testMask: 255.255.255.0
+ * do conflict
+ *
+ * testAddress: 172.28.2.23
+ * testMask: 255.255.255.0
+ * filterAddress: 172.28.1.10
+ * testMask: 255.255.0.0
+ * do not conflict
+ *
+ * Null parameters are permitted
+ *
+ * @param testAddress
+ * @param filterAddress
+ * @param testMask
+ * @param filterMask
+ * @return
+ */
+ public static boolean inetAddressConflict(InetAddress testAddress, InetAddress filterAddress, InetAddress testMask,
+ InetAddress filterMask) {
+ // Sanity check
+ if ((testAddress == null) || (filterAddress == null)) {
+ return false;
+ }
+
+ // Presence check
+ if (isAny(testAddress) || isAny(filterAddress)) {
+ return false;
+ }
+
+ int testMaskLen = (testMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+ .getSubnetMaskLength(testMask);
+ int filterMaskLen = (filterMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+ .getSubnetMaskLength(filterMask);
+
+ // Mask length check. Test mask has to be more specific than filter one
+ if (testMaskLen < filterMaskLen) {
+ return true;
+ }
+
+ // Subnet Prefix on filter mask length must be the same
+ InetAddress prefix1 = getSubnetPrefix(testAddress, filterMaskLen);
+ InetAddress prefix2 = getSubnetPrefix(filterAddress, filterMaskLen);
+ return (!prefix1.equals(prefix2));
+ }
+
+ /**
+ * Returns true if the passed MAC address is all zero
+ *
+ * @param mac
+ * the byte array representing the MAC address
+ * @return true if all MAC bytes are zero
+ */
+ public static boolean isZeroMAC(byte[] mac) {
+ for (short i = 0; i < 6; i++) {
+ if (mac[i] != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if the MAC address is the broadcast MAC address and false
+ * otherwise.
+ *
+ * @param MACAddress
+ * @return
+ */
+ public static boolean isBroadcastMACAddr(byte[] MACAddress) {
+ if (MACAddress.length == MACAddrLengthInBytes) {
+ for (int i = 0; i < 6; i++) {
+ if (MACAddress[i] != BroadcastMACAddr[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return false;
+ }
+ /**
+ * Returns true if the MAC address is a unicast MAC address and false
+ * otherwise.
+ *
+ * @param MACAddress
+ * @return
+ */
+ public static boolean isUnicastMACAddr(byte[] MACAddress) {
+ if (MACAddress.length == MACAddrLengthInBytes) {
+ return (MACAddress[0] & 1) == 0;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the MAC address is a multicast MAC address and false
+ * otherwise. Note that this explicitly returns false for the broadcast MAC
+ * address.
+ *
+ * @param MACAddress
+ * @return
+ */
+ public static boolean isMulticastMACAddr(byte[] MACAddress) {
+ if (MACAddress.length == MACAddrLengthInBytes && !isBroadcastMACAddr(MACAddress)) {
+ return (MACAddress[0] & 1) != 0;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the passed InetAddress contains all zero
+ *
+ * @param ip
+ * the IP address to test
+ * @return true if the address is all zero
+ */
+ public static boolean isAny(InetAddress ip) {
+ for (byte b : ip.getAddress()) {
+ if (b != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean fieldsConflict(int field1, int field2) {
+ if ((field1 == 0) || (field2 == 0) || (field1 == field2)) {
+ return false;
+ }
+ return true;
+ }
+
+ public static InetAddress parseInetAddress(String addressString) {
+ InetAddress address = null;
+ try {
+ address = InetAddress.getByName(addressString);
+ } catch (UnknownHostException e) {
+ logger.error("", e);
+ }
+ return address;
+ }
+
+ /**
+ * Checks if the passed IP v4 address in string form is valid The address
+ * may specify a mask at the end as "/MM"
+ *
+ * @param cidr
+ * the v4 address as A.B.C.D/MM
+ * @return
+ */
+ public static boolean isIPv4AddressValid(String cidr) {
+ if (cidr == null) {
+ return false;
+ }
+
+ String values[] = cidr.split("/");
+ Pattern ipv4Pattern = Pattern
+ .compile("(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])");
+ Matcher mm = ipv4Pattern.matcher(values[0]);
+ if (!mm.matches()) {
+ return false;
+ }
+ if (values.length >= 2) {
+ int prefix = Integer.valueOf(values[1]);
+ if ((prefix < 0) || (prefix > 32)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the passed IP v6 address in string form is valid The address
+ * may specify a mask at the end as "/MMM"
+ *
+ * @param cidr
+ * the v6 address as A::1/MMM
+ * @return
+ */
+ public static boolean isIPv6AddressValid(String cidr) {
+ if (cidr == null) {
+ return false;
+ }
+
+ String values[] = cidr.split("/");
+ try {
+ // when given an IP address, InetAddress.getByName validates the ip
+ // address
+ InetAddress addr = InetAddress.getByName(values[0]);
+ if (!(addr instanceof Inet6Address)) {
+ return false;
+ }
+ } catch (UnknownHostException ex) {
+ return false;
+ }
+
+ if (values.length >= 2) {
+ int prefix = Integer.valueOf(values[1]);
+ if ((prefix < 0) || (prefix > 128)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the passed IP address in string form is a valid v4 or v6
+ * address. The address may specify a mask at the end as "/MMM"
+ *
+ * @param cidr
+ * the v4 or v6 address as IP/MMM
+ * @return
+ */
+ public static boolean isIPAddressValid(String cidr) {
+ return NetUtils.isIPv4AddressValid(cidr) || NetUtils.isIPv6AddressValid(cidr);
+ }
+
+ /*
+ * Following utilities are useful when you need to compare or bit shift java
+ * primitive type variable which are inherently signed
+ */
+ /**
+ * Returns the unsigned value of the passed byte variable
+ *
+ * @param b
+ * the byte value
+ * @return the int variable containing the unsigned byte value
+ */
+ public static int getUnsignedByte(byte b) {
+ return b & 0xFF;
+ }
+
+ /**
+ * Return the unsigned value of the passed short variable
+ *
+ * @param s
+ * the short value
+ * @return the int variable containing the unsigned short value
+ */
+ public static int getUnsignedShort(short s) {
+ return s & 0xFFFF;
+ }
+
+ /**
+ * Returns the highest v4 or v6 InetAddress
+ *
+ * @param v6
+ * true for IPv6, false for Ipv4
+ * @return The highest IPv4 or IPv6 address
+ */
+ public static InetAddress gethighestIP(boolean v6) {
+ try {
+ return (v6) ? InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") : InetAddress
+ .getByName("255.255.255.255");
+ } catch (UnknownHostException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns Broadcast MAC Address
+ *
+ * @return the byte array containing broadcast mac address
+ */
+ public static byte[] getBroadcastMACAddr() {
+ return Arrays.copyOf(BroadcastMACAddr, BroadcastMACAddr.length);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract class which represents the generic network packet object It provides
+ * the basic methods which are common for all the packets, like serialize and
+ * deserialize
+ */
+
+public abstract class Packet {
+ protected static final Logger logger = LoggerFactory
+ .getLogger(Packet.class);
+ // Access level granted to this packet
+ protected boolean writeAccess;
+ // When deserialized from wire, packet could result corrupted
+ protected boolean corrupted;
+ // The packet that encapsulate this packet
+ protected Packet parent;
+ // The packet encapsulated by this packet
+ protected Packet payload;
+ // The unparsed raw payload carried by this packet
+ protected byte[] rawPayload;
+ // Bit coordinates of packet header fields
+ protected Map<String, Pair<Integer, Integer>> hdrFieldCoordMap;
+ // Header fields values: Map<FieldName,Value>
+ protected Map<String, byte[]> hdrFieldsMap;
+ // The class of the encapsulated packet object
+ protected Class<? extends Packet> payloadClass;
+
+ public Packet() {
+ writeAccess = false;
+ corrupted = false;
+ }
+
+ public Packet(boolean writeAccess) {
+ this.writeAccess = writeAccess;
+ corrupted = false;
+ }
+
+ public Packet getParent() {
+ return parent;
+ }
+
+ public Packet getPayload() {
+ return payload;
+ }
+
+ public void setParent(Packet parent) {
+ this.parent = parent;
+ }
+
+ public void setPayload(Packet payload) {
+ this.payload = payload;
+ }
+
+ public void setHeaderField(String headerField, byte[] readValue) {
+ hdrFieldsMap.put(headerField, readValue);
+ }
+
+ /**
+ * This method deserializes the data bits obtained from the wire into the
+ * respective header and payload which are of type Packet
+ *
+ * @param byte[] data - data from wire to deserialize
+ * @param int bitOffset bit position where packet header starts in data
+ * array
+ * @param int size of packet in bits
+ * @return Packet
+ * @throws PacketException
+ */
+ public Packet deserialize(byte[] data, int bitOffset, int size)
+ throws PacketException {
+
+ // Deserialize the header fields one by one
+ int startOffset = 0, numBits = 0;
+ for (Entry<String, Pair<Integer, Integer>> pairs : hdrFieldCoordMap
+ .entrySet()) {
+ String hdrField = pairs.getKey();
+ startOffset = bitOffset + this.getfieldOffset(hdrField);
+ numBits = this.getfieldnumBits(hdrField);
+
+ byte[] hdrFieldBytes = null;
+ try {
+ hdrFieldBytes = BitBufferHelper.getBits(data, startOffset,
+ numBits);
+ } catch (BufferException e) {
+ throw new PacketException(e.getMessage());
+ }
+
+ /*
+ * Store the raw read value, checks the payload type and set the
+ * payloadClass accordingly
+ */
+ this.setHeaderField(hdrField, hdrFieldBytes);
+
+ if (logger.isTraceEnabled()) {
+ logger.trace("{}: {}: {} (offset {} bitsize {})",
+ new Object[] { this.getClass().getSimpleName(), hdrField,
+ HexEncode.bytesToHexString(hdrFieldBytes),
+ startOffset, numBits });
+ }
+ }
+
+ // Deserialize the payload now
+ int payloadStart = startOffset + numBits;
+ int payloadSize = data.length * NetUtils.NumBitsInAByte - payloadStart;
+
+ if (payloadClass != null) {
+ try {
+ payload = payloadClass.newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Error parsing payload for Ethernet packet", e);
+ }
+ payload.deserialize(data, payloadStart, payloadSize);
+ payload.setParent(this);
+ } else {
+ /*
+ * The payload class was not set, it means no class for parsing
+ * this payload is present. Let's store the raw payload if any.
+ */
+ int start = payloadStart / NetUtils.NumBitsInAByte;
+ int stop = start + payloadSize / NetUtils.NumBitsInAByte;
+ rawPayload = Arrays.copyOfRange(data, start, stop);
+ }
+
+
+ // Take care of computation that can be done only after deserialization
+ postDeserializeCustomOperation(data, payloadStart - getHeaderSize());
+
+ return this;
+ }
+
+ /**
+ * This method serializes the header and payload from the respective
+ * packet class, into a single stream of bytes to be sent on the wire
+ *
+ * @return The byte array representing the serialized Packet
+ * @throws PacketException
+ */
+ public byte[] serialize() throws PacketException {
+
+ // Acquire or compute the serialized payload
+ byte[] payloadBytes = null;
+ if (payload != null) {
+ payloadBytes = payload.serialize();
+ } else if (rawPayload != null) {
+ payloadBytes = rawPayload;
+ }
+ int payloadSize = (payloadBytes == null) ? 0 : payloadBytes.length;
+
+ // Allocate the buffer to contain the full (header + payload) packet
+ int headerSize = this.getHeaderSize() / NetUtils.NumBitsInAByte;
+ byte packetBytes[] = new byte[headerSize + payloadSize];
+ if (payloadBytes != null) {
+ System.arraycopy(payloadBytes, 0, packetBytes, headerSize, payloadSize);
+ }
+
+ // Serialize this packet header, field by field
+ for (Map.Entry<String, Pair<Integer, Integer>> pairs : hdrFieldCoordMap
+ .entrySet()) {
+ String field = pairs.getKey();
+ byte[] fieldBytes = hdrFieldsMap.get(field);
+ // Let's skip optional fields when not set
+ if (fieldBytes != null) {
+ try {
+ BitBufferHelper.setBytes(packetBytes, fieldBytes,
+ getfieldOffset(field), getfieldnumBits(field));
+ } catch (BufferException e) {
+ throw new PacketException(e.getMessage());
+ }
+ }
+ }
+
+ // Perform post serialize operations (like checksum computation)
+ postSerializeCustomOperation(packetBytes);
+
+ if (logger.isTraceEnabled()) {
+ logger.trace("{}: {}", this.getClass().getSimpleName(),
+ HexEncode.bytesToHexString(packetBytes));
+ }
+
+ return packetBytes;
+ }
+
+ /**
+ * This method gets called at the end of the serialization process It is
+ * intended for the child packets to insert some custom data into the output
+ * byte stream which cannot be done or cannot be done efficiently during the
+ * normal Packet.serialize() path. An example is the checksum computation
+ * for IPv4
+ *
+ * @param byte[] - serialized bytes
+ * @throws PacketException
+ */
+ protected void postSerializeCustomOperation(byte[] myBytes)
+ throws PacketException {
+ // no op
+ }
+
+ /**
+ * This method re-computes the checksum of the bits received on the wire and
+ * validates it with the checksum in the bits received Since the computation
+ * of checksum varies based on the protocol, this method is overridden.
+ * Currently only IPv4 and ICMP do checksum computation and validation. TCP
+ * and UDP need to implement these if required.
+ *
+ * @param byte[] data The byte stream representing the Ethernet frame
+ * @param int startBitOffset The bit offset from where the byte array corresponding to this Packet starts in the frame
+ * @throws PacketException
+ */
+ protected void postDeserializeCustomOperation(byte[] data, int startBitOffset)
+ throws PacketException {
+ // no op
+ }
+
+ /**
+ * Gets the header length in bits
+ *
+ * @return int the header length in bits
+ */
+ public int getHeaderSize() {
+ int size = 0;
+ /*
+ * We need to iterate over the fields that were read in the frame
+ * (hdrFieldsMap) not all the possible ones described in
+ * hdrFieldCoordMap. For ex, 802.1Q may or may not be there
+ */
+ for (Map.Entry<String, byte[]> fieldEntry : hdrFieldsMap.entrySet()) {
+ if (fieldEntry.getValue() != null) {
+ String field = fieldEntry.getKey();
+ size += getfieldnumBits(field);
+ }
+ }
+ return size;
+ }
+
+ /**
+ * This method fetches the start bit offset for header field specified by
+ * 'fieldname'. The offset is present in the hdrFieldCoordMap of the
+ * respective packet class
+ *
+ * @param String
+ * fieldName
+ * @return Integer - startOffset of the requested field
+ */
+ public int getfieldOffset(String fieldName) {
+ return hdrFieldCoordMap.get(fieldName).getLeft();
+ }
+
+ /**
+ * This method fetches the number of bits for header field specified by
+ * 'fieldname'. The numBits are present in the hdrFieldCoordMap of the
+ * respective packet class
+ *
+ * @param String
+ * fieldName
+ * @return Integer - number of bits of the requested field
+ */
+ public int getfieldnumBits(String fieldName) {
+ return hdrFieldCoordMap.get(fieldName).getRight();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder ret = new StringBuilder();
+ ret.append(this.getClass().getSimpleName());
+ ret.append(": [");
+ for (String field : hdrFieldCoordMap.keySet()) {
+ byte[] value = hdrFieldsMap.get(field);
+ ret.append(field);
+ ret.append(": ");
+ ret.append(HexEncode.bytesToHexString(value));
+ ret.append(", ");
+ }
+ ret.replace(ret.length()-2, ret.length()-1, "]");
+ return ret.toString();
+ }
+
+ /**
+ * Returns the raw payload carried by this packet in case payload was not
+ * parsed. Caller can call this function in case the getPaylod() returns null.
+ *
+ * @return The raw payload if not parsable as an array of bytes, null otherwise
+ */
+ public byte[] getRawPayload() {
+ return rawPayload;
+ }
+
+ /**
+ * Set a raw payload in the packet class
+ *
+ * @param payload The raw payload as byte array
+ */
+ public void setRawPayload(byte[] payload) {
+ this.rawPayload = Arrays.copyOf(payload, payload.length);
+ }
+
+ /**
+ * Return whether the deserialized packet is to be considered corrupted.
+ * This is the case when the checksum computed after reconstructing the
+ * packet received from wire is not equal to the checksum read from the
+ * stream. For the Packet class which do not have a checksum field, this
+ * function will always return false.
+ *
+ *
+ * @return true if the deserialized packet's recomputed checksum is not
+ * equal to the packet carried checksum
+ */
+ public boolean isCorrupted() {
+ return corrupted;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result
+ + ((this.hdrFieldsMap == null) ? 0 : hdrFieldsMap.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Packet other = (Packet) obj;
+ if (hdrFieldsMap == other.hdrFieldsMap) {
+ return true;
+ }
+ if (hdrFieldsMap == null || other.hdrFieldsMap == null) {
+ return false;
+ }
+ if (hdrFieldsMap != null && other.hdrFieldsMap != null) {
+ for (String field : hdrFieldsMap.keySet()) {
+ if (!Arrays.equals(hdrFieldsMap.get(field), other.hdrFieldsMap.get(field))) {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ return true;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.liblldp;
+
+/**
+ * Describes an exception that is raised when the process of serializing or
+ * deserializing a network packet/stream fails. This generally happens when the
+ * packet/stream is malformed.
+ *
+ */
+public class PacketException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public PacketException(String message) {
+ super(message);
+ }
+}
--- /dev/null
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.packet;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.opendaylight.controller.liblldp.BitBufferHelper;
+
+public class BitBufferHelperTest {
+
+ @Test
+ public void testGetByte() {
+ byte[] data = { 100 };
+ Assert.assertTrue(BitBufferHelper.getByte(data) == 100);
+ }
+
+ @Test
+ public void testGetBits() throws Exception {
+ byte[] data = { 10, 12, 14, 20, 55, 69, 82, 97, 109, 117, 127, -50 };
+ byte[] bits;
+
+ bits = BitBufferHelper.getBits(data, 88, 8); //BYTE extraOffsetBits = extranumBits = 0
+ Assert.assertTrue(bits[0] == -50);
+
+ bits = BitBufferHelper.getBits(data, 8, 16); //Short
+ Assert.assertTrue(bits[0] == 12);
+ Assert.assertTrue(bits[1] == 14);
+
+ bits = BitBufferHelper.getBits(data, 32, 32); //Int
+ Assert.assertTrue(bits[0] == 55);
+ Assert.assertTrue(bits[1] == 69);
+ Assert.assertTrue(bits[2] == 82);
+ Assert.assertTrue(bits[3] == 97);
+
+ bits = BitBufferHelper.getBits(data, 16, 48); //Long
+ Assert.assertTrue(bits[0] == 14);
+ Assert.assertTrue(bits[1] == 20);
+ Assert.assertTrue(bits[2] == 55);
+ Assert.assertTrue(bits[3] == 69);
+ Assert.assertTrue(bits[4] == 82);
+ Assert.assertTrue(bits[5] == 97);
+
+ bits = BitBufferHelper.getBits(data, 40, 7); //BYTE extraOffsetBits = extranumBits != 0
+ Assert.assertTrue(bits[0] == 34);
+
+ bits = BitBufferHelper.getBits(data, 8, 13); //Short
+ Assert.assertTrue(bits[0] == 1);
+ Assert.assertTrue(bits[1] == -127);
+
+ bits = BitBufferHelper.getBits(data, 32, 28); //Int
+ Assert.assertTrue(bits[0] == 3);
+ Assert.assertTrue(bits[1] == 116);
+ Assert.assertTrue(bits[2] == 85);
+ Assert.assertTrue(bits[3] == 38);
+
+ bits = BitBufferHelper.getBits(data, 16, 41); //Long
+ Assert.assertTrue(bits[0] == 0);
+ Assert.assertTrue(bits[1] == 28);
+ Assert.assertTrue(bits[2] == 40);
+ Assert.assertTrue(bits[3] == 110);
+ Assert.assertTrue(bits[4] == -118);
+ Assert.assertTrue(bits[5] == -92);
+
+ bits = BitBufferHelper.getBits(data, 3, 7); //BYTE extraOffsetBits != 0; extranumBits == 0
+ Assert.assertTrue(bits[0] == 40);
+
+ bits = BitBufferHelper.getBits(data, 13, 16); //Short
+ Assert.assertTrue(bits[0] == -127);
+ Assert.assertTrue(bits[1] == -62);
+
+ bits = BitBufferHelper.getBits(data, 5, 32); //Int
+ Assert.assertTrue(bits[0] == 65);
+ Assert.assertTrue(bits[1] == -127);
+ Assert.assertTrue(bits[2] == -62);
+ Assert.assertTrue(bits[3] == -122);
+
+ bits = BitBufferHelper.getBits(data, 23, 48); //Long
+ Assert.assertTrue(bits[0] == 10);
+ Assert.assertTrue(bits[1] == 27);
+ Assert.assertTrue(bits[2] == -94);
+ Assert.assertTrue(bits[3] == -87);
+ Assert.assertTrue(bits[4] == 48);
+ Assert.assertTrue(bits[5] == -74);
+
+ bits = BitBufferHelper.getBits(data, 66, 9); //BYTE extraOffsetBits != 0; extranumBits != 0
+ Assert.assertTrue(bits[0] == 1);
+ Assert.assertTrue(bits[1] == 107);
+
+ bits = BitBufferHelper.getBits(data, 13, 15); //Short
+ Assert.assertTrue(bits[0] == 64);
+ Assert.assertTrue(bits[1] == -31);
+
+ bits = BitBufferHelper.getBits(data, 5, 29); //Int
+ Assert.assertTrue(bits[0] == 8);
+ Assert.assertTrue(bits[1] == 48);
+ Assert.assertTrue(bits[2] == 56);
+ Assert.assertTrue(bits[3] == 80);
+
+ bits = BitBufferHelper.getBits(data, 31, 43); //Long
+ Assert.assertTrue(bits[0] == 0);
+ Assert.assertTrue(bits[1] == -35);
+ Assert.assertTrue(bits[2] == 21);
+ Assert.assertTrue(bits[3] == 73);
+ Assert.assertTrue(bits[4] == -123);
+ Assert.assertTrue(bits[5] == -75);
+
+ bits = BitBufferHelper.getBits(data, 4, 12); //Short
+ Assert.assertTrue(bits[0] == 10);
+ Assert.assertTrue(bits[1] == 12);
+
+ byte[] data1 = { 0, 8 };
+ bits = BitBufferHelper.getBits(data1, 7, 9); //Short
+ Assert.assertTrue(bits[0] == 0);
+ Assert.assertTrue(bits[1] == 8);
+
+ byte[] data2 = { 2, 8 };
+ bits = BitBufferHelper.getBits(data2, 0, 7); //Short
+ Assert.assertTrue(bits[0] == 1);
+
+ bits = BitBufferHelper.getBits(data2, 7, 9); //Short
+ Assert.assertTrue(bits[0] == 0);
+ Assert.assertTrue(bits[1] == 8);
+ }
+
+ // [01101100][01100000]
+ // [01100011]
+ @Test
+ public void testGetBytes() throws Exception {
+ byte data[] = { 108, 96, 125, -112, 5, 6, 108, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22 };
+ byte[] x;
+
+ Assert.assertTrue(BitBufferHelper.getBits(data, 0, 8)[0] == 108);
+ Assert.assertTrue(BitBufferHelper.getBits(data, 8, 8)[0] == 96);
+
+ x = BitBufferHelper.getBits(data, 0, 10);
+ Assert.assertTrue(x[0] == 1);
+ Assert.assertTrue(x[1] == -79);
+
+ x = BitBufferHelper.getBits(data, 3, 8);
+ Assert.assertTrue(x[0] == 99);
+ //Assert.assertTrue(x[1] == 97);
+
+ }
+
+ @Test
+ public void testMSBMask() {
+ int numBits = 1; //MSB
+ int mask = BitBufferHelper.getMSBMask(numBits);
+ Assert.assertTrue(mask == 128);
+
+ numBits = 8;
+ mask = BitBufferHelper.getMSBMask(numBits);
+ Assert.assertTrue(mask == 255);
+
+ numBits = 2;
+ mask = BitBufferHelper.getMSBMask(numBits);
+ Assert.assertTrue(mask == 192);
+ }
+
+ @Test
+ public void testLSBMask() {
+ int numBits = 1; //LSB
+ int mask = BitBufferHelper.getLSBMask(numBits);
+ Assert.assertTrue(mask == 1);
+
+ numBits = 3;
+ mask = BitBufferHelper.getLSBMask(numBits);
+ Assert.assertTrue(mask == 7);
+
+ numBits = 8;
+ mask = BitBufferHelper.getLSBMask(numBits);
+ Assert.assertTrue(mask == 255);
+ }
+
+ @Test
+ public void testToByteArray() {
+ short sh = Short.MAX_VALUE;
+ byte[] data_sh = new byte[Byte.SIZE / 8];
+ data_sh = BitBufferHelper.toByteArray(sh);
+ Assert.assertTrue(data_sh[0] == 127);
+ Assert.assertTrue(data_sh[1] == -1);
+
+ short sh2 = Short.MIN_VALUE;
+ byte[] data_sh2 = new byte[Byte.SIZE / 8];
+ data_sh2 = BitBufferHelper.toByteArray(sh2);
+ Assert.assertTrue(data_sh2[0] == -128);
+ Assert.assertTrue(data_sh2[1] == 0);
+
+ short sh3 = 16384;
+ byte[] data_sh3 = new byte[Byte.SIZE / 8];
+ data_sh3 = BitBufferHelper.toByteArray(sh3);
+ Assert.assertTrue(data_sh3[0] == 64);
+ Assert.assertTrue(data_sh3[1] == 0);
+
+ short sh4 = 146; //TCP headerlenflags - startoffset = 103
+ byte[] data_sh4 = new byte[Byte.SIZE / 8];
+ data_sh4 = BitBufferHelper.toByteArray(sh4);
+ Assert.assertTrue(data_sh4[0] == 0);
+ Assert.assertTrue(data_sh4[1] == -110);
+
+ short sh4_2 = 5000; //IPv4 Offset - startOffset = 51 (to 63)
+ byte[] data_sh4_2 = new byte[Byte.SIZE / 8];
+ data_sh4_2 = BitBufferHelper.toByteArray(sh4_2);
+ Assert.assertTrue(data_sh4_2[0] == 19);
+ Assert.assertTrue(data_sh4_2[1] == -120);
+
+ short sh4_3 = 5312; //numEndRestBits < numBitstoShiftBy
+ byte[] data_sh4_3 = new byte[Byte.SIZE / 8];
+ data_sh4_3 = BitBufferHelper.toByteArray(sh4_3);
+ Assert.assertTrue(data_sh4_3[0] == 20);
+ Assert.assertTrue(data_sh4_3[1] == -64);
+
+ int Int = Integer.MAX_VALUE;
+ byte[] data_Int = new byte[Integer.SIZE / 8];
+ data_Int = BitBufferHelper.toByteArray(Int);
+ Assert.assertTrue(data_Int[0] == 127);
+ Assert.assertTrue(data_Int[1] == -1);
+ Assert.assertTrue(data_Int[2] == -1);
+ Assert.assertTrue(data_Int[3] == -1);
+
+ int Int2 = Integer.MIN_VALUE;
+ byte[] data_Int2 = new byte[Integer.SIZE / 8];
+ data_Int2 = BitBufferHelper.toByteArray(Int2);
+ Assert.assertTrue(data_Int2[0] == -128);
+ Assert.assertTrue(data_Int2[1] == 0);
+ Assert.assertTrue(data_Int2[2] == 0);
+ Assert.assertTrue(data_Int2[3] == 0);
+
+ int Int3 = 1077952576;
+ byte[] data_Int3 = new byte[Integer.SIZE / 8];
+ data_Int3 = BitBufferHelper.toByteArray(Int3);
+ Assert.assertTrue(data_Int3[0] == 64);
+ Assert.assertTrue(data_Int3[1] == 64);
+ Assert.assertTrue(data_Int3[2] == 64);
+ Assert.assertTrue(data_Int3[3] == 64);
+
+ long Lng = Long.MAX_VALUE;
+ byte[] data_lng = new byte[Long.SIZE / 8];
+ data_lng = BitBufferHelper.toByteArray(Lng);
+ Assert.assertTrue(data_lng[0] == 127);
+ Assert.assertTrue(data_lng[1] == -1);
+ Assert.assertTrue(data_lng[2] == -1);
+ Assert.assertTrue(data_lng[3] == -1);
+ Assert.assertTrue(data_lng[4] == -1);
+ Assert.assertTrue(data_lng[5] == -1);
+ Assert.assertTrue(data_lng[6] == -1);
+ Assert.assertTrue(data_lng[7] == -1);
+
+ long Lng2 = Long.MIN_VALUE;
+ byte[] data_lng2 = new byte[Long.SIZE / 8];
+ data_lng2 = BitBufferHelper.toByteArray(Lng2);
+ Assert.assertTrue(data_lng2[0] == -128);
+ Assert.assertTrue(data_lng2[1] == 0);
+ Assert.assertTrue(data_lng2[2] == 0);
+ Assert.assertTrue(data_lng2[3] == 0);
+ Assert.assertTrue(data_lng2[4] == 0);
+ Assert.assertTrue(data_lng2[5] == 0);
+ Assert.assertTrue(data_lng2[6] == 0);
+ Assert.assertTrue(data_lng2[7] == 0);
+
+ byte B = Byte.MAX_VALUE;
+ byte[] data_B = new byte[Byte.SIZE / 8];
+ data_B = BitBufferHelper.toByteArray(B);
+ Assert.assertTrue(data_B[0] == 127);
+
+ byte B1 = Byte.MIN_VALUE;
+ byte[] data_B1 = new byte[Byte.SIZE / 8];
+ data_B1 = BitBufferHelper.toByteArray(B1);
+ Assert.assertTrue(data_B1[0] == -128);
+
+ byte B2 = 64;
+ byte[] data_B2 = new byte[Byte.SIZE / 8];
+ data_B2 = BitBufferHelper.toByteArray(B2);
+ Assert.assertTrue(data_B2[0] == 64);
+
+ byte B3 = 32;
+ byte[] data_B3 = new byte[Byte.SIZE / 8];
+ data_B3 = BitBufferHelper.toByteArray(B3);
+ Assert.assertTrue(data_B3[0] == 32);
+
+ }
+
+ @Test
+ public void testToByteArrayVariable() {
+ int len = 9;
+ byte[] data_sh;
+ data_sh = BitBufferHelper.toByteArray(511, len);
+ Assert.assertTrue(data_sh[0] == (byte) 255);
+ Assert.assertTrue(data_sh[1] == (byte) 128);
+
+ data_sh = BitBufferHelper.toByteArray((int) 511, len);
+ Assert.assertTrue(data_sh[0] == (byte) 255);
+ Assert.assertTrue(data_sh[1] == (byte) 128);
+
+ data_sh = BitBufferHelper.toByteArray((long) 511, len);
+ Assert.assertTrue(data_sh[0] == (byte) 255);
+ Assert.assertTrue(data_sh[1] == (byte) 128);
+ }
+
+ @Test
+ public void testToInt() {
+ byte data[] = { 1 };
+ Assert.assertTrue(BitBufferHelper.toNumber(data) == 1);
+
+ byte data2[] = { 1, 1 };
+ Assert.assertTrue(BitBufferHelper.toNumber(data2) == 257);
+
+ byte data3[] = { 1, 1, 1 };
+ Assert.assertTrue(BitBufferHelper.toNumber(data3) == 65793);
+ }
+
+ @Test
+ public void testToLongGetter() {
+ byte data[] = { 1, 1 };
+ Assert.assertTrue(BitBufferHelper.getLong(data) == 257L);
+ }
+
+ @Test
+ public void testSetByte() throws Exception {
+ byte input;
+ byte[] data = new byte[20];
+
+ input = 125;
+ BitBufferHelper.setByte(data, input, 0, Byte.SIZE);
+ Assert.assertTrue(data[0] == 125);
+
+ input = 109;
+ BitBufferHelper.setByte(data, input, 152, Byte.SIZE);
+ Assert.assertTrue(data[19] == 109);
+ }
+
+ @Test
+ public void testSetBytes() throws Exception {
+ byte[] input = { 0, 1 };
+ byte[] data = { 6, 0 };
+
+ BitBufferHelper.setBytes(data, input, 7, 9);
+ Assert.assertTrue(data[0] == 6);
+ Assert.assertTrue(data[1] == 1);
+ }
+
+ //@Test
+ //INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]*/
+ public void testInsertBits() throws Exception {
+ //CASE 1: startOffset%8 == 0 && numBits%8 == 0
+ byte inputdata[] = { 75, 110, 107, 80, 10, 12, 35, 100, 125, 65 };
+ int startOffset = 0;
+ int numBits = 8;
+
+ byte data1[] = new byte[2];
+ startOffset = 0;
+ numBits = 16;
+ BitBufferHelper.insertBits(data1, inputdata, startOffset, numBits);
+ Assert.assertTrue(data1[0] == 75);
+ Assert.assertTrue(data1[1] == 110);
+
+ byte data2[] = new byte[4];
+ startOffset = 0;
+ numBits = 32;
+ BitBufferHelper.insertBits(data2, inputdata, startOffset, numBits);
+ Assert.assertTrue(data2[0] == 75);
+ Assert.assertTrue(data2[1] == 110);
+ Assert.assertTrue(data2[2] == 107);
+ Assert.assertTrue(data2[3] == 80);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] // OUTPUT: [01001011] [01101000] = {75, 104}
+ byte data10[] = new byte[2];
+ startOffset = 0;
+ numBits = 13;
+ BitBufferHelper.insertBits(data10, inputdata, startOffset, numBits);
+ Assert.assertTrue(data10[0] == 75);
+ Assert.assertTrue(data10[1] == 104);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] // OUTPUT: [01001000] = {72}
+ byte data11[] = new byte[4];
+ startOffset = 8;
+ numBits = 6;
+ BitBufferHelper.insertBits(data11, inputdata, startOffset, numBits);
+ Assert.assertTrue(data11[1] == 72);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [01001011] [01101110] [01101000] = {75, 110, 105}
+ byte data12[] = new byte[4];
+ startOffset = 0;
+ numBits = 23;
+ BitBufferHelper.insertBits(data12, inputdata, startOffset, numBits);
+ Assert.assertTrue(data12[0] == 75);
+ Assert.assertTrue(data12[1] == 110);
+ Assert.assertTrue(data12[2] == 106);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [01001011] [01101110] [01100000] = {75, 110, 96}
+ byte data13[] = new byte[4];
+ startOffset = 8;
+ numBits = 20;
+ BitBufferHelper.insertBits(data13, inputdata, startOffset, numBits);
+ Assert.assertTrue(data13[1] == 75);
+ Assert.assertTrue(data13[2] == 110);
+ Assert.assertTrue(data13[3] == 96);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [01001011] [01101110] [01101011] [10100000]= {75, 110, 107, 80}
+ byte data14[] = new byte[4];
+ startOffset = 0;
+ numBits = 30;
+ BitBufferHelper.insertBits(data14, inputdata, startOffset, numBits);
+ Assert.assertTrue(data14[0] == 75);
+ Assert.assertTrue(data14[1] == 110);
+ Assert.assertTrue(data14[2] == 107);
+ Assert.assertTrue(data14[3] == 80);
+
+ //CASE 3: startOffset%8 != 0, numBits%8 = 0
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00001001] [11000000] = {72, 96}
+ byte data16[] = new byte[5];
+ startOffset = 3;
+ numBits = 8;
+ BitBufferHelper.insertBits(data16, inputdata, startOffset, numBits);
+ Assert.assertTrue(data16[0] == 9);
+ Assert.assertTrue(data16[1] == 96);
+ Assert.assertTrue(data16[2] == 0);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+ // OUTPUT: [00000100] [1011 0110] [1110 0000] = {4, -54, -96}
+
+ startOffset = 3;
+ numBits = 16;
+ byte data17[] = new byte[5];
+ BitBufferHelper.insertBits(data17, inputdata, startOffset, numBits);
+ Assert.assertTrue(data17[0] == 9);
+ Assert.assertTrue(data17[1] == 109);
+ Assert.assertTrue(data17[2] == -64);
+ Assert.assertTrue(data17[3] == 0);
+
+ // INPUT: {79, 110, 111}
+ // = [01001111] [01101110] [01101111]
+ //OUTPUT: [0000 1001] [1110 1101] [110 00000] = {9, -19, -64}
+ byte data18[] = new byte[5];
+ byte inputdata3[] = { 79, 110, 111 };
+ startOffset = 3;
+ numBits = 16;
+ BitBufferHelper.insertBits(data18, inputdata3, startOffset, numBits);
+ Assert.assertTrue(data18[0] == 9);
+ Assert.assertTrue(data18[1] == -19);
+ Assert.assertTrue(data18[2] == -64);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+ // OUTPUT: [0000 1001] [0110 1101] [1100 1101] [0110 1010] [0000 0001] = {9, 109, -51, 106, 0}
+
+ startOffset = 3;
+ numBits = 32;
+ byte data19[] = new byte[5];
+ BitBufferHelper.insertBits(data19, inputdata, startOffset, numBits);
+ Assert.assertTrue(data19[0] == 9);
+ Assert.assertTrue(data19[1] == 109);
+ Assert.assertTrue(data19[2] == -51);
+ Assert.assertTrue(data19[3] == 106);
+ Assert.assertTrue(data19[4] == 0);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+ // OUTPUT: data[4, 5, 6] = [0 010 0101] [1 011 0111] [0 000 0000] = {37, -73, 0}
+ startOffset = 33;
+ numBits = 16;
+ byte data20[] = new byte[7];
+ BitBufferHelper.insertBits(data20, inputdata, startOffset, numBits);
+ Assert.assertTrue(data20[4] == 37);
+ Assert.assertTrue(data20[5] == -73);
+ Assert.assertTrue(data20[6] == 0);
+
+ //CASE 4: extranumBits != 0 AND extraOffsetBits != 0
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+ // OUTPUT: [0000 1001] [0100 0000] = {9, 96}
+ startOffset = 3;
+ numBits = 7;
+ byte data21[] = new byte[7];
+ BitBufferHelper.insertBits(data21, inputdata, startOffset, numBits);
+ Assert.assertTrue(data21[0] == 9);
+ Assert.assertTrue(data21[1] == 64);
+ Assert.assertTrue(data21[2] == 0);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+ // OUTPUT: data = [00000 010] [01011 011] [01110 000] = {37, -73, 0}
+ startOffset = 5;
+ numBits = 17;
+ byte data22[] = new byte[7];
+ BitBufferHelper.insertBits(data22, inputdata, startOffset, numBits);
+ Assert.assertTrue(data22[0] == 2);
+ Assert.assertTrue(data22[1] == 91);
+ Assert.assertTrue(data22[2] == 112);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+ // OUTPUT: [0000 1001] [0110 1101] [110 01101] [01 00000] = {9, 109, -51, 64}
+ startOffset = 3;
+ numBits = 23;
+ byte data23[] = new byte[7];
+ BitBufferHelper.insertBits(data23, inputdata, startOffset, numBits);
+ Assert.assertTrue(data23[0] == 9);
+ Assert.assertTrue(data23[1] == 109);
+ Assert.assertTrue(data23[2] == -51);
+ Assert.assertTrue(data23[3] == 64);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+ // OUTPUT: [0000 1001] [0110 1101] = {9, 109}
+ startOffset = 3;
+ numBits = 13;
+ byte data24[] = new byte[7];
+ BitBufferHelper.insertBits(data24, inputdata, startOffset, numBits);
+ Assert.assertTrue(data24[0] == 9);
+ Assert.assertTrue(data24[1] == 109);
+ Assert.assertTrue(data24[2] == 0);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+ // OUTPUT: [0000 0100] [1011 0110] [1110 0110] = {4, -74, -26}
+ startOffset = 4;
+ numBits = 20;
+ byte data25[] = new byte[7];
+ BitBufferHelper.insertBits(data25, inputdata, startOffset, numBits);
+ Assert.assertTrue(data25[0] == 4);
+ Assert.assertTrue(data25[1] == -74);
+ Assert.assertTrue(data25[2] == -26);
+ Assert.assertTrue(data25[3] == -0);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+ // OUTPUT: [0000 0010] [0101 1011] = {0, 2, 91, 0}
+ startOffset = 13;
+ numBits = 11;
+ byte data26[] = new byte[7];
+ BitBufferHelper.insertBits(data26, inputdata, startOffset, numBits);
+ Assert.assertTrue(data26[0] == 0);
+ Assert.assertTrue(data26[1] == 2);
+ Assert.assertTrue(data26[2] == 91);
+ Assert.assertTrue(data26[3] == 0);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+ // OUTPUT: [000 01001] [011 01101] [110 0 0000] = {9, 109, -64, 0}
+ startOffset = 3;
+ numBits = 17;
+ byte data27[] = new byte[7];
+ BitBufferHelper.insertBits(data27, inputdata, startOffset, numBits);
+ Assert.assertTrue(data27[0] == 9);
+ Assert.assertTrue(data27[1] == 109);
+ Assert.assertTrue(data27[2] == -64);
+ Assert.assertTrue(data27[3] == 0);
+
+ // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+ // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+ // OUTPUT: [00 000000] [00 000000] [00 010010] [11 011011] [10 011010] [11 010100] [0000 0000] = {0, 0, 18, -37,-102,-44,0}
+ startOffset = 18;
+ numBits = 34;
+ byte data28[] = new byte[7];
+ BitBufferHelper.insertBits(data28, inputdata, startOffset, numBits);
+ Assert.assertTrue(data28[0] == 0);
+ Assert.assertTrue(data28[1] == 0);
+ Assert.assertTrue(data28[2] == 18);
+ Assert.assertTrue(data28[3] == -37);
+ Assert.assertTrue(data28[4] == -102);
+ Assert.assertTrue(data28[5] == -44);
+ Assert.assertTrue(data28[6] == 0);
+
+ }
+
+ @Test
+ public void testGetShort() throws Exception {
+ byte data[] = new byte[2];
+ data[0] = 7;
+ data[1] = 8;
+ int length = 9; // num bits
+ Assert.assertTrue(BitBufferHelper.getShort(data, length) == 264);
+
+ data[0] = 6;
+ data[1] = 8;
+ short result = BitBufferHelper.getShort(data, length);
+ Assert.assertTrue(result == 8);
+
+ data[0] = 8;
+ data[1] = 47;
+ result = BitBufferHelper.getShort(data, length);
+ Assert.assertTrue(result == 47);
+
+ //[0000 0001] [0001 0100] [0110 0100]
+ byte[] data1 = new byte[2];
+ data1[0] = 1;
+ data1[1] = 20; //data1[2] = 100;
+ length = 15;
+ result = BitBufferHelper.getShort(data1, length);
+ Assert.assertTrue(result == 276);
+
+ byte[] data2 = new byte[2];
+ data2[0] = 64;
+ data2[1] = 99; //data2[2] = 100;
+ length = 13;
+ result = BitBufferHelper.getShort(data2, length);
+ Assert.assertTrue(result == 99);
+
+ byte[] data3 = { 100, 50 };
+ result = BitBufferHelper.getShort(data3);
+ Assert.assertTrue(result == 25650);
+ }
+
+ @Test
+ public void testToIntVarLength() throws Exception {
+ byte data[] = { (byte) 255, (byte) 128 };
+ int length = 9; // num bits
+ Assert.assertTrue(BitBufferHelper.getInt(data, length) == 384);
+
+ byte data2[] = { 0, 8 };
+ Assert.assertTrue(BitBufferHelper.getInt(data2, 9) == 8);
+
+ byte data3[] = { 1, 1, 1 };
+ Assert.assertTrue(BitBufferHelper.getInt(data3) == 65793);
+
+ byte data4[] = { 1, 1, 1 };
+ Assert.assertTrue(BitBufferHelper.getInt(data4) == 65793);
+
+ byte data5[] = { 1, 1 };
+ Assert.assertTrue(BitBufferHelper.getInt(data5) == 257);
+
+ }
+
+ @Test
+ public void testShiftBitstoLSB() {
+ byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] data2 = { 8, 9, 10 };
+ byte[] shiftedBytes2 = BitBufferHelper.shiftBitsToLSB(data2, 11);
+
+ Assert.assertTrue(shiftedBytes2[0] == 0);
+ Assert.assertTrue(shiftedBytes2[1] == 64);
+ Assert.assertTrue(shiftedBytes2[2] == 72);
+
+ byte[] shiftedBytes = BitBufferHelper.shiftBitsToLSB(data, 49);
+
+ Assert.assertTrue(shiftedBytes[0] == 0);
+ Assert.assertTrue(shiftedBytes[1] == 2);
+ Assert.assertTrue(shiftedBytes[2] == 4);
+ Assert.assertTrue(shiftedBytes[3] == 6);
+ Assert.assertTrue(shiftedBytes[4] == 8);
+ Assert.assertTrue(shiftedBytes[5] == 10);
+ Assert.assertTrue(shiftedBytes[6] == 12);
+ Assert.assertTrue(shiftedBytes[7] == 14);
+ Assert.assertTrue(shiftedBytes[8] == 16);
+ Assert.assertTrue(shiftedBytes[9] == 18);
+
+ byte[] data1 = { 1, 2, 3 };
+ byte[] shiftedBytes1 = BitBufferHelper.shiftBitsToLSB(data1, 18);
+ Assert.assertTrue(shiftedBytes1[0] == 0);
+ Assert.assertTrue(shiftedBytes1[1] == 4);
+ Assert.assertTrue(shiftedBytes1[2] == 8);
+
+ }
+
+ @Test
+ public void testShiftBitstoLSBMSB() {
+ byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+ byte[] clone = BitBufferHelper.shiftBitsToMSB(BitBufferHelper
+ .shiftBitsToLSB(data, 72), 72);
+
+ Assert.assertTrue(clone[0] == 1);
+ Assert.assertTrue(clone[1] == 2);
+ Assert.assertTrue(clone[2] == 3);
+ Assert.assertTrue(clone[3] == 4);
+ Assert.assertTrue(clone[4] == 5);
+ Assert.assertTrue(clone[5] == 6);
+ Assert.assertTrue(clone[6] == 7);
+ Assert.assertTrue(clone[7] == 8);
+ Assert.assertTrue(clone[8] == 9);
+ Assert.assertTrue(clone[9] == 0);
+ }
+
+}
--- /dev/null
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+/**
+ * @file EthernetAddressTest.java
+ *
+ * @brief Unit Tests for EthernetAddress class
+ *
+ * Unit Tests for EthernetAddress class
+ */
+package org.opendaylight.controller.sal.packet.address;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.liblldp.ConstructionException;
+import org.opendaylight.controller.liblldp.EthernetAddress;
+
+public class EthernetAddressTest {
+ @Test
+ public void testNonValidConstructor() {
+ @SuppressWarnings("unused")
+ EthernetAddress ea1;
+ // Null input array
+ try {
+ ea1 = new EthernetAddress((byte[]) null);
+
+ // Exception is expected if NOT raised test will fail
+ Assert.assertTrue(false);
+ } catch (ConstructionException e) {
+ }
+
+ // Array too short
+ try {
+ ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0 });
+
+ // Exception is expected if NOT raised test will fail
+ Assert.assertTrue(false);
+ } catch (ConstructionException e) {
+ }
+
+ // Array too long
+ try {
+ ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+ (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
+ (byte) 0x0 });
+
+ // Exception is expected if NOT raised test will fail
+ Assert.assertTrue(false);
+ } catch (ConstructionException e) {
+ }
+ }
+
+ @Test
+ public void testEquality() {
+ EthernetAddress ea1;
+ EthernetAddress ea2;
+ try {
+ ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+ (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 });
+
+ ea2 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+ (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 });
+ Assert.assertTrue(ea1.equals(ea2));
+ } catch (ConstructionException e) {
+ // Exception is NOT expected if raised test will fail
+ Assert.assertTrue(false);
+ }
+
+ try {
+ ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+ (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 });
+
+ ea2 = ea1.clone();
+ Assert.assertTrue(ea1.equals(ea2));
+ } catch (ConstructionException e) {
+ // Exception is NOT expected if raised test will fail
+ Assert.assertTrue(false);
+ }
+
+ // Check for well knowns
+ try {
+ ea1 = EthernetAddress.BROADCASTMAC;
+ ea2 = new EthernetAddress(new byte[] { (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff });
+ Assert.assertTrue(ea1.equals(ea2));
+ } catch (ConstructionException e) {
+ // Exception is NOT expected if raised test will fail
+ Assert.assertTrue(false);
+ }
+ }
+
+ @Test
+ public void testUnEquality() {
+ EthernetAddress ea1;
+ EthernetAddress ea2;
+ try {
+ ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+ (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2 });
+
+ ea2 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+ (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 });
+ Assert.assertTrue(!ea1.equals(ea2));
+ } catch (ConstructionException e) {
+ // Exception is NOT expected if raised test will fail
+ Assert.assertTrue(false);
+ }
+ }
+}
<artifactId>karaf.branding</artifactId>
<version>${karaf.branding.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>liblldp</artifactId>
+ <version>${sal.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>logback-config</artifactId>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>topology-lldp-discovery</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>liblldp</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>topology-manager</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>sal</artifactId>
+ <artifactId>sal-binding-api</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-api</artifactId>
+ <artifactId>liblldp</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
import java.nio.charset.Charset;
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.LLDP;
-import org.opendaylight.controller.sal.packet.LLDPTLV;
-import org.opendaylight.controller.sal.utils.NetUtils;
+import org.opendaylight.controller.liblldp.Ethernet;
+import org.opendaylight.controller.liblldp.LLDP;
+import org.opendaylight.controller.liblldp.LLDPTLV;
+import org.opendaylight.controller.liblldp.NetUtils;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
<module>opendaylight/commons/parent</module>
<module>opendaylight/commons/logback_settings</module>
<module>opendaylight/commons/filter-valve</module>
+ <module>opendaylight/commons/liblldp</module>
<!-- Karaf Distribution -->
<module>opendaylight/dummy-console</module>