| /* |
| * Copyright 2016-present Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.onosproject.ospf.protocol.util; |
| |
| import org.onosproject.ospf.controller.OspfLsa; |
| import org.onosproject.ospf.controller.OspfLsaType; |
| import org.onosproject.ospf.protocol.lsa.types.AsbrSummaryLsa; |
| import org.onosproject.ospf.protocol.lsa.types.ExternalLsa; |
| import org.onosproject.ospf.protocol.lsa.types.NetworkLsa; |
| import org.onosproject.ospf.protocol.lsa.types.OpaqueLsa10; |
| import org.onosproject.ospf.protocol.lsa.types.OpaqueLsa11; |
| import org.onosproject.ospf.protocol.lsa.types.OpaqueLsa9; |
| import org.onosproject.ospf.protocol.lsa.types.RouterLsa; |
| import org.onosproject.ospf.protocol.lsa.types.SummaryLsa; |
| import org.onosproject.ospf.controller.OspfMessage; |
| import org.onosproject.ospf.protocol.ospfpacket.types.DdPacket; |
| import org.onosproject.ospf.protocol.ospfpacket.types.HelloPacket; |
| import org.onosproject.ospf.protocol.ospfpacket.types.LsAcknowledge; |
| import org.onosproject.ospf.protocol.ospfpacket.types.LsRequest; |
| import org.onosproject.ospf.protocol.ospfpacket.types.LsUpdate; |
| |
| import java.util.Arrays; |
| |
| /** |
| * Calculates checksum for different types of OSPF packets. |
| */ |
| public class ChecksumCalculator { |
| |
| /** |
| * Converts given string to sixteen bits integer. |
| * If hexasum is more than 16 bit value, needs to be reduced to 16 bit value. |
| * |
| * @param strToConvert hexasum value to convert |
| * @return 16 bit integer value |
| */ |
| public static int convertToSixteenBits(String strToConvert) { |
| StringBuilder sb = new StringBuilder(strToConvert); |
| sb = sb.reverse(); |
| StringBuilder s1 = new StringBuilder(sb.substring(0, 4)); |
| s1 = s1.reverse(); |
| StringBuilder s2 = new StringBuilder(sb.substring(4, sb.length())); |
| s2 = s2.reverse(); |
| int num = Integer.parseInt(s1.toString(), 16) + Integer.parseInt(s2.toString(), 16); |
| return num; |
| } |
| |
| /** |
| * Checks whether checksum is valid or not in the given OSPF message. |
| * |
| * @param ospfMessage ospf message instance |
| * @param checksumPos1 position of checksum bit in packet |
| * @param checksumPos2 position of checksum bit in packet |
| * @return true if valid else false |
| */ |
| public boolean isValidOspfCheckSum(OspfMessage ospfMessage, int checksumPos1, int checksumPos2) { |
| |
| switch (ospfMessage.ospfMessageType().value()) { |
| case OspfParameters.HELLO: |
| ospfMessage = (HelloPacket) ospfMessage; |
| break; |
| case OspfParameters.DD: |
| ospfMessage = (DdPacket) ospfMessage; |
| break; |
| case OspfParameters.LSREQUEST: |
| ospfMessage = (LsRequest) ospfMessage; |
| break; |
| case OspfParameters.LSUPDATE: |
| ospfMessage = (LsUpdate) ospfMessage; |
| break; |
| case OspfParameters.LSACK: |
| ospfMessage = (LsAcknowledge) ospfMessage; |
| break; |
| default: |
| break; |
| } |
| |
| byte[] messageAsBytes = ospfMessage.asBytes(); |
| return validateOspfCheckSum(messageAsBytes, checksumPos1, checksumPos2); |
| } |
| |
| /** |
| * Checks whether checksum is valid or not in the given OSPF LSA. |
| * |
| * @param ospfLsa lsa instance |
| * @param lsType lsa type |
| * @param lsaChecksumPos1 lsa checksum position in packet |
| * @param lsaChecksumPos2 lsa checksum position in packet |
| * @return true if valid else false |
| * @throws Exception might throw exception while processing |
| */ |
| public boolean isValidLsaCheckSum(OspfLsa ospfLsa, int lsType, int lsaChecksumPos1, |
| int lsaChecksumPos2) throws Exception { |
| if (lsType == OspfLsaType.ROUTER.value()) { |
| RouterLsa lsa = (RouterLsa) ospfLsa; |
| return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| } else if (lsType == OspfLsaType.NETWORK.value()) { |
| NetworkLsa lsa = (NetworkLsa) ospfLsa; |
| return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| } else if (lsType == OspfLsaType.SUMMARY.value()) { |
| SummaryLsa lsa = (SummaryLsa) ospfLsa; |
| return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| } else if (lsType == OspfLsaType.ASBR_SUMMARY.value()) { |
| AsbrSummaryLsa lsa = (AsbrSummaryLsa) ospfLsa; |
| return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| } else if (lsType == OspfLsaType.EXTERNAL_LSA.value()) { |
| ExternalLsa lsa = (ExternalLsa) ospfLsa; |
| return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| } else if (lsType == OspfLsaType.LINK_LOCAL_OPAQUE_LSA.value()) { |
| OpaqueLsa9 lsa = (OpaqueLsa9) ospfLsa; |
| return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| } else if (lsType == OspfLsaType.AREA_LOCAL_OPAQUE_LSA.value()) { |
| OpaqueLsa10 lsa = (OpaqueLsa10) ospfLsa; |
| return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| } else if (lsType == OspfLsaType.AS_OPAQUE_LSA.value()) { |
| OpaqueLsa11 lsa = (OpaqueLsa11) ospfLsa; |
| return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Verifies the checksum is valid in given LSA packet bytes. |
| * |
| * @param lsaPacket lsa as byte array |
| * @param lsaChecksumPos1 position of checksum bit in packet |
| * @param lsaChecksumPos2 position of checksum bit in packet |
| * @return true if valid else false |
| */ |
| public boolean validateLsaCheckSum(byte[] lsaPacket, int lsaChecksumPos1, int lsaChecksumPos2) { |
| |
| byte[] checksum = calculateLsaChecksum(lsaPacket, lsaChecksumPos1, lsaChecksumPos2); |
| |
| if (lsaPacket[lsaChecksumPos1] == checksum[0] && lsaPacket[lsaChecksumPos2] == checksum[1]) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Verifies the checksum is valid in given OSPF packet bytes. |
| * |
| * @param ospfPacket as byte array |
| * @param checksumPos1 position of checksum bit in packet |
| * @param checksumPos2 position of checksum bit in packet |
| * @return true if valid else false |
| */ |
| public boolean validateOspfCheckSum(byte[] ospfPacket, int checksumPos1, int checksumPos2) { |
| |
| byte[] checkSum = calculateOspfCheckSum(ospfPacket, checksumPos1, checksumPos2); |
| |
| if (ospfPacket[checksumPos1] == checkSum[0] && ospfPacket[checksumPos2] == checkSum[1]) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Calculates the LSA checksum. |
| * |
| * @param lsaBytes as byte array |
| * @param lsaChecksumPos1 position of checksum bit in packet |
| * @param lsaChecksumPos2 position of checksum bit in packet |
| * @return checksum bytes |
| */ |
| public byte[] calculateLsaChecksum(byte[] lsaBytes, int lsaChecksumPos1, int lsaChecksumPos2) { |
| |
| byte[] tempLsaByte = Arrays.copyOf(lsaBytes, lsaBytes.length); |
| |
| int[] checksumOut = {0, 0}; |
| tempLsaByte[lsaChecksumPos1] = 0; |
| tempLsaByte[lsaChecksumPos2] = 0; |
| byte[] byteCheckSum = {0, 0}; |
| if (lsaBytes != null) { |
| for (int i = 2; i < tempLsaByte.length; i++) { |
| checksumOut[0] = checksumOut[0] + ((int) tempLsaByte[i] & 0xFF); |
| checksumOut[1] = checksumOut[1] + checksumOut[0]; |
| } |
| checksumOut[0] = checksumOut[0] % 255; |
| checksumOut[1] = checksumOut[1] % 255; |
| } |
| int byte1 = (int) ((tempLsaByte.length - lsaChecksumPos1 - 1) * checksumOut[0] - checksumOut[1]) % 255; |
| if (byte1 <= 0) { |
| byte1 += 255; |
| } |
| int byte2 = 510 - checksumOut[0] - byte1; |
| if (byte2 > 255) { |
| byte2 -= 255; |
| } |
| |
| byteCheckSum[0] = (byte) byte1; |
| byteCheckSum[1] = (byte) byte2; |
| |
| return byteCheckSum; |
| } |
| |
| /** |
| * Calculate checksum from hexasum. |
| * |
| * @param hexasum total of 16 bits hexadecimal values |
| * @return checksum value |
| */ |
| private int calculateChecksum(int hexasum) { |
| |
| char[] tempZeros = {'0', '0', '0', '0'}; |
| StringBuffer hexaAsBinaryStr = new StringBuffer(Integer.toBinaryString(hexasum)); |
| int length = hexaAsBinaryStr.length(); |
| while (length > 16) { |
| if (hexaAsBinaryStr.length() % 4 != 0) { |
| int offset = hexaAsBinaryStr.length() % 4; |
| hexaAsBinaryStr.insert(0, tempZeros, 0, 4 - offset); |
| } |
| StringBuffer hexaStr1 = new StringBuffer(hexaAsBinaryStr.reverse().substring(0, 16)); |
| String revHexaStr1 = hexaStr1.reverse().toString(); |
| StringBuffer hexaStr2 = new StringBuffer(hexaAsBinaryStr.reverse()); |
| StringBuffer hexaStr3 = new StringBuffer(hexaStr2.reverse().substring(16, hexaStr2.length())); |
| String revHexaStr3 = hexaStr3.reverse().toString(); |
| int lastSixteenHexaBits = Integer.parseInt(revHexaStr1, 2); |
| int remainingHexaBits = Integer.parseInt(revHexaStr3, 2); |
| int totalCheckSum = lastSixteenHexaBits + remainingHexaBits; |
| hexaAsBinaryStr = new StringBuffer(Integer.toBinaryString(totalCheckSum)); |
| length = hexaAsBinaryStr.length(); |
| } |
| if (hexaAsBinaryStr.length() < 16) { |
| int count = 16 - hexaAsBinaryStr.length(); |
| String s = hexaAsBinaryStr.toString(); |
| for (int i = 0; i < count; i++) { |
| s = "0" + s; |
| } |
| |
| hexaAsBinaryStr = new StringBuffer(s); |
| |
| } |
| StringBuffer checksum = negate(hexaAsBinaryStr); |
| return Integer.parseInt(checksum.toString(), 2); |
| } |
| |
| /** |
| * Negates given hexasum. |
| * |
| * @param binaryString binary form of hexasum |
| * @return binary from of calculateChecksum |
| */ |
| private StringBuffer negate(StringBuffer binaryString) { |
| for (int i = 0; i < binaryString.length(); i++) { |
| if (binaryString.charAt(i) == '1') { |
| binaryString.replace(i, i + 1, "0"); |
| } else { |
| binaryString.replace(i, i + 1, "1"); |
| } |
| } |
| |
| return binaryString; |
| } |
| |
| /** |
| * Calculates the OSPF checksum for the given packet. |
| * |
| * @param packet as byte array |
| * @param checksumPos1 position of checksum bit in packet |
| * @param checksumPos2 position of checksum bit in packet |
| * @return checksum bytes |
| */ |
| public byte[] calculateOspfCheckSum(byte[] packet, int checksumPos1, int checksumPos2) { |
| |
| int hexasum = 0; |
| for (int i = 0; i < packet.length; i = i + 2) { |
| if (i != 12) { |
| byte b1 = packet[i]; |
| String s1 = String.format("%8s", Integer.toBinaryString(b1 & 0xFF)).replace(' ', '0'); |
| b1 = packet[i + 1]; |
| String s2 = String.format("%8s", Integer.toBinaryString(b1 & 0xFF)).replace(' ', '0'); |
| String hexa = s1 + s2; |
| int num1 = Integer.parseInt(hexa, 2); |
| hexasum = hexasum + num1; |
| String convertTo16 = Integer.toHexString(hexasum); |
| if (convertTo16.length() > 4) { |
| hexasum = convertToSixteenBits(convertTo16); |
| } |
| } |
| } |
| StringBuilder sb = new StringBuilder(Integer.toHexString(hexasum)); |
| if (sb.length() > 4) { |
| sb = sb.reverse(); |
| StringBuilder s1 = new StringBuilder(sb.substring(0, 4)); |
| s1 = s1.reverse(); |
| StringBuilder s2 = new StringBuilder(sb.substring(4, sb.length())); |
| s2 = s2.reverse(); |
| hexasum = Integer.parseInt(s1.toString(), 16) + Integer.parseInt(s2.toString(), 16); |
| } |
| int finalChecksum = calculateChecksum(hexasum); |
| return OspfUtil.convertToTwoBytes(finalChecksum); |
| } |
| } |