package org.freertr.ifc; import java.util.List; import org.freertr.pack.packHolder; import org.freertr.util.bits; import org.freertr.util.counter; import org.freertr.util.debugger; import org.freertr.util.logger; import org.freertr.enc.encTlv; import org.freertr.util.cmds; /** * one network control protocol for ppp * * @author matecsaba */ public abstract class ifcPppNcp { /** * create instance */ public ifcPppNcp() { } /** * bitmap value of sawn events */ protected int sawBit; /** * confreqs seen */ private int sawReq1; /** * confreqs seen */ private int sawReq2; /** * confreqs seen */ protected int sawReq3; /** * confnaks seen */ private int sawNakC; /** * confnaks size */ private int sawNakS; /** * last id used */ private int lastTxIdnt; /** * transmitted confreq */ public Object txReq; /** * to keep track of parent */ public ifcPpp parent; /** * counter for this ncp */ public counter cntr = new counter(); /** * saw tx confreq */ public final static int sawTxReq = 0x1; /** * saw rx confreq */ public final static int sawRxReq = 0x2; /** * saw tx confack */ public final static int sawTxAck = 0x4; /** * saw rx confack */ public final static int sawRxAck = 0x8; /** * saw loc2rem data */ public final static int sawLocNeed = 0x10; /** * saw rem2loc data */ public final static int sawRemNeed = 0x20; /** * forced to open */ public final static int sawFrcOpen = 0x40; /** * forced to close */ public final static int sawFrcClsd = 0x80; /** * forced to optional */ public final static int sawFrcOptn = 0x100; /** * preserve state */ public final static int sawPreserv = 0x10; /** * Configure-Request */ public final static int codeConfReq = 1; /** * Configure-Ack */ public final static int codeConfAck = 2; /** * Configure-Nak */ public final static int codeConfNak = 3; /** * Configure-Reject */ public final static int codeConfRej = 4; /** * Terminate-Request */ public final static int codeTermReq = 5; /** * Terminate-Ack */ public final static int codeTermAck = 6; /** * Code-Reject */ public final static int codeCodeRej = 7; /** * Protocol-Reject */ public final static int codeProtRej = 8; /** * Echo-Request */ public final static int codeEchoReq = 9; /** * Echo-Reply */ public final static int codeEchoRep = 10; /** * Discard-Request */ public final static int codeDiscReq = 11; /** * clear this state * * @param prs preserve state if requested */ public void clearUpperState(boolean prs) { int i = sawBit; sawBit &= (sawFrcOpen | sawFrcClsd | sawFrcOptn); if (prs && ((i & sawPreserv) != 0)) { sawBit = i & ~sawPreserv; } if ((sawBit & sawFrcOpen) != 0) { sawBit |= sawLocNeed; } sawReq1 = 0; sawReq2 = 0; sawReq3 = 0; sawNakC = 0; sawNakS = -1; txReq = getOneConfig(true); } /** * force to open state * * @param b state to force */ public void forceOpen(boolean b) { if (b) { sawBit |= sawFrcOpen; } else { sawBit &= ~sawFrcOpen; } } /** * force to closed state * * @param b true to force closed, false to not */ public void forceClose(boolean b) { if (b) { sawBit |= sawFrcClsd; } else { sawBit &= ~sawFrcClsd; } } /** * force to optional state * * @param b true to force closed, false to not */ public void forceOptional(boolean b) { if (b) { sawBit |= sawFrcOptn; } else { sawBit &= ~sawFrcOptn; } } /** * check if forced to open * * @return true if forced, false if not */ public boolean forced2open() { return (sawBit & sawFrcOpen) != 0; } /** * check if forced to closed * * @return true if forced, false if not */ public boolean forced2close() { return (sawBit & sawFrcClsd) != 0; } /** * check if forced to optional * * @return true if forced, false if not */ public boolean forced2optional() { return (sawBit & sawFrcOptn) != 0; } /** * get force value * * @return force */ public int getForceVal() { return sawBit & (sawFrcClsd | sawFrcOpen | sawFrcOptn); } /** * set local need bit */ public void setLocalNeed() { sawBit |= sawLocNeed; } /** * perform generic configuration * * @param a config */ public void doConfig(String a) { if (a.equals("open")) { forceOpen(true); return; } if (a.equals("close")) { forceClose(true); return; } if (a.equals("optional")) { forceOptional(true); return; } } /** * perform generic configuration * * @param a config */ public void unConfig(String a) { if (a.equals("open")) { forceOpen(false); return; } if (a.equals("close")) { forceClose(false); return; } if (a.equals("optional")) { forceOptional(false); return; } } /** * get generic configuration * * @param l list to append * @param beg beginning */ public void getConfig(List l, String beg) { cmds.cfgLine(l, !forced2close(), cmds.tabulator, beg + " close", ""); cmds.cfgLine(l, !forced2open(), cmds.tabulator, beg + " open", ""); cmds.cfgLine(l, !forced2optional(), cmds.tabulator, beg + " optional", ""); } /** * convert code to string * * @param i code value * @return string */ public static String code2str(int i) { switch (i) { case codeConfReq: return "confReq"; case codeConfAck: return "confAck"; case codeConfNak: return "confNak"; case codeConfRej: return "confRej"; case codeTermReq: return "termReq"; case codeTermAck: return "termAck"; case codeCodeRej: return "codeRej"; case codeProtRej: return "protRej"; case codeEchoReq: return "echoReq"; case codeEchoRep: return "echoRep"; case codeDiscReq: return "discReq"; default: return "unknown=" + i; } } /** * check if ready for transmission * * @return true if yes, false if not */ public boolean getReady() { int need = sawTxReq | sawRxReq | sawTxAck | sawRxAck; return (sawBit & need) == need; } /** * check if needed * * @return true if yes, false if not */ public boolean getNeeded() { int need = sawLocNeed | sawRemNeed; return (sawBit & need) != 0; } /** * send one confreq */ public void sendReq() { sawReq2++; if (sawReq2 > 32) { if ((sawBit & sawFrcOptn) != 0) { return; } parent.clearState(); return; } sawReq3++; sawBit |= sawTxReq; packHolder pck = new packHolder(true, true); lastTxIdnt = bits.randomB(); pck.clear(); pck.putStart(); writeOptions(pck, txReq); cntr.tx(pck); parent.sendNcpCtrl(pck, getPPPctrl(), codeConfReq, lastTxIdnt); if (debugger.ifcPppEvnt) { logger.debug("saw=" + bits.toHexB(sawBit) + " options: " + txReq); } } /** * received one confreq * * @param pck packet containing request * @param code code * @param id identification */ public void recvPck(packHolder pck, int code, int id) { if ((sawBit & sawFrcClsd) != 0) { pck.getSkip(-2 - ifcPpp.size); cntr.drop(pck, counter.reasons.notUp); parent.sendNcpCtrl(pck, ifcPppLcp.pppCtrl, ifcPppNcp.codeProtRej, bits.randomB()); return; } cntr.rx(pck); packHolder rej = new packHolder(true, true); rej.clear(); rej.putStart(); Object tmp1; switch (code) { case codeConfReq: rej = pck.copyBytes(true, true); sawBit |= sawRemNeed; Object tmp2 = readOptions(pck); if (tmp2 == null) { cntr.tx(pck); parent.sendNcpCtrl(pck, getPPPctrl(), codeConfRej, id); return; } sawBit |= sawRxReq; tmp1 = gotConfReq(tmp2, true); if (tmp1 != null) { rej.clear(); rej.putStart(); sawNakC = 0; writeOptions(rej, tmp1); rej = copyOptions(rej, pck); cntr.tx(pck); parent.sendNcpCtrl(rej, getPPPctrl(), codeConfRej, id); if (debugger.ifcPppEvnt) { logger.debug("saw=" + bits.toHexB(sawBit) + " options: " + tmp1); } break; } tmp1 = gotConfReq(tmp2, false); if (tmp1 != null) { rej.clear(); rej.putStart(); sawNakC++; writeOptions(rej, tmp1); int siz = rej.headSize(); if (siz != sawNakS) { sawNakC = 0; sawNakS = siz; } if (sawNakC < parent.nakRetryLimit) { cntr.tx(pck); parent.sendNcpCtrl(rej, getPPPctrl(), codeConfNak, id); } else { rej = copyOptions(rej, pck); cntr.tx(pck); parent.sendNcpCtrl(rej, getPPPctrl(), codeConfRej, id); } if (debugger.ifcPppEvnt) { logger.debug("saw=" + bits.toHexB(sawBit) + " options: " + tmp1); } break; } sawBit |= sawTxAck; cntr.tx(pck); parent.sendNcpCtrl(rej, getPPPctrl(), codeConfAck, id); if (debugger.ifcPppEvnt) { logger.debug("saw=" + bits.toHexB(sawBit) + " options: " + tmp2); } sawReq1++; if (sawReq1 > parent.reqResetLimit) { clearState(); sawBit |= sawTxAck | sawRxReq | sawRemNeed | sawPreserv; break; } if (!getReady()) { sawReq1 = 0; } break; case codeConfAck: if (id != lastTxIdnt) { return; } sawReq2 = 0; tmp1 = readOptions(pck); if (tmp1 == null) { return; } if (gotConfAck(tmp1)) { break; } sawBit |= sawRxAck; break; case codeConfNak: if (id != lastTxIdnt) { return; } sawReq2 = 0; tmp1 = readOptions(pck); if (tmp1 == null) { return; } gotConfNak(tmp1); sendReq(); break; case codeConfRej: if (id != lastTxIdnt) { return; } sawReq2 = 0; tmp1 = readOptions(pck); if (tmp1 == null) { return; } gotConfRej(tmp1); sendReq(); break; case codeTermReq: pck.clear(); pck.putStart(); cntr.tx(pck); parent.sendNcpCtrl(pck, getPPPctrl(), codeTermAck, id); parent.clearState(); break; default: if (!gotUnknownCode(pck, code, id)) { break; } cntr.drop(pck, counter.reasons.badCod); parent.sendNcpCtrl(pck, getPPPctrl(), codeCodeRej, id); break; } } /** * get tlv handler * * @return tlv */ protected encTlv getTlv() { return new encTlv(0, 8, 8, 8, 1, 2, 2, 1, 0, 512, true); } /** * read up options * * @param pck packet to parse * @return readed config values, null if reject needed */ public Object readOptions(packHolder pck) { packHolder rej = new packHolder(true, true); Object config = getOneConfig(false); int siz = pck.dataSize(); encTlv tlv = getTlv(); for (;;) { if (tlv.getBytes(pck)) { break; } if (!readOption(config, tlv)) { continue; } tlv.putThis(rej); } pck.setBytesLeft(siz); if (debugger.ifcPppEvnt) { logger.debug("saw=" + bits.toHexB(sawBit) + " options: " + config); } if (rej.headSize() > 0) { rej.merge2beg(); byte[] buf = rej.getCopy(); pck.clear(); pck.putCopy(buf, 0, 0, buf.length); pck.putSkip(buf.length); return null; } return config; } /** * copy option data * * @param lst generated options * @param src original options * @return list of options */ public packHolder copyOptions(packHolder lst, packHolder src) { lst.merge2beg(); packHolder res = new packHolder(true, true); int siz = src.dataSize(); encTlv tlv = getTlv(); for (;;) { if (tlv.getBytes(lst)) { break; } byte[] buf = tlv.copyBytes(); int typ = tlv.valTyp; for (;;) { if (tlv.getBytes(src)) { break; } if (tlv.valTyp != typ) { continue; } buf = tlv.copyBytes(); break; } tlv.putBytes(res, typ, buf); src.setBytesLeft(siz); } return res; } /** * get ppp subprotocol name * * @return value */ public abstract String getPPPname(); /** * get ppp control code * * @return value */ public abstract int getPPPctrl(); /** * clear state of ncp */ public abstract void clearState(); /** * get one configuration * * @param txReq true for tx config request, false if empty one * @return configuration returned */ public abstract Object getOneConfig(boolean txReq); /** * read up one option * * @param config where to store configuration * @param tlv tlv to use * @return false if successful, true if reject needed */ public abstract boolean readOption(Object config, encTlv tlv); /** * write options * * @param pck packet to update * @param data options to use */ public abstract void writeOptions(packHolder pck, Object data); /** * got config acknowledge * * @param data options got * @return false on success, true on error */ public abstract boolean gotConfAck(Object data); /** * got config request * * @param data options got * @param rej report just rejects * @return options to send back as nak */ public abstract Object gotConfReq(Object data, boolean rej); /** * got config nak * * @param data options got */ public abstract void gotConfNak(Object data); /** * got config reject * * @param data options got */ public abstract void gotConfRej(Object data); /** * handle unknown code * * @param pck packet containing request * @param code code * @param id identification * @return false if handled successfully, true to send code reject */ public abstract boolean gotUnknownCode(packHolder pck, int code, int id); }