fsm.c revision 37210
169800Stomsoft/* 269800Stomsoft * PPP Finite State Machine for LCP/IPCP 369800Stomsoft * 469800Stomsoft * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5114067Sschweikh * 669800Stomsoft * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 769800Stomsoft * 8114067Sschweikh * Redistribution and use in source and binary forms are permitted 969800Stomsoft * provided that the above copyright notice and this paragraph are 1069800Stomsoft * duplicated in all such forms and that any documentation, 1169800Stomsoft * advertising materials, and other materials related to such 1269800Stomsoft * distribution and use acknowledge that the software was developed 1369800Stomsoft * by the Internet Initiative Japan, Inc. The name of the 1469800Stomsoft * IIJ may not be used to endorse or promote products derived 1569800Stomsoft * from this software without specific prior written permission. 1669800Stomsoft * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1769800Stomsoft * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1869800Stomsoft * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1969800Stomsoft * 2069800Stomsoft * $Id: fsm.c,v 1.33 1998/06/25 22:33:20 brian Exp $ 2169800Stomsoft * 2269800Stomsoft * TODO: 2369800Stomsoft */ 2469800Stomsoft 25114067Sschweikh#include <sys/types.h> 2669800Stomsoft#include <netinet/in.h> 2769800Stomsoft#include <netinet/in_systm.h> 2869800Stomsoft#include <netinet/ip.h> 2969800Stomsoft#include <sys/un.h> 3069800Stomsoft 3169800Stomsoft#include <string.h> 3269800Stomsoft#include <termios.h> 3369800Stomsoft 3469800Stomsoft#include "mbuf.h" 3569800Stomsoft#include "log.h" 3669800Stomsoft#include "defs.h" 3769800Stomsoft#include "timer.h" 3869926Stomsoft#include "fsm.h" 3969800Stomsoft#include "iplist.h" 4069800Stomsoft#include "lqr.h" 4169800Stomsoft#include "hdlc.h" 4269800Stomsoft#include "throughput.h" 4369800Stomsoft#include "slcompress.h" 4469800Stomsoft#include "ipcp.h" 4569800Stomsoft#include "filter.h" 4669800Stomsoft#include "descriptor.h" 4769800Stomsoft#include "lcp.h" 4869800Stomsoft#include "ccp.h" 4969800Stomsoft#include "link.h" 5069800Stomsoft#include "mp.h" 5169926Stomsoft#include "bundle.h" 5269800Stomsoft#include "async.h" 5369800Stomsoft#include "physical.h" 5469800Stomsoft#include "lcpproto.h" 5569800Stomsoft 5669800Stomsoftstatic void FsmSendConfigReq(struct fsm *); 5769800Stomsoftstatic void FsmSendTerminateReq(struct fsm *); 5869800Stomsoftstatic void FsmInitRestartCounter(struct fsm *); 5969800Stomsoft 6069800Stomsofttypedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *); 6169800Stomsoftstatic recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak, 6269800Stomsoft FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck, 6369800Stomsoft FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq, 6469800Stomsoft FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent, 65103949Smike FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck; 6669800Stomsoft 6769800Stomsoftstatic const struct fsmcodedesc { 6869800Stomsoft recvfn *recv; 6969800Stomsoft unsigned check_reqid : 1; 7069800Stomsoft unsigned inc_reqid : 1; 7169800Stomsoft const char *name; 7269800Stomsoft} FsmCodes[] = { 7369800Stomsoft { FsmRecvConfigReq, 0, 0, "ConfigReq" }, 7469800Stomsoft { FsmRecvConfigAck, 1, 1, "ConfigAck" }, 7569800Stomsoft { FsmRecvConfigNak, 1, 1, "ConfigNak" }, 7669800Stomsoft { FsmRecvConfigRej, 1, 1, "ConfigRej" }, 7769800Stomsoft { FsmRecvTermReq, 0, 0, "TerminateReq" }, 7869800Stomsoft { FsmRecvTermAck, 1, 1, "TerminateAck" }, 7969800Stomsoft { FsmRecvCodeRej, 0, 0, "CodeRej" }, 8069800Stomsoft { FsmRecvProtoRej, 0, 0, "ProtocolRej" }, 8198542Smckusick { FsmRecvEchoReq, 0, 0, "EchoRequest" }, 8269800Stomsoft { FsmRecvEchoRep, 0, 0, "EchoReply" }, 8369800Stomsoft { FsmRecvDiscReq, 0, 0, "DiscardReq" }, 8469800Stomsoft { FsmRecvIdent, 0, 0, "Ident" }, 8569800Stomsoft { FsmRecvTimeRemain,0, 0, "TimeRemain" }, 8698542Smckusick { FsmRecvResetReq, 0, 0, "ResetReqt" }, 8798542Smckusick { FsmRecvResetAck, 0, 1, "ResetAck" } 8898542Smckusick}; 8998542Smckusick 9098542Smckusickstatic const char * 9198542SmckusickCode2Nam(u_int code) 9269800Stomsoft{ 9369800Stomsoft if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0]) 9469800Stomsoft return "Unknown"; 9569800Stomsoft return FsmCodes[code-1].name; 9669800Stomsoft} 9769800Stomsoft 9869800Stomsoftconst char * 9998542SmckusickState2Nam(u_int state) 10069800Stomsoft{ 10198542Smckusick static const char *StateNames[] = { 10269800Stomsoft "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", 10398542Smckusick "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", 10498542Smckusick }; 10598542Smckusick 10669800Stomsoft if (state >= sizeof StateNames / sizeof StateNames[0]) 10798542Smckusick return "unknown"; 10898542Smckusick return StateNames[state]; 10998542Smckusick} 11098542Smckusick 11198542Smckusickstatic void 11298542SmckusickStoppedTimeout(void *v) 11369800Stomsoft{ 11469800Stomsoft struct fsm *fp = (struct fsm *)v; 115114067Sschweikh 11669800Stomsoft log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name); 11769800Stomsoft if (fp->OpenTimer.state == TIMER_RUNNING) { 11869800Stomsoft log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n", 11969800Stomsoft fp->link->name, fp->name); 12098542Smckusick timer_Stop(&fp->OpenTimer); 12198542Smckusick } 12269800Stomsoft if (fp->state == ST_STOPPED) 12369800Stomsoft fsm2initial(fp); 12477885Stomsoft} 12569800Stomsoft 12669800Stomsoftvoid 12769800Stomsoftfsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, 12869800Stomsoft int maxcode, int maxcfg, int LogLevel, struct bundle *bundle, 12977885Stomsoft struct link *l, const struct fsm_parent *parent, 13098542Smckusick struct fsm_callbacks *fn, const char *timer_names[3]) 13198542Smckusick{ 13298542Smckusick fp->name = name; 13369800Stomsoft fp->proto = proto; 13469926Stomsoft fp->min_code = mincode; 13569800Stomsoft fp->max_code = maxcode; 13669800Stomsoft fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; 13769800Stomsoft fp->reqid = 1; 13877885Stomsoft fp->restart = 1; 13977885Stomsoft fp->maxconfig = maxcfg; 14077885Stomsoft memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); 14169800Stomsoft memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); 14277885Stomsoft memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); 14398542Smckusick fp->LogLevel = LogLevel; 14498542Smckusick fp->link = l; 14598542Smckusick fp->bundle = bundle; 14698542Smckusick fp->parent = parent; 14769800Stomsoft fp->fn = fn; 14877885Stomsoft fp->FsmTimer.name = timer_names[0]; 14998542Smckusick fp->OpenTimer.name = timer_names[1]; 15098542Smckusick fp->StoppedTimer.name = timer_names[2]; 15169800Stomsoft} 15269800Stomsoft 15369800Stomsoftstatic void 154114067SschweikhNewState(struct fsm * fp, int new) 155114067Sschweikh{ 156114067Sschweikh log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", 15769800Stomsoft fp->link->name, State2Nam(fp->state), State2Nam(new)); 158114067Sschweikh if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) 159114067Sschweikh timer_Stop(&fp->StoppedTimer); 160114067Sschweikh fp->state = new; 16169800Stomsoft if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { 16269800Stomsoft timer_Stop(&fp->FsmTimer); 16369800Stomsoft if (new == ST_STOPPED && fp->StoppedTimer.load) { 16469800Stomsoft timer_Stop(&fp->StoppedTimer); 16577885Stomsoft fp->StoppedTimer.func = StoppedTimeout; 16669800Stomsoft fp->StoppedTimer.arg = (void *) fp; 16769800Stomsoft timer_Start(&fp->StoppedTimer); 16877885Stomsoft } 16977885Stomsoft } 17069800Stomsoft} 17169800Stomsoft 17269800Stomsoftvoid 17369800Stomsoftfsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count) 17469800Stomsoft{ 17569800Stomsoft int plen; 17669800Stomsoft struct fsmheader lh; 17769800Stomsoft struct mbuf *bp; 17869800Stomsoft 17969800Stomsoft if (log_IsKept(fp->LogLevel)) { 18069800Stomsoft log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 18169800Stomsoft fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 18269800Stomsoft switch (code) { 18369800Stomsoft case CODE_CONFIGREQ: 18469800Stomsoft case CODE_CONFIGACK: 18569800Stomsoft case CODE_CONFIGREJ: 18669800Stomsoft case CODE_CONFIGNAK: 18769800Stomsoft (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL); 18869800Stomsoft if (count < sizeof(struct fsmconfig)) 18969800Stomsoft log_Printf(fp->LogLevel, " [EMPTY]\n"); 19069800Stomsoft break; 19169800Stomsoft } 19277885Stomsoft } 19369926Stomsoft 19469926Stomsoft plen = sizeof(struct fsmheader) + count; 19569926Stomsoft lh.code = code; 19669800Stomsoft lh.id = id; 19769800Stomsoft lh.length = htons(plen); 19877885Stomsoft bp = mbuf_Alloc(plen, MB_FSM); 19977885Stomsoft memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 20069800Stomsoft if (count) 20169800Stomsoft memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 20269800Stomsoft log_DumpBp(LogDEBUG, "fsm_Output", bp); 20369800Stomsoft hdlc_Output(fp->link, PRI_LINK, fp->proto, bp); 20469800Stomsoft} 20569800Stomsoft 20669800Stomsoftstatic void 20769800StomsoftFsmOpenNow(void *v) 20869800Stomsoft{ 20969800Stomsoft struct fsm *fp = (struct fsm *)v; 21077885Stomsoft 21177885Stomsoft timer_Stop(&fp->OpenTimer); 21269926Stomsoft if (fp->state <= ST_STOPPED) { 21369926Stomsoft if (fp->state != ST_STARTING) { 21469926Stomsoft /* 21569800Stomsoft * In practice, we're only here in ST_STOPPED (when delaying the 21669800Stomsoft * first config request) or ST_CLOSED (when openmode == 0). 21769800Stomsoft * 21869800Stomsoft * The ST_STOPPED bit is breaking the RFC already :-( 21969800Stomsoft * 22069800Stomsoft * According to the RFC (1661) state transition table, a TLS isn't 22169800Stomsoft * required for an Open event when state == Closed, but the RFC 22269800Stomsoft * must be wrong as TLS hasn't yet been called (since the last TLF) 22369800Stomsoft * ie, Initial gets an `Up' event, Closing gets a RTA etc. 22469800Stomsoft */ 22569800Stomsoft (*fp->fn->LayerStart)(fp); 226102231Strhodes (*fp->parent->LayerStart)(fp->parent->object, fp); 22769800Stomsoft } 22898542Smckusick FsmInitRestartCounter(fp); 22998542Smckusick FsmSendConfigReq(fp); 23069800Stomsoft NewState(fp, ST_REQSENT); 23198542Smckusick } 23298542Smckusick} 23398542Smckusick 23498542Smckusickvoid 23598542Smckusickfsm_Open(struct fsm * fp) 23698542Smckusick{ 23798542Smckusick switch (fp->state) { 23869800Stomsoft case ST_INITIAL: 23969800Stomsoft NewState(fp, ST_STARTING); 24069800Stomsoft (*fp->fn->LayerStart)(fp); 24169800Stomsoft (*fp->parent->LayerStart)(fp->parent->object, fp); 24269800Stomsoft break; 24369800Stomsoft case ST_CLOSED: 24469800Stomsoft if (fp->open_mode == OPEN_PASSIVE) { 24569800Stomsoft NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 24669800Stomsoft } else if (fp->open_mode > 0) { 24769800Stomsoft if (fp->open_mode > 1) 24869800Stomsoft log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 24969800Stomsoft fp->link->name, fp->open_mode); 25069800Stomsoft NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 25169800Stomsoft timer_Stop(&fp->OpenTimer); 25277885Stomsoft fp->OpenTimer.load = fp->open_mode * SECTICKS; 25377885Stomsoft fp->OpenTimer.func = FsmOpenNow; 25469800Stomsoft fp->OpenTimer.arg = (void *)fp; 25569800Stomsoft timer_Start(&fp->OpenTimer); 25669800Stomsoft } else 25769800Stomsoft FsmOpenNow(fp); 25869800Stomsoft break; 25969800Stomsoft case ST_STOPPED: /* XXX: restart option */ 26069800Stomsoft case ST_REQSENT: 26169800Stomsoft case ST_ACKRCVD: 26269800Stomsoft case ST_ACKSENT: 26369800Stomsoft case ST_OPENED: /* XXX: restart option */ 26469800Stomsoft break; 26569800Stomsoft case ST_CLOSING: /* XXX: restart option */ 26669800Stomsoft case ST_STOPPING: /* XXX: restart option */ 26769800Stomsoft NewState(fp, ST_STOPPING); 26869800Stomsoft break; 26969800Stomsoft } 27069800Stomsoft} 27169800Stomsoft 27269800Stomsoftvoid 27369800Stomsoftfsm_Up(struct fsm * fp) 27469800Stomsoft{ 27569800Stomsoft switch (fp->state) { 27677885Stomsoft case ST_INITIAL: 27777885Stomsoft log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 27869800Stomsoft fp->link->name); 27969800Stomsoft NewState(fp, ST_CLOSED); 28069800Stomsoft break; 28169800Stomsoft case ST_STARTING: 28269800Stomsoft FsmInitRestartCounter(fp); 28369800Stomsoft FsmSendConfigReq(fp); 28469800Stomsoft NewState(fp, ST_REQSENT); 28569800Stomsoft break; 28669800Stomsoft default: 28769800Stomsoft log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 28869800Stomsoft fp->link->name, State2Nam(fp->state)); 28977885Stomsoft break; 29077885Stomsoft } 29169926Stomsoft} 29269926Stomsoft 29369926Stomsoftvoid 29469800Stomsoftfsm_Down(struct fsm *fp) 29569800Stomsoft{ 29669800Stomsoft switch (fp->state) { 29769800Stomsoft case ST_CLOSED: 29869800Stomsoft NewState(fp, ST_INITIAL); 29969800Stomsoft break; 30069800Stomsoft case ST_CLOSING: 30169800Stomsoft (*fp->fn->LayerFinish)(fp); 30298542Smckusick NewState(fp, ST_INITIAL); 30369800Stomsoft (*fp->parent->LayerFinish)(fp->parent->object, fp); 30469926Stomsoft break; 30569926Stomsoft case ST_STOPPED: 30669800Stomsoft NewState(fp, ST_STARTING); 30769800Stomsoft (*fp->fn->LayerStart)(fp); 30869800Stomsoft (*fp->parent->LayerStart)(fp->parent->object, fp); 30969800Stomsoft break; 31069800Stomsoft case ST_STOPPING: 31169800Stomsoft case ST_REQSENT: 31269800Stomsoft case ST_ACKRCVD: 31369800Stomsoft case ST_ACKSENT: 31469800Stomsoft NewState(fp, ST_STARTING); 31569800Stomsoft break; 31669800Stomsoft case ST_OPENED: 31769800Stomsoft (*fp->fn->LayerDown)(fp); 31869800Stomsoft NewState(fp, ST_STARTING); 31969800Stomsoft (*fp->parent->LayerDown)(fp->parent->object, fp); 320114067Sschweikh break; 32169800Stomsoft } 32269800Stomsoft} 32369800Stomsoft 32469800Stomsoftvoid 32569800Stomsoftfsm_Close(struct fsm *fp) 32669800Stomsoft{ 32769800Stomsoft switch (fp->state) { 32869800Stomsoft case ST_STARTING: 32969800Stomsoft (*fp->fn->LayerFinish)(fp); 33069800Stomsoft NewState(fp, ST_INITIAL); 33169800Stomsoft (*fp->parent->LayerFinish)(fp->parent->object, fp); 332114067Sschweikh break; 33369800Stomsoft case ST_STOPPED: 33469800Stomsoft NewState(fp, ST_CLOSED); 335114067Sschweikh break; 33669800Stomsoft case ST_STOPPING: 33769800Stomsoft NewState(fp, ST_CLOSING); 33869800Stomsoft break; 33969800Stomsoft case ST_OPENED: 34069800Stomsoft (*fp->fn->LayerDown)(fp); 34169800Stomsoft FsmInitRestartCounter(fp); 34269800Stomsoft FsmSendTerminateReq(fp); 34369800Stomsoft NewState(fp, ST_CLOSING); 34498542Smckusick (*fp->parent->LayerDown)(fp->parent->object, fp); 34569800Stomsoft break; 34669800Stomsoft case ST_REQSENT: 34769926Stomsoft case ST_ACKRCVD: 34869926Stomsoft case ST_ACKSENT: 34969800Stomsoft FsmInitRestartCounter(fp); 35069800Stomsoft FsmSendTerminateReq(fp); 35169800Stomsoft NewState(fp, ST_CLOSING); 35269800Stomsoft break; 35369800Stomsoft } 35469800Stomsoft} 35569800Stomsoft 356114067Sschweikh/* 357114067Sschweikh * Send functions 358114067Sschweikh */ 35969800Stomsoftstatic void 36069800StomsoftFsmSendConfigReq(struct fsm * fp) 36169800Stomsoft{ 36277885Stomsoft if (--fp->maxconfig > 0) { 36369800Stomsoft (*fp->fn->SendConfigReq)(fp); 36469800Stomsoft timer_Start(&fp->FsmTimer); /* Start restart timer */ 36598542Smckusick fp->restart--; /* Decrement restart counter */ 36698542Smckusick } else { 36798542Smckusick fsm_Close(fp); 36898542Smckusick } 36998542Smckusick} 37092806Sobrien 37169800Stomsoftstatic void 37298542SmckusickFsmSendTerminateReq(struct fsm *fp) 37398542Smckusick{ 37498542Smckusick fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0); 37569800Stomsoft (*fp->fn->SentTerminateReq)(fp); 37669800Stomsoft timer_Start(&fp->FsmTimer); /* Start restart timer */ 37798542Smckusick fp->restart--; /* Decrement restart counter */ 37898542Smckusick} 37969800Stomsoft 38069800Stomsoft/* 38169800Stomsoft * Timeout actions 38298542Smckusick */ 38369800Stomsoftstatic void 38469800StomsoftFsmTimeout(void *v) 38569800Stomsoft{ 38698542Smckusick struct fsm *fp = (struct fsm *)v; 38769800Stomsoft 38898542Smckusick if (fp->restart) { 38998542Smckusick switch (fp->state) { 39069800Stomsoft case ST_CLOSING: 39169800Stomsoft case ST_STOPPING: 39269800Stomsoft FsmSendTerminateReq(fp); 39369800Stomsoft break; 39498542Smckusick case ST_REQSENT: 39569800Stomsoft case ST_ACKSENT: 39698542Smckusick FsmSendConfigReq(fp); 39769800Stomsoft break; 39898542Smckusick case ST_ACKRCVD: 39998542Smckusick FsmSendConfigReq(fp); 40098542Smckusick NewState(fp, ST_REQSENT); 40198542Smckusick break; 40298542Smckusick } 40398542Smckusick timer_Start(&fp->FsmTimer); 40498542Smckusick } else { 40598542Smckusick switch (fp->state) { 40698542Smckusick case ST_CLOSING: 40798542Smckusick (*fp->fn->LayerFinish)(fp); 40898542Smckusick NewState(fp, ST_CLOSED); 40998542Smckusick (*fp->parent->LayerFinish)(fp->parent->object, fp); 41098542Smckusick break; 41198542Smckusick case ST_STOPPING: 41298542Smckusick (*fp->fn->LayerFinish)(fp); 41369800Stomsoft NewState(fp, ST_STOPPED); 414103949Smike (*fp->parent->LayerFinish)(fp->parent->object, fp); 415103949Smike break; 41698542Smckusick case ST_REQSENT: /* XXX: 3p */ 41769800Stomsoft case ST_ACKSENT: 41898542Smckusick case ST_ACKRCVD: 41998542Smckusick (*fp->fn->LayerFinish)(fp); 42069800Stomsoft NewState(fp, ST_STOPPED); 42169800Stomsoft (*fp->parent->LayerFinish)(fp->parent->object, fp); 42298542Smckusick break; 423103949Smike } 42469800Stomsoft } 42598542Smckusick} 42669800Stomsoft 42798542Smckusickstatic void 428102231StrhodesFsmInitRestartCounter(struct fsm * fp) 42969800Stomsoft{ 43069926Stomsoft timer_Stop(&fp->FsmTimer); 43169800Stomsoft fp->FsmTimer.func = FsmTimeout; 43269800Stomsoft fp->FsmTimer.arg = (void *) fp; 43369800Stomsoft (*fp->fn->InitRestartCounter)(fp); 43498542Smckusick} 43569800Stomsoft 43669800Stomsoft/* 43769800Stomsoft * Actions when receive packets 43898542Smckusick */ 43969800Stomsoftstatic void 44098542SmckusickFsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 44198542Smckusick/* RCR */ 44269800Stomsoft{ 44398542Smckusick struct fsm_decode dec; 44498542Smckusick int plen, flen; 44598542Smckusick int ackaction = 0; 44698542Smckusick 44798542Smckusick plen = mbuf_Length(bp); 44898542Smckusick flen = ntohs(lhp->length) - sizeof *lhp; 44998542Smckusick if (plen < flen) { 45098542Smckusick log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 45169800Stomsoft fp->link->name, plen, flen); 45269800Stomsoft mbuf_Free(bp); 45398542Smckusick return; 45469800Stomsoft } 45598542Smckusick 45698542Smckusick /* 45798542Smckusick * Check and process easy case 45898542Smckusick */ 45998542Smckusick switch (fp->state) { 46098542Smckusick case ST_INITIAL: 46198542Smckusick case ST_STARTING: 46298542Smckusick log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 46398542Smckusick fp->link->name, State2Nam(fp->state)); 46498542Smckusick mbuf_Free(bp); 46598542Smckusick return; 46669800Stomsoft case ST_CLOSED: 46798542Smckusick (*fp->fn->SendTerminateAck)(fp, lhp->id); 46869800Stomsoft mbuf_Free(bp); 46969800Stomsoft return; 47069800Stomsoft case ST_CLOSING: 47169800Stomsoft log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 47269800Stomsoft fp->link->name, State2Nam(fp->state)); 47369800Stomsoft case ST_STOPPING: 47469800Stomsoft mbuf_Free(bp); 47569800Stomsoft return; 47669800Stomsoft } 47798542Smckusick 47898542Smckusick dec.ackend = dec.ack; 47969800Stomsoft dec.nakend = dec.nak; 48069800Stomsoft dec.rejend = dec.rej; 48198542Smckusick (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec); 48269800Stomsoft if (flen < sizeof(struct fsmconfig)) 48369800Stomsoft log_Printf(fp->LogLevel, " [EMPTY]\n"); 48469800Stomsoft 48598542Smckusick if (dec.nakend == dec.nak && dec.rejend == dec.rej) 48698542Smckusick ackaction = 1; 48798542Smckusick 48869800Stomsoft switch (fp->state) { 48969800Stomsoft case ST_OPENED: 49069800Stomsoft (*fp->fn->LayerDown)(fp); 49169800Stomsoft FsmSendConfigReq(fp); 49269800Stomsoft (*fp->parent->LayerDown)(fp->parent->object, fp); 49398542Smckusick break; 49498542Smckusick case ST_STOPPED: 49598542Smckusick FsmInitRestartCounter(fp); 49698542Smckusick FsmSendConfigReq(fp); 49798542Smckusick break; 49869800Stomsoft } 49969800Stomsoft 50098542Smckusick if (dec.rejend != dec.rej) 50169800Stomsoft fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej); 50298542Smckusick if (dec.nakend != dec.nak) 50398542Smckusick fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak); 50469800Stomsoft if (ackaction) 50569800Stomsoft fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack); 50669800Stomsoft 50769800Stomsoft switch (fp->state) { 508103949Smike case ST_OPENED: 50969800Stomsoft case ST_STOPPED: 51098542Smckusick if (ackaction) 51169800Stomsoft NewState(fp, ST_ACKSENT); 51269800Stomsoft else 51369800Stomsoft NewState(fp, ST_REQSENT); 51469800Stomsoft break; 51569800Stomsoft case ST_REQSENT: 51698542Smckusick if (ackaction) 51769800Stomsoft NewState(fp, ST_ACKSENT); 51869800Stomsoft break; 51969800Stomsoft case ST_ACKRCVD: 52069800Stomsoft if (ackaction) { 52169800Stomsoft NewState(fp, ST_OPENED); 52269800Stomsoft if ((*fp->fn->LayerUp)(fp)) 52369800Stomsoft (*fp->parent->LayerUp)(fp->parent->object, fp); 52469800Stomsoft else { 52569800Stomsoft (*fp->fn->LayerDown)(fp); 52669800Stomsoft FsmInitRestartCounter(fp); 52798542Smckusick FsmSendTerminateReq(fp); 52869926Stomsoft NewState(fp, ST_CLOSING); 52969926Stomsoft } 53069926Stomsoft } 53169800Stomsoft break; 53269800Stomsoft case ST_ACKSENT: 53369800Stomsoft if (!ackaction) 53469800Stomsoft NewState(fp, ST_REQSENT); 53569800Stomsoft break; 53669800Stomsoft } 53769800Stomsoft mbuf_Free(bp); 538114067Sschweikh} 53969800Stomsoft 540114067Sschweikhstatic void 541108470SschweikhFsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 54269800Stomsoft/* RCA */ 54369800Stomsoft{ 54498542Smckusick switch (fp->state) { 54569800Stomsoft case ST_CLOSED: 54669800Stomsoft case ST_STOPPED: 54769800Stomsoft (*fp->fn->SendTerminateAck)(fp, lhp->id); 54869800Stomsoft break; 54969800Stomsoft case ST_CLOSING: 55069800Stomsoft case ST_STOPPING: 55169800Stomsoft break; 55269800Stomsoft case ST_REQSENT: 55369800Stomsoft FsmInitRestartCounter(fp); 55469800Stomsoft NewState(fp, ST_ACKRCVD); 55569800Stomsoft break; 55669800Stomsoft case ST_ACKRCVD: 557114067Sschweikh FsmSendConfigReq(fp); 55869800Stomsoft NewState(fp, ST_REQSENT); 55969800Stomsoft break; 56069800Stomsoft case ST_ACKSENT: 561114067Sschweikh FsmInitRestartCounter(fp); 56269800Stomsoft NewState(fp, ST_OPENED); 56369800Stomsoft if ((*fp->fn->LayerUp)(fp)) 56469800Stomsoft (*fp->parent->LayerUp)(fp->parent->object, fp); 56569800Stomsoft else { 56669800Stomsoft (*fp->fn->LayerDown)(fp); 56769800Stomsoft FsmInitRestartCounter(fp); 56869800Stomsoft FsmSendTerminateReq(fp); 56969800Stomsoft NewState(fp, ST_CLOSING); 57069800Stomsoft } 57169926Stomsoft break; 57269926Stomsoft case ST_OPENED: 57369926Stomsoft (*fp->fn->LayerDown)(fp); 57469800Stomsoft FsmSendConfigReq(fp); 57569800Stomsoft NewState(fp, ST_REQSENT); 57669800Stomsoft (*fp->parent->LayerDown)(fp->parent->object, fp); 57769800Stomsoft break; 57869800Stomsoft } 57969800Stomsoft mbuf_Free(bp); 58069800Stomsoft} 58169800Stomsoft 58269800Stomsoftstatic void 58369926StomsoftFsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 58469926Stomsoft/* RCN */ 58569926Stomsoft{ 58669800Stomsoft struct fsm_decode dec; 58769926Stomsoft int plen, flen; 58869926Stomsoft 58969926Stomsoft plen = mbuf_Length(bp); 59069800Stomsoft flen = ntohs(lhp->length) - sizeof *lhp; 59169800Stomsoft if (plen < flen) { 59269800Stomsoft mbuf_Free(bp); 59369800Stomsoft return; 59469800Stomsoft } 59569800Stomsoft 59669800Stomsoft /* 59769800Stomsoft * Check and process easy case 598114067Sschweikh */ 599114067Sschweikh switch (fp->state) { 600114067Sschweikh case ST_INITIAL: 60169800Stomsoft case ST_STARTING: 60269800Stomsoft log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 60369800Stomsoft fp->link->name, State2Nam(fp->state)); 60498542Smckusick mbuf_Free(bp); 60598542Smckusick return; 60698542Smckusick case ST_CLOSED: 60769800Stomsoft case ST_STOPPED: 60869800Stomsoft (*fp->fn->SendTerminateAck)(fp, lhp->id); 60998542Smckusick mbuf_Free(bp); 61098542Smckusick return; 61198542Smckusick case ST_CLOSING: 61298542Smckusick case ST_STOPPING: 61369800Stomsoft mbuf_Free(bp); 61469800Stomsoft return; 61569800Stomsoft } 61698542Smckusick 61798542Smckusick dec.ackend = dec.ack; 61898542Smckusick dec.nakend = dec.nak; 61998542Smckusick dec.rejend = dec.rej; 62098542Smckusick (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); 62198542Smckusick if (flen < sizeof(struct fsmconfig)) 62298542Smckusick log_Printf(fp->LogLevel, " [EMPTY]\n"); 62398542Smckusick 62498542Smckusick switch (fp->state) { 62598542Smckusick case ST_REQSENT: 62698542Smckusick case ST_ACKSENT: 62798542Smckusick FsmInitRestartCounter(fp); 62898542Smckusick FsmSendConfigReq(fp); 62998542Smckusick break; 63098542Smckusick case ST_OPENED: 63198542Smckusick (*fp->fn->LayerDown)(fp); 63269800Stomsoft FsmSendConfigReq(fp); 63398542Smckusick NewState(fp, ST_REQSENT); 63498542Smckusick (*fp->parent->LayerDown)(fp->parent->object, fp); 63598542Smckusick break; 63698542Smckusick case ST_ACKRCVD: 63798542Smckusick FsmSendConfigReq(fp); 63898542Smckusick NewState(fp, ST_REQSENT); 63998542Smckusick break; 64098542Smckusick } 64198542Smckusick 64298542Smckusick mbuf_Free(bp); 64398542Smckusick} 64498542Smckusick 64598542Smckusickstatic void 64698542SmckusickFsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 64798542Smckusick/* RTR */ 64898542Smckusick{ 64998542Smckusick switch (fp->state) { 65098542Smckusick case ST_INITIAL: 65169800Stomsoft case ST_STARTING: 65269800Stomsoft log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 65369800Stomsoft fp->link->name, State2Nam(fp->state)); 65498542Smckusick break; 65569800Stomsoft case ST_CLOSED: 65669800Stomsoft case ST_STOPPED: 65769800Stomsoft case ST_CLOSING: 65869800Stomsoft case ST_STOPPING: 65969800Stomsoft case ST_REQSENT: 660114067Sschweikh (*fp->fn->SendTerminateAck)(fp, lhp->id); 661114067Sschweikh break; 662114067Sschweikh case ST_ACKRCVD: 66369800Stomsoft case ST_ACKSENT: 664114067Sschweikh (*fp->fn->SendTerminateAck)(fp, lhp->id); 665114067Sschweikh NewState(fp, ST_REQSENT); 666114067Sschweikh break; 66769800Stomsoft case ST_OPENED: 66869800Stomsoft (*fp->fn->LayerDown)(fp); 66969800Stomsoft (*fp->fn->SendTerminateAck)(fp, lhp->id); 67077885Stomsoft FsmInitRestartCounter(fp); 67169800Stomsoft timer_Start(&fp->FsmTimer); /* Start restart timer */ 67269800Stomsoft fp->restart = 0; 67398542Smckusick NewState(fp, ST_STOPPING); 67469800Stomsoft (*fp->parent->LayerDown)(fp->parent->object, fp); 67569800Stomsoft break; 67669800Stomsoft } 67769800Stomsoft mbuf_Free(bp); 67869800Stomsoft} 67969800Stomsoft 68069800Stomsoftstatic void 68169800StomsoftFsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 68269800Stomsoft/* RTA */ 68369800Stomsoft{ 68477885Stomsoft switch (fp->state) { 68577885Stomsoft case ST_CLOSING: 68669800Stomsoft (*fp->fn->LayerFinish)(fp); 68769926Stomsoft NewState(fp, ST_CLOSED); 68869926Stomsoft (*fp->parent->LayerFinish)(fp->parent->object, fp); 68969926Stomsoft break; 69069800Stomsoft case ST_STOPPING: 69169800Stomsoft (*fp->fn->LayerFinish)(fp); 69269800Stomsoft NewState(fp, ST_STOPPED); 69369800Stomsoft (*fp->parent->LayerFinish)(fp->parent->object, fp); 694114067Sschweikh break; 69569800Stomsoft case ST_ACKRCVD: 69669800Stomsoft NewState(fp, ST_REQSENT); 697114067Sschweikh break; 69869800Stomsoft case ST_OPENED: 699114067Sschweikh (*fp->fn->LayerDown)(fp); 70069800Stomsoft FsmSendConfigReq(fp); 70169800Stomsoft NewState(fp, ST_REQSENT); 70298542Smckusick (*fp->parent->LayerDown)(fp->parent->object, fp); 70398542Smckusick break; 70469800Stomsoft } 70577885Stomsoft mbuf_Free(bp); 70677885Stomsoft} 70769800Stomsoft 70869926Stomsoftstatic void 70969926StomsoftFsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 71069926Stomsoft/* RCJ */ 71169800Stomsoft{ 71269800Stomsoft struct fsm_decode dec; 71369800Stomsoft int plen, flen; 71469800Stomsoft 71569800Stomsoft plen = mbuf_Length(bp); 71669800Stomsoft flen = ntohs(lhp->length) - sizeof *lhp; 71769800Stomsoft if (plen < flen) { 71869800Stomsoft mbuf_Free(bp); 71969800Stomsoft return; 72069800Stomsoft } 72169800Stomsoft 72269800Stomsoft /* 72369800Stomsoft * Check and process easy case 72477885Stomsoft */ 72569800Stomsoft switch (fp->state) { 72669800Stomsoft case ST_INITIAL: 72769800Stomsoft case ST_STARTING: 72869800Stomsoft log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 72969800Stomsoft fp->link->name, State2Nam(fp->state)); 73069800Stomsoft mbuf_Free(bp); 73169800Stomsoft return; 73269800Stomsoft case ST_CLOSED: 73369800Stomsoft case ST_STOPPED: 73469800Stomsoft (*fp->fn->SendTerminateAck)(fp, lhp->id); 73569800Stomsoft mbuf_Free(bp); 73669800Stomsoft return; 73769800Stomsoft case ST_CLOSING: 73869800Stomsoft case ST_STOPPING: 73969800Stomsoft mbuf_Free(bp); 74069800Stomsoft return; 74169800Stomsoft } 74298542Smckusick 74398542Smckusick dec.ackend = dec.ack; 74498542Smckusick dec.nakend = dec.nak; 74569800Stomsoft dec.rejend = dec.rej; 74698542Smckusick (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); 74769800Stomsoft if (flen < sizeof(struct fsmconfig)) 74898542Smckusick log_Printf(fp->LogLevel, " [EMPTY]\n"); 74969926Stomsoft 75098542Smckusick switch (fp->state) { 75198542Smckusick case ST_REQSENT: 75298542Smckusick case ST_ACKSENT: 75398542Smckusick FsmInitRestartCounter(fp); 75498542Smckusick FsmSendConfigReq(fp); 75598542Smckusick break; 75669800Stomsoft case ST_OPENED: 75769800Stomsoft (*fp->fn->LayerDown)(fp); 75869800Stomsoft FsmSendConfigReq(fp); 75969800Stomsoft NewState(fp, ST_REQSENT); 76069800Stomsoft (*fp->parent->LayerDown)(fp->parent->object, fp); 76169800Stomsoft break; 76269800Stomsoft case ST_ACKRCVD: 763114067Sschweikh FsmSendConfigReq(fp); 764114067Sschweikh NewState(fp, ST_REQSENT); 765114067Sschweikh break; 766114067Sschweikh } 767114067Sschweikh mbuf_Free(bp); 768102231Strhodes} 76969800Stomsoft 77069800Stomsoftstatic void 77169800StomsoftFsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 77269800Stomsoft{ 77369800Stomsoft mbuf_Free(bp); 77469800Stomsoft} 77569800Stomsoft 77669800Stomsoftstatic void 77769800StomsoftFsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 77869800Stomsoft{ 77969800Stomsoft struct physical *p = link2physical(fp->link); 78069800Stomsoft u_short *sp, proto; 78169800Stomsoft 78269800Stomsoft sp = (u_short *)MBUF_CTOP(bp); 78369800Stomsoft proto = ntohs(*sp); 78469800Stomsoft log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 78569800Stomsoft fp->link->name, proto, hdlc_Protocol2Nam(proto)); 78669800Stomsoft 78769800Stomsoft switch (proto) { 78869800Stomsoft case PROTO_LQR: 78969800Stomsoft if (p) 790114067Sschweikh lqr_Stop(p, LQM_LQR); 79169800Stomsoft else 792102231Strhodes log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 79369800Stomsoft fp->link->name); 79469800Stomsoft break; 79569800Stomsoft case PROTO_CCP: 79669800Stomsoft if (fp->proto == PROTO_LCP) { 79769800Stomsoft fp = &fp->link->ccp.fsm; 798114067Sschweikh (*fp->fn->LayerFinish)(fp); 79969800Stomsoft switch (fp->state) { 80069800Stomsoft case ST_CLOSED: 80169800Stomsoft case ST_CLOSING: 80269800Stomsoft NewState(fp, ST_CLOSED); 80369800Stomsoft default: 80469800Stomsoft NewState(fp, ST_STOPPED); 80569800Stomsoft break; 80669800Stomsoft } 80769800Stomsoft (*fp->parent->LayerFinish)(fp->parent->object, fp); 80869800Stomsoft } 80969800Stomsoft break; 81069800Stomsoft case PROTO_MP: 81169800Stomsoft if (fp->proto == PROTO_LCP) { 81269800Stomsoft struct lcp *lcp = fsm2lcp(fp); 81369800Stomsoft 81469800Stomsoft if (lcp->want_mrru && lcp->his_mrru) { 81569800Stomsoft log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 81669800Stomsoft fp->link->name); 81769800Stomsoft fsm_Close(fp); 81869800Stomsoft } 81969800Stomsoft } 82069800Stomsoft break; 82169800Stomsoft } 82269800Stomsoft mbuf_Free(bp); 82369800Stomsoft} 82469800Stomsoft 82569800Stomsoftstatic void 82669800StomsoftFsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 82769800Stomsoft{ 82869800Stomsoft struct lcp *lcp = fsm2lcp(fp); 82969800Stomsoft u_char *cp; 83069800Stomsoft u_int32_t magic; 83169800Stomsoft 83269800Stomsoft if (lcp) { 83369800Stomsoft cp = MBUF_CTOP(bp); 83469800Stomsoft magic = ntohl(*(u_int32_t *)cp); 83569800Stomsoft if (magic != lcp->his_magic) { 83669800Stomsoft log_Printf(fp->LogLevel, "%s: RecvEchoReq: Error: His magic is bad!!\n", 83769800Stomsoft fp->link->name); 83869800Stomsoft /* XXX: We should send terminate request */ 83969800Stomsoft } 84069800Stomsoft if (fp->state == ST_OPENED) { 84169800Stomsoft *(u_int32_t *)cp = htonl(lcp->want_magic); /* local magic */ 84269800Stomsoft fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, mbuf_Length(bp)); 84369800Stomsoft } 84469800Stomsoft } 84569800Stomsoft mbuf_Free(bp); 84669800Stomsoft} 84769800Stomsoft 84869800Stomsoftstatic void 84969800StomsoftFsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 85069800Stomsoft{ 85169800Stomsoft struct lcp *lcp = fsm2lcp(fp); 85269800Stomsoft u_int32_t magic; 85369800Stomsoft 85469800Stomsoft if (lcp) { 85569800Stomsoft magic = ntohl(*(u_int32_t *)MBUF_CTOP(bp)); 85669800Stomsoft /* Tolerate echo replies with either magic number */ 85769800Stomsoft if (magic != 0 && magic != lcp->his_magic && magic != lcp->want_magic) { 85869800Stomsoft log_Printf(LogWARN, 85969800Stomsoft "%s: RecvEchoRep: Bad magic: expected 0x%08x, got: 0x%08x\n", 86069800Stomsoft fp->link->name, lcp->his_magic, magic); 86169800Stomsoft /* 86269800Stomsoft * XXX: We should send terminate request. But poor implementations may 86369800Stomsoft * die as a result. 86469800Stomsoft */ 86569800Stomsoft } 86669800Stomsoft lqr_RecvEcho(fp, bp); 867114067Sschweikh } 86869800Stomsoft mbuf_Free(bp); 86969800Stomsoft} 87069800Stomsoft 87169800Stomsoftstatic void 87269800StomsoftFsmRecvDiscReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 87369800Stomsoft{ 87469800Stomsoft mbuf_Free(bp); 87569800Stomsoft} 87669800Stomsoft 87769800Stomsoftstatic void 87869800StomsoftFsmRecvIdent(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 87969800Stomsoft{ 88069800Stomsoft mbuf_Free(bp); 88169800Stomsoft} 88269800Stomsoft 88369800Stomsoftstatic void 88469800StomsoftFsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 88569800Stomsoft{ 88669800Stomsoft mbuf_Free(bp); 88769800Stomsoft} 88869800Stomsoft 88969800Stomsoftstatic void 89069800StomsoftFsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 89169800Stomsoft{ 89269800Stomsoft (*fp->fn->RecvResetReq)(fp); 89369800Stomsoft /* 89477885Stomsoft * All sendable compressed packets are queued in the PRI_NORMAL modem 89577885Stomsoft * output queue.... dump 'em to the priority queue so that they arrive 89669800Stomsoft * at the peer before our ResetAck. 89769926Stomsoft */ 89869926Stomsoft link_SequenceQueue(fp->link); 89969926Stomsoft fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0); 90069800Stomsoft mbuf_Free(bp); 90169800Stomsoft} 90269800Stomsoft 90369800Stomsoftstatic void 90469800StomsoftFsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 90569800Stomsoft{ 90669800Stomsoft (*fp->fn->RecvResetAck)(fp, lhp->id); 907114067Sschweikh mbuf_Free(bp); 90869800Stomsoft} 909114067Sschweikh 91069800Stomsoftvoid 91169800Stomsoftfsm_Input(struct fsm *fp, struct mbuf *bp) 912114067Sschweikh{ 913114067Sschweikh int len; 914114067Sschweikh struct fsmheader *lhp; 91569800Stomsoft const struct fsmcodedesc *codep; 916114067Sschweikh 91769800Stomsoft len = mbuf_Length(bp); 918114067Sschweikh if (len < sizeof(struct fsmheader)) { 919114067Sschweikh mbuf_Free(bp); 92069800Stomsoft return; 92169800Stomsoft } 92269800Stomsoft lhp = (struct fsmheader *) MBUF_CTOP(bp); 92377885Stomsoft if (lhp->code < fp->min_code || lhp->code > fp->max_code || 92469800Stomsoft lhp->code > sizeof FsmCodes / sizeof *FsmCodes) { 92569800Stomsoft /* 92669800Stomsoft * Use a private id. This is really a response-type packet, but we 92769800Stomsoft * MUST send a unique id for each REQ.... 92869800Stomsoft */ 92998542Smckusick static u_char id; 93069800Stomsoft 93169800Stomsoft fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->cnt); 93269800Stomsoft mbuf_Free(bp); 93369800Stomsoft return; 93469800Stomsoft } 93569800Stomsoft bp->offset += sizeof(struct fsmheader); 93669800Stomsoft bp->cnt -= sizeof(struct fsmheader); 93769800Stomsoft 93869800Stomsoft codep = FsmCodes + lhp->code - 1; 93969800Stomsoft if (lhp->id != fp->reqid && codep->check_reqid && 94069800Stomsoft Enabled(fp->bundle, OPT_IDCHECK)) { 94169800Stomsoft log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 94269800Stomsoft fp->link->name, codep->name, lhp->id, fp->reqid); 94369800Stomsoft return; 94469800Stomsoft } 94569800Stomsoft 94669800Stomsoft log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 94769800Stomsoft fp->link->name, codep->name, lhp->id, State2Nam(fp->state)); 94869800Stomsoft 94969800Stomsoft if (log_IsKept(LogDEBUG)) 95069800Stomsoft mbuf_Log(); 95169800Stomsoft 95269800Stomsoft if (codep->inc_reqid && (lhp->id == fp->reqid || 95369800Stomsoft (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 95481311Schm fp->reqid++; /* That's the end of that ``exchange''.... */ 95581311Schm 95681311Schm (*codep->recv)(fp, lhp, bp); 95769800Stomsoft 95877885Stomsoft if (log_IsKept(LogDEBUG)) 95977885Stomsoft mbuf_Log(); 96069800Stomsoft} 96169926Stomsoft 96269926Stomsoftvoid 96369926Stomsoftfsm_NullRecvResetReq(struct fsm *fp) 96469800Stomsoft{ 96569800Stomsoft log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 96669800Stomsoft fp->link->name); 96769800Stomsoft} 96869800Stomsoft 96969800Stomsoftvoid 97069800Stomsoftfsm_NullRecvResetAck(struct fsm *fp, u_char id) 97169800Stomsoft{ 97269800Stomsoft log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 97369800Stomsoft fp->link->name); 97469800Stomsoft} 975114067Sschweikh 976114067Sschweikhvoid 97769800Stomsoftfsm_Reopen(struct fsm *fp) 97869800Stomsoft{ 97969800Stomsoft if (fp->state == ST_OPENED) { 98069800Stomsoft (*fp->fn->LayerDown)(fp); 981114067Sschweikh FsmInitRestartCounter(fp); 982114067Sschweikh FsmSendConfigReq(fp); 983114067Sschweikh NewState(fp, ST_REQSENT); 98469800Stomsoft (*fp->parent->LayerDown)(fp->parent->object, fp); 985114067Sschweikh } 986114067Sschweikh} 98769800Stomsoft 98869800Stomsoftvoid 989114067Sschweikhfsm2initial(struct fsm *fp) 990114067Sschweikh{ 991114067Sschweikh if (fp->state == ST_STOPPED) 99269800Stomsoft fsm_Close(fp); 993114067Sschweikh if (fp->state > ST_INITIAL) 99469800Stomsoft fsm_Down(fp); 995114067Sschweikh if (fp->state > ST_INITIAL) 99669800Stomsoft fsm_Close(fp); 99769800Stomsoft} 99869800Stomsoft