package org.freertr.rtr; import org.freertr.addr.addrIPv4; import org.freertr.pack.packHolder; import org.freertr.util.bits; /** * ospfv2 lsa * * @author matecsaba */ public class rtrOspf4lsa implements Comparable { /** * header size */ public final static int headSize = 20; /** * request size */ public final static int reqSize = 12; /** * router lsa */ public final static int lsaRouter = 1; /** * network lsa */ public final static int lsaNetwork = 2; /** * network summary lsa */ public final static int lsaSumNet = 3; /** * asbr summary lsa */ public final static int lsaSumAsBr = 4; /** * as external lsa */ public final static int lsaAsExt = 5; /** * group membership lsa */ public final static int lsaGrpMem = 6; /** * nssa external lsa */ public final static int lsaNssaExt = 7; /** * link opaque lsa */ public final static int lsaOpLink = 9; /** * area opaque lsa */ public final static int lsaOpArea = 10; /** * as opaque lsa */ public final static int lsaOpWhole = 11; /** * point to point link */ public final static int lnkP2p = 1; /** * transit network */ public final static int lnkTrns = 2; /** * stub network */ public final static int lnkStub = 3; /** * virtual link */ public final static int lnkVirt = 4; /** * max lsa age */ public final static int lsaMaxAge = 3600000; /** * time when lsa created */ public long created; /** * do not age lsa */ public boolean doNotAge; /** * optional capability bits */ public int capability; /** * type of lsa */ public int lsaType; /** * link state id */ public addrIPv4 lsaID; /** * advertising router id */ public addrIPv4 rtrID; /** * link state sequence number */ public int sequence; /** * checksum of stored data */ public int bufSum; /** * link state data */ protected byte[] bufDat; /** * create empty lsa */ public rtrOspf4lsa() { lsaID = new addrIPv4(); rtrID = new addrIPv4(); bufDat = new byte[0]; } /** * convert lsa type to string * * @param i lsa type * @return converted string */ public static String lsaType2string(int i) { switch (i) { case lsaRouter: return "router"; case lsaNetwork: return "network"; case lsaSumNet: return "summaryNetwork"; case lsaSumAsBr: return "summaryAsbr"; case lsaAsExt: return "asExternal"; case lsaGrpMem: return "groupMembership"; case lsaNssaExt: return "nssaExternal"; case lsaOpLink: return "opaque-link"; case lsaOpArea: return "opaque-area"; case lsaOpWhole: return "opaque-as"; default: return "unknown=" + i; } } public String toString() { String a; if (bufDat == null) { a = "?"; } else { a = "" + bufDat.length; } String b; if (doNotAge) { b = "dna"; } else { b = bits.timePast(created); } return rtrID + "|" + lsaID + "|" + bits.toHexD(sequence) + "|" + lsaType2string(lsaType) + "|" + a + "|" + b; } /** * check if other is newer * * @param other other lsa to compare to * @return true if other newer, false if this is newer */ public boolean otherNewer(rtrOspf4lsa other) { final int mask = 0x7fffffff; if ((other.sequence & mask) > (sequence & mask)) { return true; } return false; } /** * clone this lsa * * @param payload copy payload too * @return copied lsa object */ public rtrOspf4lsa copyBytes(boolean payload) { rtrOspf4lsa n = new rtrOspf4lsa(); n.created = created; n.capability = capability; n.sequence = sequence; n.lsaType = lsaType; n.lsaID = lsaID.copyBytes(); n.rtrID = rtrID.copyBytes(); n.bufSum = bufSum; if (!payload) { return n; } n.bufDat = new byte[bufDat.length]; bits.byteCopy(bufDat, 0, n.bufDat, 0, bufDat.length); return n; } public int compareTo(rtrOspf4lsa o) { if (lsaType < o.lsaType) { return -1; } if (lsaType > o.lsaType) { return +1; } int i = lsaID.compareTo(o.lsaID); if (i != 0) { return i; } return rtrID.compareTo(o.rtrID); } /** * write request * * @param pck packet to write to * @param ofs offset where to write * @return bytes written */ public int writeReq(packHolder pck, int ofs) { pck.msbPutD(ofs + 0, lsaType); // type pck.putAddr(ofs + 4, lsaID); // lsa id pck.putAddr(ofs + 8, rtrID); // router id return reqSize; } /** * read request * * @param pck packet to read from * @param ofs offset where from read * @return bytes readed, negative on error */ public int readReq(packHolder pck, int ofs) { if (pck.dataSize() < reqSize) { return -1; } lsaType = pck.msbGetD(ofs + 0); // type pck.getAddr(lsaID, ofs + 4); // lsa id pck.getAddr(rtrID, ofs + 8); // router id return reqSize; } /** * write lsa * * @param pck packet to write to * @param ofs offset where to write * @param payload copy payload too * @return bytes written */ public int writeData(packHolder pck, int ofs, boolean payload) { int i; if (doNotAge) { i = (int) created; } else { i = (int) ((bits.getTime() - created) / 1000); } if (i < 0) { i = 0; } if (i > 0x7fff) { i = 0x7fff; } if (doNotAge) { i |= 0x8000; } pck.msbPutW(ofs + 0, i); // age pck.putByte(ofs + 2, capability); // options pck.putByte(ofs + 3, lsaType); // type pck.putAddr(ofs + 4, lsaID); // lsa id pck.putAddr(ofs + 8, rtrID); // router id pck.msbPutD(ofs + 12, sequence); // sequence number pck.msbPutW(ofs + 16, bufSum); // checksum pck.msbPutW(ofs + 18, bufDat.length + headSize); // size if (!payload) { return headSize; } pck.putCopy(bufDat, 0, ofs + headSize, bufDat.length); return headSize + bufDat.length; } /** * read lsa * * @param pck packet to read from * @param ofs offset where from read * @param payload copy payload too * @return bytes readed, negative on error */ public int readData(packHolder pck, int ofs, boolean payload) { if (pck.dataSize() < (ofs + headSize)) { return -1; } int i = pck.msbGetW(ofs + 0); // age doNotAge = (i & 0x8000) != 0; if (doNotAge) { created = i; } else { created = bits.getTime() - (i * 1000); } capability = pck.getByte(ofs + 2); // options lsaType = pck.getByte(ofs + 3); // type pck.getAddr(lsaID, ofs + 4); // lsa id pck.getAddr(rtrID, ofs + 8); // router id sequence = pck.msbGetD(ofs + 12); // sequence number bufSum = pck.msbGetW(ofs + 16); // checksum i = pck.msbGetW(ofs + 18); // length if (i < headSize) { return -2; } if (!payload) { return headSize; } bufDat = new byte[i - headSize]; if (pck.dataSize() < (ofs + headSize + bufDat.length)) { return -3; } if (bufSum != pck.getISOsum(ofs + 2, headSize + bufDat.length - 2, 14)) { return -4; } pck.getCopy(bufDat, 0, ofs + headSize, bufDat.length); return headSize + bufDat.length; } /** * calculate lsa checksum */ public void generateCheckSum() { packHolder pck = new packHolder(true, true); int i = writeData(pck, 0, true); bufSum = pck.putISOsum(2, i - 2, 14); } /** * get payload as packet * * @return payload */ public packHolder getPayload() { packHolder pck = new packHolder(true, true); pck.putCopy(bufDat, 0, 0, bufDat.length); pck.putSkip(bufDat.length); pck.merge2beg(); return pck; } /** * check if content differs * * @param other other lsa to check * @return true if yes, false if no */ public boolean contentDiffers(rtrOspf4lsa other) { if (other == null) { return true; } if (bufDat.length != other.bufDat.length) { return true; } if (capability != other.capability) { return true; } return bits.byteComp(bufDat, 0, other.bufDat, 0, bufDat.length) != 0; } }