package org.freertr.rtr; import org.freertr.addr.addrIP; import org.freertr.addr.addrIPv4; import org.freertr.addr.addrIPv6; import org.freertr.addr.addrPrefix; import org.freertr.pack.packHolder; import org.freertr.prt.prtGenConn; import org.freertr.tab.tabRoute; import org.freertr.tab.tabRouteEntry; import org.freertr.util.bits; import org.freertr.util.debugger; import org.freertr.util.logger; /** * olsr neighbor * * @author matecsaba */ public class rtrOlsrNeigh implements rtrBfdClnt, Comparable { /** * prefixes learned from this neighbor */ public final tabRoute learned; /** * olsr interface this neighbor belongs to */ protected final rtrOlsrIface iface; /** * udp connection for this neighbor */ protected prtGenConn conn; /** * uptime */ protected long upTime; /** * create one neighbor * * @param id current connection * @param ifc current interface */ public rtrOlsrNeigh(prtGenConn id, rtrOlsrIface ifc) { conn = id; iface = ifc; learned = new tabRoute("olsr"); upTime = bits.getTime(); } public String toString() { return "olsr with " + conn; } /** * unregister from udp */ public void unregister2udp() { conn.setClosing(); } public int compareTo(rtrOlsrNeigh o) { if (conn.iface.ifwNum < o.conn.iface.ifwNum) { return -1; } if (conn.iface.ifwNum > o.conn.iface.ifwNum) { return +1; } return conn.peerAddr.compareTo(o.conn.peerAddr); } /** * got one packet from neighbor * * @param pck packet received * @return false if successfully parsed, true if error happened */ public synchronized boolean gotPack(packHolder pck) { if (debugger.rtrOlsrTraf) { logger.debug("rx " + conn); } int i = pck.msbGetW(0); if (pck.dataSize() < i) { logger.info("truncated " + conn); return true; } pck.setDataSize(i); //int pckSeq = pck.msbGetW(2); pck.getSkip(4); long tim = bits.getTime(); boolean ipv4 = conn.peerAddr.isIPv4(); for (;;) { if (pck.dataSize() < 1) { break; } int msgTyp = pck.getByte(0); int vldTim = rtrOlsr.mant2tim(pck.getByte(1)); i = pck.msbGetW(2) - 8; pck.getSkip(4); addrIP orig = new addrIP(); if (ipv4) { addrIPv4 a4 = new addrIPv4(); pck.getAddr(a4, 0); pck.getSkip(addrIPv4.size); i -= addrIPv4.size; orig.fromIPv4addr(a4); } else { addrIPv6 a6 = new addrIPv6(); pck.getAddr(a6, 0); pck.getSkip(addrIPv6.size); i -= addrIPv6.size; orig.fromIPv6addr(a6); } //int ttl = pck.getByte(0); int hop = pck.getByte(1); //int msgSeq = pck.msbGetW(2); pck.getSkip(4); if (i < 0) { logger.info("bad length " + conn); break; } if (pck.dataSize() < i) { logger.info("truncated " + conn); return true; } byte[] buf = new byte[i]; pck.getCopy(buf, 0, 0, buf.length); pck.getSkip(i); switch (msgTyp) { case rtrOlsr.typLqHello: break; case rtrOlsr.typLqTc: break; case rtrOlsr.typHello: break; case rtrOlsr.typTc: break; case rtrOlsr.typMid: break; case rtrOlsr.typHna: tabRouteEntry ntry = new tabRouteEntry(); ntry.best.iface = iface.iface; ntry.best.srcRtr = conn.peerAddr.copyBytes(); ntry.best.distance = iface.distance; ntry.best.nextHop = conn.peerAddr.copyBytes(); ntry.best.aggrRtr = orig.copyBytes(); ntry.best.time = tim; ntry.best.accIgp = vldTim; ntry.best.metric = iface.metricIn + hop; if (ipv4) { addrIPv4 a4 = new addrIPv4(); addrIPv4 m4 = new addrIPv4(); a4.fromBuf(buf, 0); m4.fromBuf(buf, addrIPv4.size); ntry.prefix = addrPrefix.ip4toIP(new addrPrefix(a4, m4.toNetmask())); } else { addrIPv6 a6 = new addrIPv6(); addrIPv6 m6 = new addrIPv6(); a6.fromBuf(buf, 0); m6.fromBuf(buf, addrIPv6.size); ntry.prefix = addrPrefix.ip6toIP(new addrPrefix(a6, m6.toNetmask())); } if (debugger.rtrOlsrTraf) { logger.debug("rxnet " + ntry); } tabRoute.addUpdatedEntry(tabRoute.addType.always, learned, rtrBgpUtil.sfiUnicast, 0, ntry, true, iface.roumapIn, iface.roupolIn, iface.prflstIn); break; default: logger.info("invalid msg " + msgTyp); break; } } return false; } /** * do one work round * * @return true if table touched, false otherwise */ public synchronized boolean doWork() { long curTim = bits.getTime(); conn.timeout = iface.helloHold; conn.workInterval = iface.helloTimer; int done = 0; for (int i = learned.size() - 1; i >= 0; i--) { tabRouteEntry ntry = learned.get(i); if (ntry == null) { continue; } if ((curTim - ntry.best.time) < ntry.best.accIgp) { continue; } if (debugger.rtrOlsrEvnt) { logger.debug("netdel " + ntry); } learned.del(ntry.prefix); done++; } return (done > 0); } /** * stop work */ public void bfdPeerDown() { iface.lower.datagramClosed(conn); } }