Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 1 | /* |
Brian O'Connor | a09fe5b | 2017-08-03 21:12:30 -0700 | [diff] [blame] | 2 | * Copyright 2016-present Open Networking Foundation |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | package org.onosproject.ospf.protocol.util; |
| 17 | |
| 18 | import org.onosproject.ospf.controller.OspfLsa; |
| 19 | import org.onosproject.ospf.controller.OspfLsaType; |
Ray Milkey | 019fba4 | 2018-01-31 14:07:47 -0800 | [diff] [blame] | 20 | import org.onosproject.ospf.exceptions.OspfParseException; |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 21 | import org.onosproject.ospf.protocol.lsa.types.AsbrSummaryLsa; |
| 22 | import org.onosproject.ospf.protocol.lsa.types.ExternalLsa; |
| 23 | import org.onosproject.ospf.protocol.lsa.types.NetworkLsa; |
| 24 | import org.onosproject.ospf.protocol.lsa.types.OpaqueLsa10; |
| 25 | import org.onosproject.ospf.protocol.lsa.types.OpaqueLsa11; |
| 26 | import org.onosproject.ospf.protocol.lsa.types.OpaqueLsa9; |
| 27 | import org.onosproject.ospf.protocol.lsa.types.RouterLsa; |
| 28 | import org.onosproject.ospf.protocol.lsa.types.SummaryLsa; |
sunishvk | f7c5655 | 2016-07-18 16:02:39 +0530 | [diff] [blame] | 29 | import org.onosproject.ospf.controller.OspfMessage; |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 30 | import org.onosproject.ospf.protocol.ospfpacket.types.DdPacket; |
| 31 | import org.onosproject.ospf.protocol.ospfpacket.types.HelloPacket; |
| 32 | import org.onosproject.ospf.protocol.ospfpacket.types.LsAcknowledge; |
| 33 | import org.onosproject.ospf.protocol.ospfpacket.types.LsRequest; |
| 34 | import org.onosproject.ospf.protocol.ospfpacket.types.LsUpdate; |
Ray Milkey | 019fba4 | 2018-01-31 14:07:47 -0800 | [diff] [blame] | 35 | import org.slf4j.Logger; |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 36 | |
| 37 | import java.util.Arrays; |
| 38 | |
Ray Milkey | 019fba4 | 2018-01-31 14:07:47 -0800 | [diff] [blame] | 39 | import static org.slf4j.LoggerFactory.getLogger; |
| 40 | |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 41 | /** |
| 42 | * Calculates checksum for different types of OSPF packets. |
| 43 | */ |
| 44 | public class ChecksumCalculator { |
| 45 | |
Ray Milkey | 019fba4 | 2018-01-31 14:07:47 -0800 | [diff] [blame] | 46 | private static final Logger log = getLogger(ChecksumCalculator.class); |
| 47 | |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 48 | /** |
| 49 | * Converts given string to sixteen bits integer. |
| 50 | * If hexasum is more than 16 bit value, needs to be reduced to 16 bit value. |
| 51 | * |
| 52 | * @param strToConvert hexasum value to convert |
| 53 | * @return 16 bit integer value |
| 54 | */ |
| 55 | public static int convertToSixteenBits(String strToConvert) { |
| 56 | StringBuilder sb = new StringBuilder(strToConvert); |
| 57 | sb = sb.reverse(); |
| 58 | StringBuilder s1 = new StringBuilder(sb.substring(0, 4)); |
| 59 | s1 = s1.reverse(); |
| 60 | StringBuilder s2 = new StringBuilder(sb.substring(4, sb.length())); |
| 61 | s2 = s2.reverse(); |
| 62 | int num = Integer.parseInt(s1.toString(), 16) + Integer.parseInt(s2.toString(), 16); |
| 63 | return num; |
| 64 | } |
| 65 | |
| 66 | /** |
| 67 | * Checks whether checksum is valid or not in the given OSPF message. |
| 68 | * |
| 69 | * @param ospfMessage ospf message instance |
| 70 | * @param checksumPos1 position of checksum bit in packet |
| 71 | * @param checksumPos2 position of checksum bit in packet |
| 72 | * @return true if valid else false |
| 73 | */ |
| 74 | public boolean isValidOspfCheckSum(OspfMessage ospfMessage, int checksumPos1, int checksumPos2) { |
| 75 | |
| 76 | switch (ospfMessage.ospfMessageType().value()) { |
| 77 | case OspfParameters.HELLO: |
| 78 | ospfMessage = (HelloPacket) ospfMessage; |
| 79 | break; |
| 80 | case OspfParameters.DD: |
| 81 | ospfMessage = (DdPacket) ospfMessage; |
| 82 | break; |
| 83 | case OspfParameters.LSREQUEST: |
| 84 | ospfMessage = (LsRequest) ospfMessage; |
| 85 | break; |
| 86 | case OspfParameters.LSUPDATE: |
| 87 | ospfMessage = (LsUpdate) ospfMessage; |
| 88 | break; |
| 89 | case OspfParameters.LSACK: |
| 90 | ospfMessage = (LsAcknowledge) ospfMessage; |
| 91 | break; |
| 92 | default: |
| 93 | break; |
| 94 | } |
| 95 | |
| 96 | byte[] messageAsBytes = ospfMessage.asBytes(); |
| 97 | return validateOspfCheckSum(messageAsBytes, checksumPos1, checksumPos2); |
| 98 | } |
| 99 | |
| 100 | /** |
| 101 | * Checks whether checksum is valid or not in the given OSPF LSA. |
| 102 | * |
| 103 | * @param ospfLsa lsa instance |
| 104 | * @param lsType lsa type |
| 105 | * @param lsaChecksumPos1 lsa checksum position in packet |
| 106 | * @param lsaChecksumPos2 lsa checksum position in packet |
Ray Milkey | 019fba4 | 2018-01-31 14:07:47 -0800 | [diff] [blame] | 107 | * @throws OspfParseException if packet can't be parsed |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 108 | * @return true if valid else false |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 109 | */ |
| 110 | public boolean isValidLsaCheckSum(OspfLsa ospfLsa, int lsType, int lsaChecksumPos1, |
Ray Milkey | 019fba4 | 2018-01-31 14:07:47 -0800 | [diff] [blame] | 111 | int lsaChecksumPos2) throws OspfParseException { |
| 112 | |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 113 | if (lsType == OspfLsaType.ROUTER.value()) { |
| 114 | RouterLsa lsa = (RouterLsa) ospfLsa; |
| 115 | return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| 116 | } else if (lsType == OspfLsaType.NETWORK.value()) { |
| 117 | NetworkLsa lsa = (NetworkLsa) ospfLsa; |
| 118 | return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| 119 | } else if (lsType == OspfLsaType.SUMMARY.value()) { |
| 120 | SummaryLsa lsa = (SummaryLsa) ospfLsa; |
| 121 | return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| 122 | } else if (lsType == OspfLsaType.ASBR_SUMMARY.value()) { |
| 123 | AsbrSummaryLsa lsa = (AsbrSummaryLsa) ospfLsa; |
| 124 | return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| 125 | } else if (lsType == OspfLsaType.EXTERNAL_LSA.value()) { |
| 126 | ExternalLsa lsa = (ExternalLsa) ospfLsa; |
| 127 | return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| 128 | } else if (lsType == OspfLsaType.LINK_LOCAL_OPAQUE_LSA.value()) { |
| 129 | OpaqueLsa9 lsa = (OpaqueLsa9) ospfLsa; |
| 130 | return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| 131 | } else if (lsType == OspfLsaType.AREA_LOCAL_OPAQUE_LSA.value()) { |
| 132 | OpaqueLsa10 lsa = (OpaqueLsa10) ospfLsa; |
| 133 | return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| 134 | } else if (lsType == OspfLsaType.AS_OPAQUE_LSA.value()) { |
| 135 | OpaqueLsa11 lsa = (OpaqueLsa11) ospfLsa; |
| 136 | return validateLsaCheckSum(lsa.asBytes(), lsaChecksumPos1, lsaChecksumPos2); |
| 137 | } |
| 138 | |
Ray Milkey | 019fba4 | 2018-01-31 14:07:47 -0800 | [diff] [blame] | 139 | |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 140 | return false; |
| 141 | } |
| 142 | |
| 143 | /** |
| 144 | * Verifies the checksum is valid in given LSA packet bytes. |
| 145 | * |
| 146 | * @param lsaPacket lsa as byte array |
| 147 | * @param lsaChecksumPos1 position of checksum bit in packet |
| 148 | * @param lsaChecksumPos2 position of checksum bit in packet |
| 149 | * @return true if valid else false |
| 150 | */ |
| 151 | public boolean validateLsaCheckSum(byte[] lsaPacket, int lsaChecksumPos1, int lsaChecksumPos2) { |
| 152 | |
| 153 | byte[] checksum = calculateLsaChecksum(lsaPacket, lsaChecksumPos1, lsaChecksumPos2); |
| 154 | |
| 155 | if (lsaPacket[lsaChecksumPos1] == checksum[0] && lsaPacket[lsaChecksumPos2] == checksum[1]) { |
| 156 | return true; |
| 157 | } |
| 158 | |
| 159 | return false; |
| 160 | } |
| 161 | |
| 162 | /** |
| 163 | * Verifies the checksum is valid in given OSPF packet bytes. |
| 164 | * |
| 165 | * @param ospfPacket as byte array |
| 166 | * @param checksumPos1 position of checksum bit in packet |
| 167 | * @param checksumPos2 position of checksum bit in packet |
| 168 | * @return true if valid else false |
| 169 | */ |
| 170 | public boolean validateOspfCheckSum(byte[] ospfPacket, int checksumPos1, int checksumPos2) { |
| 171 | |
| 172 | byte[] checkSum = calculateOspfCheckSum(ospfPacket, checksumPos1, checksumPos2); |
| 173 | |
| 174 | if (ospfPacket[checksumPos1] == checkSum[0] && ospfPacket[checksumPos2] == checkSum[1]) { |
| 175 | return true; |
| 176 | } |
| 177 | |
| 178 | return false; |
| 179 | } |
| 180 | |
| 181 | /** |
| 182 | * Calculates the LSA checksum. |
| 183 | * |
| 184 | * @param lsaBytes as byte array |
| 185 | * @param lsaChecksumPos1 position of checksum bit in packet |
| 186 | * @param lsaChecksumPos2 position of checksum bit in packet |
| 187 | * @return checksum bytes |
| 188 | */ |
| 189 | public byte[] calculateLsaChecksum(byte[] lsaBytes, int lsaChecksumPos1, int lsaChecksumPos2) { |
| 190 | |
| 191 | byte[] tempLsaByte = Arrays.copyOf(lsaBytes, lsaBytes.length); |
| 192 | |
| 193 | int[] checksumOut = {0, 0}; |
| 194 | tempLsaByte[lsaChecksumPos1] = 0; |
| 195 | tempLsaByte[lsaChecksumPos2] = 0; |
| 196 | byte[] byteCheckSum = {0, 0}; |
Ray Milkey | fe0e085 | 2018-01-18 11:14:05 -0800 | [diff] [blame] | 197 | for (int i = 2; i < tempLsaByte.length; i++) { |
| 198 | checksumOut[0] = checksumOut[0] + ((int) tempLsaByte[i] & 0xFF); |
| 199 | checksumOut[1] = checksumOut[1] + checksumOut[0]; |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 200 | } |
Ray Milkey | fe0e085 | 2018-01-18 11:14:05 -0800 | [diff] [blame] | 201 | checksumOut[0] = checksumOut[0] % 255; |
| 202 | checksumOut[1] = checksumOut[1] % 255; |
Dhruv Dhody | 43f3ce6 | 2016-02-16 22:44:21 +0530 | [diff] [blame] | 203 | int byte1 = (int) ((tempLsaByte.length - lsaChecksumPos1 - 1) * checksumOut[0] - checksumOut[1]) % 255; |
| 204 | if (byte1 <= 0) { |
| 205 | byte1 += 255; |
| 206 | } |
| 207 | int byte2 = 510 - checksumOut[0] - byte1; |
| 208 | if (byte2 > 255) { |
| 209 | byte2 -= 255; |
| 210 | } |
| 211 | |
| 212 | byteCheckSum[0] = (byte) byte1; |
| 213 | byteCheckSum[1] = (byte) byte2; |
| 214 | |
| 215 | return byteCheckSum; |
| 216 | } |
| 217 | |
| 218 | /** |
| 219 | * Calculate checksum from hexasum. |
| 220 | * |
| 221 | * @param hexasum total of 16 bits hexadecimal values |
| 222 | * @return checksum value |
| 223 | */ |
| 224 | private int calculateChecksum(int hexasum) { |
| 225 | |
| 226 | char[] tempZeros = {'0', '0', '0', '0'}; |
| 227 | StringBuffer hexaAsBinaryStr = new StringBuffer(Integer.toBinaryString(hexasum)); |
| 228 | int length = hexaAsBinaryStr.length(); |
| 229 | while (length > 16) { |
| 230 | if (hexaAsBinaryStr.length() % 4 != 0) { |
| 231 | int offset = hexaAsBinaryStr.length() % 4; |
| 232 | hexaAsBinaryStr.insert(0, tempZeros, 0, 4 - offset); |
| 233 | } |
| 234 | StringBuffer hexaStr1 = new StringBuffer(hexaAsBinaryStr.reverse().substring(0, 16)); |
| 235 | String revHexaStr1 = hexaStr1.reverse().toString(); |
| 236 | StringBuffer hexaStr2 = new StringBuffer(hexaAsBinaryStr.reverse()); |
| 237 | StringBuffer hexaStr3 = new StringBuffer(hexaStr2.reverse().substring(16, hexaStr2.length())); |
| 238 | String revHexaStr3 = hexaStr3.reverse().toString(); |
| 239 | int lastSixteenHexaBits = Integer.parseInt(revHexaStr1, 2); |
| 240 | int remainingHexaBits = Integer.parseInt(revHexaStr3, 2); |
| 241 | int totalCheckSum = lastSixteenHexaBits + remainingHexaBits; |
| 242 | hexaAsBinaryStr = new StringBuffer(Integer.toBinaryString(totalCheckSum)); |
| 243 | length = hexaAsBinaryStr.length(); |
| 244 | } |
| 245 | if (hexaAsBinaryStr.length() < 16) { |
| 246 | int count = 16 - hexaAsBinaryStr.length(); |
| 247 | String s = hexaAsBinaryStr.toString(); |
| 248 | for (int i = 0; i < count; i++) { |
| 249 | s = "0" + s; |
| 250 | } |
| 251 | |
| 252 | hexaAsBinaryStr = new StringBuffer(s); |
| 253 | |
| 254 | } |
| 255 | StringBuffer checksum = negate(hexaAsBinaryStr); |
| 256 | return Integer.parseInt(checksum.toString(), 2); |
| 257 | } |
| 258 | |
| 259 | /** |
| 260 | * Negates given hexasum. |
| 261 | * |
| 262 | * @param binaryString binary form of hexasum |
| 263 | * @return binary from of calculateChecksum |
| 264 | */ |
| 265 | private StringBuffer negate(StringBuffer binaryString) { |
| 266 | for (int i = 0; i < binaryString.length(); i++) { |
| 267 | if (binaryString.charAt(i) == '1') { |
| 268 | binaryString.replace(i, i + 1, "0"); |
| 269 | } else { |
| 270 | binaryString.replace(i, i + 1, "1"); |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | return binaryString; |
| 275 | } |
| 276 | |
| 277 | /** |
| 278 | * Calculates the OSPF checksum for the given packet. |
| 279 | * |
| 280 | * @param packet as byte array |
| 281 | * @param checksumPos1 position of checksum bit in packet |
| 282 | * @param checksumPos2 position of checksum bit in packet |
| 283 | * @return checksum bytes |
| 284 | */ |
| 285 | public byte[] calculateOspfCheckSum(byte[] packet, int checksumPos1, int checksumPos2) { |
| 286 | |
| 287 | int hexasum = 0; |
| 288 | for (int i = 0; i < packet.length; i = i + 2) { |
| 289 | if (i != 12) { |
| 290 | byte b1 = packet[i]; |
| 291 | String s1 = String.format("%8s", Integer.toBinaryString(b1 & 0xFF)).replace(' ', '0'); |
| 292 | b1 = packet[i + 1]; |
| 293 | String s2 = String.format("%8s", Integer.toBinaryString(b1 & 0xFF)).replace(' ', '0'); |
| 294 | String hexa = s1 + s2; |
| 295 | int num1 = Integer.parseInt(hexa, 2); |
| 296 | hexasum = hexasum + num1; |
| 297 | String convertTo16 = Integer.toHexString(hexasum); |
| 298 | if (convertTo16.length() > 4) { |
| 299 | hexasum = convertToSixteenBits(convertTo16); |
| 300 | } |
| 301 | } |
| 302 | } |
| 303 | StringBuilder sb = new StringBuilder(Integer.toHexString(hexasum)); |
| 304 | if (sb.length() > 4) { |
| 305 | sb = sb.reverse(); |
| 306 | StringBuilder s1 = new StringBuilder(sb.substring(0, 4)); |
| 307 | s1 = s1.reverse(); |
| 308 | StringBuilder s2 = new StringBuilder(sb.substring(4, sb.length())); |
| 309 | s2 = s2.reverse(); |
| 310 | hexasum = Integer.parseInt(s1.toString(), 16) + Integer.parseInt(s2.toString(), 16); |
| 311 | } |
| 312 | int finalChecksum = calculateChecksum(hexasum); |
| 313 | return OspfUtil.convertToTwoBytes(finalChecksum); |
| 314 | } |
| 315 | } |