178189Sbrian/*- 278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 378189Sbrian * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 478189Sbrian * Internet Initiative Japan, Inc (IIJ) 578189Sbrian * All rights reserved. 66059Samurai * 778189Sbrian * Redistribution and use in source and binary forms, with or without 878189Sbrian * modification, are permitted provided that the following conditions 978189Sbrian * are met: 1078189Sbrian * 1. Redistributions of source code must retain the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer. 1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer in the 1478189Sbrian * documentation and/or other materials provided with the distribution. 156059Samurai * 1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1978189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2678189Sbrian * SUCH DAMAGE. 276059Samurai * 2850479Speter * $FreeBSD$ 296059Samurai */ 3036285Sbrian 3143313Sbrian#include <sys/param.h> 3230715Sbrian#include <netinet/in.h> 3336285Sbrian#include <netinet/in_systm.h> 3436285Sbrian#include <netinet/ip.h> 3581634Sbrian#include <sys/socket.h> 3636285Sbrian#include <sys/un.h> 3730715Sbrian 3830715Sbrian#include <string.h> 3930715Sbrian#include <termios.h> 4030715Sbrian 4146686Sbrian#include "layer.h" 4238814Sbrian#include "ua.h" 4330715Sbrian#include "mbuf.h" 4430715Sbrian#include "log.h" 4530715Sbrian#include "defs.h" 4630715Sbrian#include "timer.h" 476059Samurai#include "fsm.h" 4836285Sbrian#include "iplist.h" 4936285Sbrian#include "lqr.h" 506059Samurai#include "hdlc.h" 5136285Sbrian#include "throughput.h" 5236285Sbrian#include "slcompress.h" 5381634Sbrian#include "ncpaddr.h" 5436285Sbrian#include "ipcp.h" 5536285Sbrian#include "filter.h" 5636285Sbrian#include "descriptor.h" 576059Samurai#include "lcp.h" 5813389Sphk#include "ccp.h" 5936285Sbrian#include "link.h" 6036285Sbrian#include "mp.h" 6143313Sbrian#ifndef NORADIUS 6243313Sbrian#include "radius.h" 6343313Sbrian#endif 6481634Sbrian#include "ipv6cp.h" 6581634Sbrian#include "ncp.h" 6636285Sbrian#include "bundle.h" 6736285Sbrian#include "async.h" 6836285Sbrian#include "physical.h" 6946686Sbrian#include "proto.h" 706059Samurai 7130715Sbrianstatic void FsmSendConfigReq(struct fsm *); 7230715Sbrianstatic void FsmSendTerminateReq(struct fsm *); 7344305Sbrianstatic void FsmInitRestartCounter(struct fsm *, int); 7430715Sbrian 7536285Sbriantypedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *); 7636285Sbrianstatic recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak, 7736285Sbrian FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck, 7836285Sbrian FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq, 7936285Sbrian FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent, 8036285Sbrian FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck; 8136285Sbrian 8236285Sbrianstatic const struct fsmcodedesc { 8336285Sbrian recvfn *recv; 8436285Sbrian unsigned check_reqid : 1; 8536285Sbrian unsigned inc_reqid : 1; 8636285Sbrian const char *name; 8736285Sbrian} FsmCodes[] = { 8836285Sbrian { FsmRecvConfigReq, 0, 0, "ConfigReq" }, 8936285Sbrian { FsmRecvConfigAck, 1, 1, "ConfigAck" }, 9036285Sbrian { FsmRecvConfigNak, 1, 1, "ConfigNak" }, 9136285Sbrian { FsmRecvConfigRej, 1, 1, "ConfigRej" }, 9236285Sbrian { FsmRecvTermReq, 0, 0, "TerminateReq" }, 9336285Sbrian { FsmRecvTermAck, 1, 1, "TerminateAck" }, 9436285Sbrian { FsmRecvCodeRej, 0, 0, "CodeRej" }, 9536285Sbrian { FsmRecvProtoRej, 0, 0, "ProtocolRej" }, 9636285Sbrian { FsmRecvEchoReq, 0, 0, "EchoRequest" }, 9736285Sbrian { FsmRecvEchoRep, 0, 0, "EchoReply" }, 9836285Sbrian { FsmRecvDiscReq, 0, 0, "DiscardReq" }, 9963484Sbrian { FsmRecvIdent, 0, 1, "Ident" }, 10036285Sbrian { FsmRecvTimeRemain,0, 0, "TimeRemain" }, 10146686Sbrian { FsmRecvResetReq, 0, 0, "ResetReq" }, 10236285Sbrian { FsmRecvResetAck, 0, 1, "ResetAck" } 1036059Samurai}; 1046059Samurai 10536285Sbrianstatic const char * 10636285SbrianCode2Nam(u_int code) 10736285Sbrian{ 10836285Sbrian if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0]) 10936285Sbrian return "Unknown"; 11036285Sbrian return FsmCodes[code-1].name; 11136285Sbrian} 11236285Sbrian 11336285Sbrianconst char * 11436285SbrianState2Nam(u_int state) 11536285Sbrian{ 11655146Sbrian static const char * const StateNames[] = { 11736285Sbrian "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", 11836285Sbrian "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", 11936285Sbrian }; 12036285Sbrian 12136285Sbrian if (state >= sizeof StateNames / sizeof StateNames[0]) 12236285Sbrian return "unknown"; 12336285Sbrian return StateNames[state]; 12436285Sbrian} 12536285Sbrian 12628327Sbrianstatic void 12731343SbrianStoppedTimeout(void *v) 12828327Sbrian{ 12931343Sbrian struct fsm *fp = (struct fsm *)v; 13031343Sbrian 13136285Sbrian log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name); 13232658Sbrian if (fp->OpenTimer.state == TIMER_RUNNING) { 13336285Sbrian log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n", 13436285Sbrian fp->link->name, fp->name); 13536285Sbrian timer_Stop(&fp->OpenTimer); 13632658Sbrian } 13737060Sbrian if (fp->state == ST_STOPPED) 13837060Sbrian fsm2initial(fp); 13928327Sbrian} 14028327Sbrian 1416059Samuraivoid 14236285Sbrianfsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, 14344305Sbrian int maxcode, int LogLevel, struct bundle *bundle, 14436285Sbrian struct link *l, const struct fsm_parent *parent, 14555146Sbrian struct fsm_callbacks *fn, const char * const timer_names[3]) 1466059Samurai{ 14736285Sbrian fp->name = name; 14836285Sbrian fp->proto = proto; 14936285Sbrian fp->min_code = mincode; 15036285Sbrian fp->max_code = maxcode; 15136285Sbrian fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; 1526059Samurai fp->reqid = 1; 1536059Samurai fp->restart = 1; 15446686Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = 3; 15536285Sbrian memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); 15636285Sbrian memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); 15736285Sbrian memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); 15836285Sbrian fp->LogLevel = LogLevel; 15936285Sbrian fp->link = l; 16036285Sbrian fp->bundle = bundle; 16136285Sbrian fp->parent = parent; 16236285Sbrian fp->fn = fn; 16336285Sbrian fp->FsmTimer.name = timer_names[0]; 16436285Sbrian fp->OpenTimer.name = timer_names[1]; 16536285Sbrian fp->StoppedTimer.name = timer_names[2]; 1666059Samurai} 1676059Samurai 16830715Sbrianstatic void 16946828SbrianNewState(struct fsm *fp, int new) 1706059Samurai{ 17136285Sbrian log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", 17294894Sbrian fp->link->name, State2Nam(fp->state), State2Nam(new)); 17328461Sbrian if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) 17436285Sbrian timer_Stop(&fp->StoppedTimer); 1756059Samurai fp->state = new; 17628327Sbrian if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { 17736285Sbrian timer_Stop(&fp->FsmTimer); 17828461Sbrian if (new == ST_STOPPED && fp->StoppedTimer.load) { 17936285Sbrian timer_Stop(&fp->StoppedTimer); 18028461Sbrian fp->StoppedTimer.func = StoppedTimeout; 18128679Sbrian fp->StoppedTimer.arg = (void *) fp; 18236285Sbrian timer_Start(&fp->StoppedTimer); 18328327Sbrian } 18428327Sbrian } 1856059Samurai} 1866059Samurai 1876059Samuraivoid 188134789Sbrianfsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, unsigned count, 18947695Sbrian int mtype) 1906059Samurai{ 1916059Samurai int plen; 1926059Samurai struct fsmheader lh; 1936059Samurai struct mbuf *bp; 1946059Samurai 19536285Sbrian if (log_IsKept(fp->LogLevel)) { 19636285Sbrian log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 19736285Sbrian fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 19836285Sbrian switch (code) { 19936285Sbrian case CODE_CONFIGREQ: 20036285Sbrian case CODE_CONFIGACK: 20136285Sbrian case CODE_CONFIGREJ: 20236285Sbrian case CODE_CONFIGNAK: 20394894Sbrian (*fp->fn->DecodeConfig)(fp, ptr, ptr + count, MODE_NOP, NULL); 20494894Sbrian if (count < sizeof(struct fsm_opt_hdr)) 20536285Sbrian log_Printf(fp->LogLevel, " [EMPTY]\n"); 20636285Sbrian break; 20736285Sbrian } 20836285Sbrian } 20936285Sbrian 21028679Sbrian plen = sizeof(struct fsmheader) + count; 2116059Samurai lh.code = code; 2126059Samurai lh.id = id; 2136059Samurai lh.length = htons(plen); 21454912Sbrian bp = m_get(plen, mtype); 21530715Sbrian memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 2166059Samurai if (count) 21730715Sbrian memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 21836285Sbrian log_DumpBp(LogDEBUG, "fsm_Output", bp); 21950867Sbrian link_PushPacket(fp->link, bp, fp->bundle, LINK_QUEUES(fp->link) - 1, 22050867Sbrian fp->proto); 22163484Sbrian 22263484Sbrian if (code == CODE_CONFIGREJ) 22363484Sbrian lcp_SendIdentification(&fp->link->lcp); 2246059Samurai} 2256059Samurai 22632658Sbrianstatic void 22732658SbrianFsmOpenNow(void *v) 22832658Sbrian{ 22932658Sbrian struct fsm *fp = (struct fsm *)v; 23032658Sbrian 23136285Sbrian timer_Stop(&fp->OpenTimer); 23232658Sbrian if (fp->state <= ST_STOPPED) { 23337210Sbrian if (fp->state != ST_STARTING) { 23437210Sbrian /* 23537210Sbrian * In practice, we're only here in ST_STOPPED (when delaying the 23637210Sbrian * first config request) or ST_CLOSED (when openmode == 0). 23737210Sbrian * 23837210Sbrian * The ST_STOPPED bit is breaking the RFC already :-( 23937210Sbrian * 24037210Sbrian * According to the RFC (1661) state transition table, a TLS isn't 24137210Sbrian * required for an Open event when state == Closed, but the RFC 24237210Sbrian * must be wrong as TLS hasn't yet been called (since the last TLF) 24337210Sbrian * ie, Initial gets an `Up' event, Closing gets a RTA etc. 24437210Sbrian */ 24537210Sbrian (*fp->fn->LayerStart)(fp); 24637210Sbrian (*fp->parent->LayerStart)(fp->parent->object, fp); 24737210Sbrian } 24844305Sbrian FsmInitRestartCounter(fp, FSM_REQ_TIMER); 24932658Sbrian FsmSendConfigReq(fp); 25032658Sbrian NewState(fp, ST_REQSENT); 25132658Sbrian } 25232658Sbrian} 25332658Sbrian 2546059Samuraivoid 25546828Sbrianfsm_Open(struct fsm *fp) 2566059Samurai{ 2576059Samurai switch (fp->state) { 25836285Sbrian case ST_INITIAL: 2596059Samurai NewState(fp, ST_STARTING); 26036285Sbrian (*fp->fn->LayerStart)(fp); 26136285Sbrian (*fp->parent->LayerStart)(fp->parent->object, fp); 2626059Samurai break; 2636059Samurai case ST_CLOSED: 2646059Samurai if (fp->open_mode == OPEN_PASSIVE) { 26537210Sbrian NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 26632658Sbrian } else if (fp->open_mode > 0) { 26732658Sbrian if (fp->open_mode > 1) 26836285Sbrian log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 26936285Sbrian fp->link->name, fp->open_mode); 27037210Sbrian NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 27136285Sbrian timer_Stop(&fp->OpenTimer); 27232658Sbrian fp->OpenTimer.load = fp->open_mode * SECTICKS; 27332658Sbrian fp->OpenTimer.func = FsmOpenNow; 27432658Sbrian fp->OpenTimer.arg = (void *)fp; 27536285Sbrian timer_Start(&fp->OpenTimer); 27632658Sbrian } else 27732658Sbrian FsmOpenNow(fp); 2786059Samurai break; 27928679Sbrian case ST_STOPPED: /* XXX: restart option */ 2806059Samurai case ST_REQSENT: 2816059Samurai case ST_ACKRCVD: 2826059Samurai case ST_ACKSENT: 28328679Sbrian case ST_OPENED: /* XXX: restart option */ 2846059Samurai break; 28528679Sbrian case ST_CLOSING: /* XXX: restart option */ 28628679Sbrian case ST_STOPPING: /* XXX: restart option */ 2876059Samurai NewState(fp, ST_STOPPING); 2886059Samurai break; 2896059Samurai } 2906059Samurai} 2916059Samurai 2926059Samuraivoid 29346828Sbrianfsm_Up(struct fsm *fp) 2946059Samurai{ 2956059Samurai switch (fp->state) { 29637210Sbrian case ST_INITIAL: 29736285Sbrian log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 29836285Sbrian fp->link->name); 2996059Samurai NewState(fp, ST_CLOSED); 3006059Samurai break; 3016059Samurai case ST_STARTING: 30244305Sbrian FsmInitRestartCounter(fp, FSM_REQ_TIMER); 3036059Samurai FsmSendConfigReq(fp); 3046059Samurai NewState(fp, ST_REQSENT); 3056059Samurai break; 3066059Samurai default: 30736285Sbrian log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 30836285Sbrian fp->link->name, State2Nam(fp->state)); 3096059Samurai break; 3106059Samurai } 3116059Samurai} 3126059Samurai 3136059Samuraivoid 31436285Sbrianfsm_Down(struct fsm *fp) 3156059Samurai{ 3166059Samurai switch (fp->state) { 31736285Sbrian case ST_CLOSED: 3186059Samurai NewState(fp, ST_INITIAL); 3196059Samurai break; 32036285Sbrian case ST_CLOSING: 32144359Sbrian /* This TLF contradicts the RFC (1661), which ``misses it out'' ! */ 32236285Sbrian (*fp->fn->LayerFinish)(fp); 32336285Sbrian NewState(fp, ST_INITIAL); 32436285Sbrian (*fp->parent->LayerFinish)(fp->parent->object, fp); 32536285Sbrian break; 3266059Samurai case ST_STOPPED: 32736285Sbrian NewState(fp, ST_STARTING); 32836285Sbrian (*fp->fn->LayerStart)(fp); 32936285Sbrian (*fp->parent->LayerStart)(fp->parent->object, fp); 33036285Sbrian break; 3316059Samurai case ST_STOPPING: 3326059Samurai case ST_REQSENT: 3336059Samurai case ST_ACKRCVD: 3346059Samurai case ST_ACKSENT: 3356059Samurai NewState(fp, ST_STARTING); 3366059Samurai break; 3376059Samurai case ST_OPENED: 33836285Sbrian (*fp->fn->LayerDown)(fp); 3396059Samurai NewState(fp, ST_STARTING); 34036285Sbrian (*fp->parent->LayerDown)(fp->parent->object, fp); 3416059Samurai break; 3426059Samurai } 3436059Samurai} 3446059Samurai 3456059Samuraivoid 34636285Sbrianfsm_Close(struct fsm *fp) 3476059Samurai{ 3486059Samurai switch (fp->state) { 34936285Sbrian case ST_STARTING: 35036285Sbrian (*fp->fn->LayerFinish)(fp); 3516059Samurai NewState(fp, ST_INITIAL); 35236285Sbrian (*fp->parent->LayerFinish)(fp->parent->object, fp); 3536059Samurai break; 3546059Samurai case ST_STOPPED: 3556059Samurai NewState(fp, ST_CLOSED); 3566059Samurai break; 3576059Samurai case ST_STOPPING: 3586059Samurai NewState(fp, ST_CLOSING); 3596059Samurai break; 3606059Samurai case ST_OPENED: 36136285Sbrian (*fp->fn->LayerDown)(fp); 36271658Sbrian if (fp->state == ST_OPENED) { 36371658Sbrian FsmInitRestartCounter(fp, FSM_TRM_TIMER); 36471658Sbrian FsmSendTerminateReq(fp); 36571658Sbrian NewState(fp, ST_CLOSING); 36671658Sbrian (*fp->parent->LayerDown)(fp->parent->object, fp); 36771658Sbrian } 36836285Sbrian break; 3696059Samurai case ST_REQSENT: 3706059Samurai case ST_ACKRCVD: 3716059Samurai case ST_ACKSENT: 37244305Sbrian FsmInitRestartCounter(fp, FSM_TRM_TIMER); 3736059Samurai FsmSendTerminateReq(fp); 3746059Samurai NewState(fp, ST_CLOSING); 3756059Samurai break; 3766059Samurai } 3776059Samurai} 3786059Samurai 3796059Samurai/* 3806059Samurai * Send functions 3816059Samurai */ 38230715Sbrianstatic void 38346828SbrianFsmSendConfigReq(struct fsm *fp) 3846059Samurai{ 38544305Sbrian if (fp->more.reqs-- > 0 && fp->restart-- > 0) { 38636285Sbrian (*fp->fn->SendConfigReq)(fp); 38744305Sbrian timer_Start(&fp->FsmTimer); /* Start restart timer */ 3886059Samurai } else { 38944305Sbrian if (fp->more.reqs < 0) 39044305Sbrian log_Printf(LogPHASE, "%s: Too many %s REQs sent - abandoning " 39144305Sbrian "negotiation\n", fp->link->name, fp->name); 39263484Sbrian lcp_SendIdentification(&fp->link->lcp); 39336285Sbrian fsm_Close(fp); 3946059Samurai } 3956059Samurai} 3966059Samurai 39730715Sbrianstatic void 39836285SbrianFsmSendTerminateReq(struct fsm *fp) 3996059Samurai{ 40047695Sbrian fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0, MB_UNKNOWN); 40136285Sbrian (*fp->fn->SentTerminateReq)(fp); 40236285Sbrian timer_Start(&fp->FsmTimer); /* Start restart timer */ 4036059Samurai fp->restart--; /* Decrement restart counter */ 4046059Samurai} 4056059Samurai 4066059Samurai/* 4076059Samurai * Timeout actions 4086059Samurai */ 40930715Sbrianstatic void 41031343SbrianFsmTimeout(void *v) 4116059Samurai{ 41231343Sbrian struct fsm *fp = (struct fsm *)v; 41331343Sbrian 4146059Samurai if (fp->restart) { 4156059Samurai switch (fp->state) { 41636285Sbrian case ST_CLOSING: 41736285Sbrian case ST_STOPPING: 4186059Samurai FsmSendTerminateReq(fp); 4196059Samurai break; 4206059Samurai case ST_REQSENT: 4216059Samurai case ST_ACKSENT: 4226059Samurai FsmSendConfigReq(fp); 4236059Samurai break; 4246059Samurai case ST_ACKRCVD: 4256059Samurai FsmSendConfigReq(fp); 4266059Samurai NewState(fp, ST_REQSENT); 4276059Samurai break; 4286059Samurai } 42936285Sbrian timer_Start(&fp->FsmTimer); 4306059Samurai } else { 4316059Samurai switch (fp->state) { 4326059Samurai case ST_CLOSING: 43336285Sbrian (*fp->fn->LayerFinish)(fp); 4346059Samurai NewState(fp, ST_CLOSED); 43536285Sbrian (*fp->parent->LayerFinish)(fp->parent->object, fp); 4366059Samurai break; 4376059Samurai case ST_STOPPING: 43836285Sbrian (*fp->fn->LayerFinish)(fp); 4396059Samurai NewState(fp, ST_STOPPED); 44036285Sbrian (*fp->parent->LayerFinish)(fp->parent->object, fp); 4416059Samurai break; 4426059Samurai case ST_REQSENT: /* XXX: 3p */ 4436059Samurai case ST_ACKSENT: 4446059Samurai case ST_ACKRCVD: 44536285Sbrian (*fp->fn->LayerFinish)(fp); 4466059Samurai NewState(fp, ST_STOPPED); 44736285Sbrian (*fp->parent->LayerFinish)(fp->parent->object, fp); 4486059Samurai break; 4496059Samurai } 4506059Samurai } 4516059Samurai} 4526059Samurai 45330715Sbrianstatic void 45444305SbrianFsmInitRestartCounter(struct fsm *fp, int what) 4556059Samurai{ 45636285Sbrian timer_Stop(&fp->FsmTimer); 4576059Samurai fp->FsmTimer.func = FsmTimeout; 45844305Sbrian fp->FsmTimer.arg = (void *)fp; 45944305Sbrian (*fp->fn->InitRestartCounter)(fp, what); 4606059Samurai} 4616059Samurai 4626059Samurai/* 46346828Sbrian * Actions when receive packets 4646059Samurai */ 46530715Sbrianstatic void 46636285SbrianFsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 46728679Sbrian/* RCR */ 4686059Samurai{ 46936285Sbrian struct fsm_decode dec; 4706735Samurai int plen, flen; 4716059Samurai int ackaction = 0; 47294894Sbrian u_char *cp; 4738857Srgrimes 47494894Sbrian bp = m_pullup(bp); 47554912Sbrian plen = m_length(bp); 47631962Sbrian flen = ntohs(lhp->length) - sizeof *lhp; 4776735Samurai if (plen < flen) { 47837019Sbrian log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 47994894Sbrian fp->link->name, plen, flen); 48054912Sbrian m_freem(bp); 4816059Samurai return; 4826059Samurai } 4836059Samurai 48495872Sbrian /* Some things must be done before we Decode the packet */ 48595872Sbrian switch (fp->state) { 48695872Sbrian case ST_OPENED: 48795872Sbrian (*fp->fn->LayerDown)(fp); 48895872Sbrian } 48995872Sbrian 49094894Sbrian dec.ackend = dec.ack; 49194894Sbrian dec.nakend = dec.nak; 49294894Sbrian dec.rejend = dec.rej; 49394894Sbrian cp = MBUF_CTOP(bp); 49494894Sbrian (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_REQ, &dec); 495134789Sbrian if (flen < (int)sizeof(struct fsm_opt_hdr)) 49694894Sbrian log_Printf(fp->LogLevel, " [EMPTY]\n"); 49794894Sbrian 49894894Sbrian if (dec.nakend == dec.nak && dec.rejend == dec.rej) 49994894Sbrian ackaction = 1; 50094894Sbrian 50146828Sbrian /* Check and process easy case */ 5026059Samurai switch (fp->state) { 5036059Samurai case ST_INITIAL: 50437320Sbrian if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 50537320Sbrian /* 50637320Sbrian * ccp_SetOpenMode() leaves us in initial if we're disabling 50746686Sbrian * & denying everything. 50837320Sbrian */ 50954912Sbrian bp = m_prepend(bp, lhp, sizeof *lhp, 2); 51046686Sbrian bp = proto_Prepend(bp, fp->proto, 0, 0); 51154912Sbrian bp = m_pullup(bp); 51254912Sbrian lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->m_len); 51354912Sbrian m_freem(bp); 51437320Sbrian return; 51537320Sbrian } 51637320Sbrian /* Drop through */ 5176059Samurai case ST_STARTING: 51836285Sbrian log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 51936285Sbrian fp->link->name, State2Nam(fp->state)); 52054912Sbrian m_freem(bp); 5216059Samurai return; 5226059Samurai case ST_CLOSED: 52336285Sbrian (*fp->fn->SendTerminateAck)(fp, lhp->id); 52454912Sbrian m_freem(bp); 5256059Samurai return; 5266059Samurai case ST_CLOSING: 52736285Sbrian log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 52836285Sbrian fp->link->name, State2Nam(fp->state)); 5296059Samurai case ST_STOPPING: 53054912Sbrian m_freem(bp); 5316059Samurai return; 5326059Samurai case ST_STOPPED: 53344305Sbrian FsmInitRestartCounter(fp, FSM_REQ_TIMER); 53495872Sbrian /* Drop through */ 53537995Sbrian case ST_OPENED: 5366059Samurai FsmSendConfigReq(fp); 5376059Samurai break; 5386059Samurai } 5396059Samurai 54036285Sbrian if (dec.rejend != dec.rej) 54147695Sbrian fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej, 54247695Sbrian MB_UNKNOWN); 54336285Sbrian if (dec.nakend != dec.nak) 54447695Sbrian fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak, 54547695Sbrian MB_UNKNOWN); 5466059Samurai if (ackaction) 54747695Sbrian fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack, 54847695Sbrian MB_UNKNOWN); 5496059Samurai 5506059Samurai switch (fp->state) { 55144305Sbrian case ST_STOPPED: 55244305Sbrian /* 55344305Sbrian * According to the RFC (1661) state transition table, a TLS isn't 55444305Sbrian * required for a RCR when state == ST_STOPPED, but the RFC 55544305Sbrian * must be wrong as TLS hasn't yet been called (since the last TLF) 55644305Sbrian */ 55744305Sbrian (*fp->fn->LayerStart)(fp); 55844305Sbrian (*fp->parent->LayerStart)(fp->parent->object, fp); 559102413Scharnier /* FALLTHROUGH */ 56044305Sbrian 56136285Sbrian case ST_OPENED: 5626059Samurai if (ackaction) 5636059Samurai NewState(fp, ST_ACKSENT); 5646059Samurai else 5656059Samurai NewState(fp, ST_REQSENT); 56681634Sbrian (*fp->parent->LayerDown)(fp->parent->object, fp); 5676059Samurai break; 5686059Samurai case ST_REQSENT: 5696059Samurai if (ackaction) 5706059Samurai NewState(fp, ST_ACKSENT); 5716059Samurai break; 5726059Samurai case ST_ACKRCVD: 5736059Samurai if (ackaction) { 5746059Samurai NewState(fp, ST_OPENED); 57536285Sbrian if ((*fp->fn->LayerUp)(fp)) 57636285Sbrian (*fp->parent->LayerUp)(fp->parent->object, fp); 57736285Sbrian else { 57836285Sbrian (*fp->fn->LayerDown)(fp); 57944305Sbrian FsmInitRestartCounter(fp, FSM_TRM_TIMER); 58036285Sbrian FsmSendTerminateReq(fp); 58136285Sbrian NewState(fp, ST_CLOSING); 58263484Sbrian lcp_SendIdentification(&fp->link->lcp); 58336285Sbrian } 5846059Samurai } 5856059Samurai break; 5866059Samurai case ST_ACKSENT: 5876059Samurai if (!ackaction) 5886059Samurai NewState(fp, ST_REQSENT); 5896059Samurai break; 5906059Samurai } 59154912Sbrian m_freem(bp); 59244305Sbrian 59344305Sbrian if (dec.rejend != dec.rej && --fp->more.rejs <= 0) { 59444305Sbrian log_Printf(LogPHASE, "%s: Too many %s REJs sent - abandoning negotiation\n", 59544305Sbrian fp->link->name, fp->name); 59663484Sbrian lcp_SendIdentification(&fp->link->lcp); 59744305Sbrian fsm_Close(fp); 59844305Sbrian } 59944305Sbrian 60044305Sbrian if (dec.nakend != dec.nak && --fp->more.naks <= 0) { 60144305Sbrian log_Printf(LogPHASE, "%s: Too many %s NAKs sent - abandoning negotiation\n", 60244305Sbrian fp->link->name, fp->name); 60363484Sbrian lcp_SendIdentification(&fp->link->lcp); 60444305Sbrian fsm_Close(fp); 60544305Sbrian } 6066059Samurai} 6076059Samurai 60830715Sbrianstatic void 60936285SbrianFsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 61028679Sbrian/* RCA */ 6116059Samurai{ 61294894Sbrian struct fsm_decode dec; 61394894Sbrian int plen, flen; 61494894Sbrian u_char *cp; 61594894Sbrian 61694894Sbrian plen = m_length(bp); 61794894Sbrian flen = ntohs(lhp->length) - sizeof *lhp; 61894894Sbrian if (plen < flen) { 61994894Sbrian m_freem(bp); 62094894Sbrian return; 62194894Sbrian } 62294894Sbrian 62394894Sbrian bp = m_pullup(bp); 62494894Sbrian dec.ackend = dec.ack; 62594894Sbrian dec.nakend = dec.nak; 62694894Sbrian dec.rejend = dec.rej; 62794894Sbrian cp = MBUF_CTOP(bp); 62894894Sbrian (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_ACK, &dec); 629134789Sbrian if (flen < (int)sizeof(struct fsm_opt_hdr)) 63094894Sbrian log_Printf(fp->LogLevel, " [EMPTY]\n"); 63194894Sbrian 6326059Samurai switch (fp->state) { 63328679Sbrian case ST_CLOSED: 63428679Sbrian case ST_STOPPED: 63536285Sbrian (*fp->fn->SendTerminateAck)(fp, lhp->id); 6366059Samurai break; 6376059Samurai case ST_CLOSING: 6386059Samurai case ST_STOPPING: 6396059Samurai break; 6406059Samurai case ST_REQSENT: 64144305Sbrian FsmInitRestartCounter(fp, FSM_REQ_TIMER); 6426059Samurai NewState(fp, ST_ACKRCVD); 6436059Samurai break; 6446059Samurai case ST_ACKRCVD: 6456059Samurai FsmSendConfigReq(fp); 6466059Samurai NewState(fp, ST_REQSENT); 6476059Samurai break; 6486059Samurai case ST_ACKSENT: 64944305Sbrian FsmInitRestartCounter(fp, FSM_REQ_TIMER); 6506059Samurai NewState(fp, ST_OPENED); 65136285Sbrian if ((*fp->fn->LayerUp)(fp)) 65236285Sbrian (*fp->parent->LayerUp)(fp->parent->object, fp); 65336285Sbrian else { 65436285Sbrian (*fp->fn->LayerDown)(fp); 65544305Sbrian FsmInitRestartCounter(fp, FSM_TRM_TIMER); 65636285Sbrian FsmSendTerminateReq(fp); 65736285Sbrian NewState(fp, ST_CLOSING); 65863484Sbrian lcp_SendIdentification(&fp->link->lcp); 65936285Sbrian } 6606059Samurai break; 6616059Samurai case ST_OPENED: 66236285Sbrian (*fp->fn->LayerDown)(fp); 6636059Samurai FsmSendConfigReq(fp); 6646059Samurai NewState(fp, ST_REQSENT); 66536285Sbrian (*fp->parent->LayerDown)(fp->parent->object, fp); 6666059Samurai break; 6676059Samurai } 66854912Sbrian m_freem(bp); 6696059Samurai} 6706059Samurai 67130715Sbrianstatic void 67236285SbrianFsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 67328679Sbrian/* RCN */ 6746059Samurai{ 67536285Sbrian struct fsm_decode dec; 6766735Samurai int plen, flen; 67794894Sbrian u_char *cp; 6788857Srgrimes 67954912Sbrian plen = m_length(bp); 68031962Sbrian flen = ntohs(lhp->length) - sizeof *lhp; 6816735Samurai if (plen < flen) { 68254912Sbrian m_freem(bp); 6836059Samurai return; 6846059Samurai } 6856059Samurai 6866059Samurai /* 68728679Sbrian * Check and process easy case 6886059Samurai */ 6896059Samurai switch (fp->state) { 6906059Samurai case ST_INITIAL: 6916059Samurai case ST_STARTING: 69236285Sbrian log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 69336285Sbrian fp->link->name, State2Nam(fp->state)); 69454912Sbrian m_freem(bp); 6956059Samurai return; 6966059Samurai case ST_CLOSED: 6976059Samurai case ST_STOPPED: 69836285Sbrian (*fp->fn->SendTerminateAck)(fp, lhp->id); 69954912Sbrian m_freem(bp); 7006059Samurai return; 7016059Samurai case ST_CLOSING: 7026059Samurai case ST_STOPPING: 70354912Sbrian m_freem(bp); 7046059Samurai return; 7056059Samurai } 7066059Samurai 70754912Sbrian bp = m_pullup(bp); 70836285Sbrian dec.ackend = dec.ack; 70936285Sbrian dec.nakend = dec.nak; 71036285Sbrian dec.rejend = dec.rej; 71194894Sbrian cp = MBUF_CTOP(bp); 71294894Sbrian (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_NAK, &dec); 713134789Sbrian if (flen < (int)sizeof(struct fsm_opt_hdr)) 71436285Sbrian log_Printf(fp->LogLevel, " [EMPTY]\n"); 7156059Samurai 7166059Samurai switch (fp->state) { 7176059Samurai case ST_REQSENT: 7186059Samurai case ST_ACKSENT: 71944305Sbrian FsmInitRestartCounter(fp, FSM_REQ_TIMER); 7206059Samurai FsmSendConfigReq(fp); 7216059Samurai break; 7226059Samurai case ST_OPENED: 72336285Sbrian (*fp->fn->LayerDown)(fp); 72436285Sbrian FsmSendConfigReq(fp); 72536285Sbrian NewState(fp, ST_REQSENT); 72636285Sbrian (*fp->parent->LayerDown)(fp->parent->object, fp); 72736285Sbrian break; 7286059Samurai case ST_ACKRCVD: 7296059Samurai FsmSendConfigReq(fp); 7306059Samurai NewState(fp, ST_REQSENT); 7316059Samurai break; 7326059Samurai } 7336059Samurai 73454912Sbrian m_freem(bp); 7356059Samurai} 7366059Samurai 73730715Sbrianstatic void 73836285SbrianFsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 73928679Sbrian/* RTR */ 7406059Samurai{ 7416059Samurai switch (fp->state) { 74236285Sbrian case ST_INITIAL: 74336285Sbrian case ST_STARTING: 74436285Sbrian log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 74536285Sbrian fp->link->name, State2Nam(fp->state)); 7466059Samurai break; 7476059Samurai case ST_CLOSED: 7486059Samurai case ST_STOPPED: 7496059Samurai case ST_CLOSING: 7506059Samurai case ST_STOPPING: 7516059Samurai case ST_REQSENT: 75236285Sbrian (*fp->fn->SendTerminateAck)(fp, lhp->id); 7536059Samurai break; 7546059Samurai case ST_ACKRCVD: 7556059Samurai case ST_ACKSENT: 75636285Sbrian (*fp->fn->SendTerminateAck)(fp, lhp->id); 7576059Samurai NewState(fp, ST_REQSENT); 7586059Samurai break; 7596059Samurai case ST_OPENED: 76036285Sbrian (*fp->fn->LayerDown)(fp); 76136285Sbrian (*fp->fn->SendTerminateAck)(fp, lhp->id); 76244305Sbrian FsmInitRestartCounter(fp, FSM_TRM_TIMER); 76344305Sbrian timer_Start(&fp->FsmTimer); /* Start restart timer */ 76426353Sbrian fp->restart = 0; 76526353Sbrian NewState(fp, ST_STOPPING); 76636285Sbrian (*fp->parent->LayerDown)(fp->parent->object, fp); 76744305Sbrian /* A delayed ST_STOPPED is now scheduled */ 7686059Samurai break; 7696059Samurai } 77054912Sbrian m_freem(bp); 7716059Samurai} 7726059Samurai 77330715Sbrianstatic void 774134789SbrianFsmRecvTermAck(struct fsm *fp, struct fsmheader *lhp __unused, struct mbuf *bp) 77528679Sbrian/* RTA */ 7766059Samurai{ 7776059Samurai switch (fp->state) { 77836285Sbrian case ST_CLOSING: 77936285Sbrian (*fp->fn->LayerFinish)(fp); 7806059Samurai NewState(fp, ST_CLOSED); 78136285Sbrian (*fp->parent->LayerFinish)(fp->parent->object, fp); 7826059Samurai break; 7836059Samurai case ST_STOPPING: 78436285Sbrian (*fp->fn->LayerFinish)(fp); 7856059Samurai NewState(fp, ST_STOPPED); 78636285Sbrian (*fp->parent->LayerFinish)(fp->parent->object, fp); 7876059Samurai break; 7886059Samurai case ST_ACKRCVD: 7896059Samurai NewState(fp, ST_REQSENT); 7906059Samurai break; 7916059Samurai case ST_OPENED: 79236285Sbrian (*fp->fn->LayerDown)(fp); 7936059Samurai FsmSendConfigReq(fp); 7946059Samurai NewState(fp, ST_REQSENT); 79536285Sbrian (*fp->parent->LayerDown)(fp->parent->object, fp); 7966059Samurai break; 7976059Samurai } 79854912Sbrian m_freem(bp); 7996059Samurai} 8006059Samurai 80130715Sbrianstatic void 80236285SbrianFsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 80328679Sbrian/* RCJ */ 8046059Samurai{ 80536285Sbrian struct fsm_decode dec; 806134789Sbrian size_t plen; 807134789Sbrian int flen; 80894894Sbrian u_char *cp; 8098857Srgrimes 81054912Sbrian plen = m_length(bp); 81131962Sbrian flen = ntohs(lhp->length) - sizeof *lhp; 812134789Sbrian if ((int)plen < flen) { 81354912Sbrian m_freem(bp); 8146059Samurai return; 8156059Samurai } 8166059Samurai 81763484Sbrian lcp_SendIdentification(&fp->link->lcp); 81863484Sbrian 8196059Samurai /* 82028679Sbrian * Check and process easy case 8216059Samurai */ 8226059Samurai switch (fp->state) { 8236059Samurai case ST_INITIAL: 8246059Samurai case ST_STARTING: 82536285Sbrian log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 82636285Sbrian fp->link->name, State2Nam(fp->state)); 82754912Sbrian m_freem(bp); 8286059Samurai return; 8296059Samurai case ST_CLOSED: 8306059Samurai case ST_STOPPED: 83136285Sbrian (*fp->fn->SendTerminateAck)(fp, lhp->id); 83254912Sbrian m_freem(bp); 8336059Samurai return; 8346059Samurai case ST_CLOSING: 8356059Samurai case ST_STOPPING: 83654912Sbrian m_freem(bp); 8376059Samurai return; 8386059Samurai } 8396059Samurai 84054912Sbrian bp = m_pullup(bp); 84136285Sbrian dec.ackend = dec.ack; 84236285Sbrian dec.nakend = dec.nak; 84336285Sbrian dec.rejend = dec.rej; 84494894Sbrian cp = MBUF_CTOP(bp); 84594894Sbrian (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_REJ, &dec); 846134789Sbrian if (flen < (int)sizeof(struct fsm_opt_hdr)) 84736285Sbrian log_Printf(fp->LogLevel, " [EMPTY]\n"); 8486059Samurai 8496059Samurai switch (fp->state) { 8506059Samurai case ST_REQSENT: 8516059Samurai case ST_ACKSENT: 85244305Sbrian FsmInitRestartCounter(fp, FSM_REQ_TIMER); 8536059Samurai FsmSendConfigReq(fp); 8546059Samurai break; 8556059Samurai case ST_OPENED: 85636285Sbrian (*fp->fn->LayerDown)(fp); 85736285Sbrian FsmSendConfigReq(fp); 85836285Sbrian NewState(fp, ST_REQSENT); 85936285Sbrian (*fp->parent->LayerDown)(fp->parent->object, fp); 86036285Sbrian break; 8616059Samurai case ST_ACKRCVD: 8626059Samurai FsmSendConfigReq(fp); 8636059Samurai NewState(fp, ST_REQSENT); 8646059Samurai break; 8656059Samurai } 86654912Sbrian m_freem(bp); 8676059Samurai} 8686059Samurai 86930715Sbrianstatic void 870134789SbrianFsmRecvCodeRej(struct fsm *fp __unused, struct fsmheader *lhp __unused, 871134789Sbrian struct mbuf *bp) 8726059Samurai{ 87354912Sbrian m_freem(bp); 8746059Samurai} 8756059Samurai 87630715Sbrianstatic void 877134789SbrianFsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp __unused, struct mbuf *bp) 8786059Samurai{ 87936285Sbrian struct physical *p = link2physical(fp->link); 88046828Sbrian u_short proto; 8816059Samurai 88254912Sbrian if (m_length(bp) < 2) { 88354912Sbrian m_freem(bp); 88446828Sbrian return; 88546828Sbrian } 88646828Sbrian bp = mbuf_Read(bp, &proto, 2); 88746828Sbrian proto = ntohs(proto); 88836285Sbrian log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 88936285Sbrian fp->link->name, proto, hdlc_Protocol2Nam(proto)); 8906059Samurai 8916059Samurai switch (proto) { 8926059Samurai case PROTO_LQR: 89336285Sbrian if (p) 89436285Sbrian lqr_Stop(p, LQM_LQR); 89536285Sbrian else 89636285Sbrian log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 89736285Sbrian fp->link->name); 8986059Samurai break; 8996059Samurai case PROTO_CCP: 90036285Sbrian if (fp->proto == PROTO_LCP) { 90136285Sbrian fp = &fp->link->ccp.fsm; 90244359Sbrian /* Despite the RFC (1661), don't do an out-of-place TLF */ 90344359Sbrian /* (*fp->fn->LayerFinish)(fp); */ 90436285Sbrian switch (fp->state) { 90536285Sbrian case ST_CLOSED: 90636285Sbrian case ST_CLOSING: 90736285Sbrian NewState(fp, ST_CLOSED); 90893420Sbrian break; 90936285Sbrian default: 91036285Sbrian NewState(fp, ST_STOPPED); 91136285Sbrian break; 91236285Sbrian } 91344359Sbrian /* See above */ 91444359Sbrian /* (*fp->parent->LayerFinish)(fp->parent->object, fp); */ 9156059Samurai } 9166059Samurai break; 91749599Sbrian case PROTO_IPCP: 91849599Sbrian if (fp->proto == PROTO_LCP) { 91949599Sbrian log_Printf(LogPHASE, "%s: IPCP protocol reject closes IPCP !\n", 92049599Sbrian fp->link->name); 92149599Sbrian fsm_Close(&fp->bundle->ncp.ipcp.fsm); 92249599Sbrian } 92349599Sbrian break; 92481634Sbrian#ifndef NOINET6 92581634Sbrian case PROTO_IPV6CP: 92681897Sbrian if (fp->proto == PROTO_LCP) { 92781634Sbrian log_Printf(LogPHASE, "%s: IPV6CP protocol reject closes IPV6CP !\n", 92881634Sbrian fp->link->name); 92981634Sbrian fsm_Close(&fp->bundle->ncp.ipv6cp.fsm); 93081634Sbrian } 93181634Sbrian break; 93281634Sbrian#endif 93336285Sbrian case PROTO_MP: 93436285Sbrian if (fp->proto == PROTO_LCP) { 93536285Sbrian struct lcp *lcp = fsm2lcp(fp); 93636285Sbrian 93736285Sbrian if (lcp->want_mrru && lcp->his_mrru) { 93836285Sbrian log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 93936285Sbrian fp->link->name); 94036285Sbrian fsm_Close(fp); 94136285Sbrian } 94236285Sbrian } 94336285Sbrian break; 9446059Samurai } 94554912Sbrian m_freem(bp); 9466059Samurai} 9476059Samurai 94830715Sbrianstatic void 94936285SbrianFsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 9506059Samurai{ 95136285Sbrian struct lcp *lcp = fsm2lcp(fp); 9526059Samurai u_char *cp; 95336285Sbrian u_int32_t magic; 9546059Samurai 95554912Sbrian bp = m_pullup(bp); 95654912Sbrian m_settype(bp, MB_ECHOIN); 95752942Sbrian 95852942Sbrian if (lcp && ntohs(lhp->length) - sizeof *lhp >= 4) { 95936285Sbrian cp = MBUF_CTOP(bp); 96038814Sbrian ua_ntohl(cp, &magic); 96136285Sbrian if (magic != lcp->his_magic) { 96251970Sbrian log_Printf(fp->LogLevel, "%s: RecvEchoReq: magic 0x%08lx is wrong," 96351970Sbrian " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 96451970Sbrian (u_long)lcp->his_magic); 96536285Sbrian /* XXX: We should send terminate request */ 96636285Sbrian } 96736285Sbrian if (fp->state == ST_OPENED) { 96838814Sbrian ua_htonl(&lcp->want_magic, cp); /* local magic */ 96952942Sbrian fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, 97052942Sbrian ntohs(lhp->length) - sizeof *lhp, MB_ECHOOUT); 97136285Sbrian } 9726059Samurai } 97354912Sbrian m_freem(bp); 9746059Samurai} 9756059Samurai 97630715Sbrianstatic void 977134789SbrianFsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp __unused, struct mbuf *bp) 9786059Samurai{ 97947169Sbrian if (fsm2lcp(fp)) 98047169Sbrian bp = lqr_RecvEcho(fp, bp); 9816059Samurai 98254912Sbrian m_freem(bp); 9836059Samurai} 9846059Samurai 98530715Sbrianstatic void 986134789SbrianFsmRecvDiscReq(struct fsm *fp __unused, struct fsmheader *lhp __unused, 987134789Sbrian struct mbuf *bp) 9886059Samurai{ 98954912Sbrian m_freem(bp); 9906059Samurai} 9916059Samurai 99230715Sbrianstatic void 99346828SbrianFsmRecvIdent(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 9946059Samurai{ 99563484Sbrian u_int32_t magic; 99663484Sbrian u_short len; 99763484Sbrian u_char *cp; 99863484Sbrian 99963484Sbrian len = ntohs(lhp->length) - sizeof *lhp; 100063484Sbrian if (len >= 4) { 100163484Sbrian bp = m_pullup(m_append(bp, "", 1)); 100263484Sbrian cp = MBUF_CTOP(bp); 100363484Sbrian ua_ntohl(cp, &magic); 100463484Sbrian if (magic != fp->link->lcp.his_magic) 100563484Sbrian log_Printf(fp->LogLevel, "%s: RecvIdent: magic 0x%08lx is wrong," 100663484Sbrian " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 100763484Sbrian (u_long)fp->link->lcp.his_magic); 100863484Sbrian cp[len] = '\0'; 100963484Sbrian lcp_RecvIdentification(&fp->link->lcp, cp + 4); 101063484Sbrian } 101154912Sbrian m_freem(bp); 10126059Samurai} 10136059Samurai 101430715Sbrianstatic void 1015134789SbrianFsmRecvTimeRemain(struct fsm *fp __unused, struct fsmheader *lhp __unused, 1016134789Sbrian struct mbuf *bp) 10176059Samurai{ 101854912Sbrian m_freem(bp); 10196059Samurai} 10206059Samurai 102130715Sbrianstatic void 102236285SbrianFsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 10236059Samurai{ 102478411Sbrian if ((*fp->fn->RecvResetReq)(fp)) { 102578411Sbrian /* 102678411Sbrian * All sendable compressed packets are queued in the first (lowest 102778411Sbrian * priority) modem output queue.... dump 'em to the priority queue 102878411Sbrian * so that they arrive at the peer before our ResetAck. 102978411Sbrian */ 103078411Sbrian link_SequenceQueue(fp->link); 103178411Sbrian fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0, MB_CCPOUT); 103278411Sbrian } 103354912Sbrian m_freem(bp); 10346059Samurai} 10356059Samurai 103630715Sbrianstatic void 103736285SbrianFsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 10386059Samurai{ 103936285Sbrian (*fp->fn->RecvResetAck)(fp, lhp->id); 104054912Sbrian m_freem(bp); 10416059Samurai} 10426059Samurai 10436059Samuraivoid 104436285Sbrianfsm_Input(struct fsm *fp, struct mbuf *bp) 10456059Samurai{ 1046134789Sbrian size_t len; 104746686Sbrian struct fsmheader lh; 104831514Sbrian const struct fsmcodedesc *codep; 10496059Samurai 105054912Sbrian len = m_length(bp); 10516059Samurai if (len < sizeof(struct fsmheader)) { 105254912Sbrian m_freem(bp); 10536059Samurai return; 10546059Samurai } 105546686Sbrian bp = mbuf_Read(bp, &lh, sizeof lh); 105652942Sbrian 105763484Sbrian if (ntohs(lh.length) > len) { 1058134833Smarcel log_Printf(LogWARN, "%s: Oops: Got %zu bytes but %d byte payload " 105963484Sbrian "- dropped\n", fp->link->name, len, (int)ntohs(lh.length)); 106063484Sbrian m_freem(bp); 106163484Sbrian return; 106260957Sbrian } 106352942Sbrian 106446686Sbrian if (lh.code < fp->min_code || lh.code > fp->max_code || 106546686Sbrian lh.code > sizeof FsmCodes / sizeof *FsmCodes) { 106636285Sbrian /* 106736285Sbrian * Use a private id. This is really a response-type packet, but we 106836285Sbrian * MUST send a unique id for each REQ.... 106936285Sbrian */ 107036285Sbrian static u_char id; 107137010Sbrian 107254912Sbrian bp = m_prepend(bp, &lh, sizeof lh, 0); 107354912Sbrian bp = m_pullup(bp); 107454912Sbrian fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->m_len, MB_UNKNOWN); 107554912Sbrian m_freem(bp); 10766059Samurai return; 10776059Samurai } 10786059Samurai 107946686Sbrian codep = FsmCodes + lh.code - 1; 108046686Sbrian if (lh.id != fp->reqid && codep->check_reqid && 108136285Sbrian Enabled(fp->bundle, OPT_IDCHECK)) { 108236285Sbrian log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 108394894Sbrian fp->link->name, codep->name, lh.id, fp->reqid); 108436285Sbrian return; 108536285Sbrian } 108636285Sbrian 108736285Sbrian log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 108894894Sbrian fp->link->name, codep->name, lh.id, State2Nam(fp->state)); 108936285Sbrian 109046686Sbrian if (codep->inc_reqid && (lh.id == fp->reqid || 109136285Sbrian (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 109236285Sbrian fp->reqid++; /* That's the end of that ``exchange''.... */ 109336285Sbrian 109446686Sbrian (*codep->recv)(fp, &lh, bp); 10956059Samurai} 109636285Sbrian 109778411Sbrianint 109836285Sbrianfsm_NullRecvResetReq(struct fsm *fp) 109936285Sbrian{ 110036285Sbrian log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 110136285Sbrian fp->link->name); 110278411Sbrian return 1; 110336285Sbrian} 110436285Sbrian 110536285Sbrianvoid 1106134789Sbrianfsm_NullRecvResetAck(struct fsm *fp, u_char id __unused) 110736285Sbrian{ 110836285Sbrian log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 110936285Sbrian fp->link->name); 111036285Sbrian} 111137060Sbrian 111237060Sbrianvoid 111337160Sbrianfsm_Reopen(struct fsm *fp) 111437160Sbrian{ 111537160Sbrian if (fp->state == ST_OPENED) { 111637160Sbrian (*fp->fn->LayerDown)(fp); 111744305Sbrian FsmInitRestartCounter(fp, FSM_REQ_TIMER); 111837160Sbrian FsmSendConfigReq(fp); 111937160Sbrian NewState(fp, ST_REQSENT); 112037160Sbrian (*fp->parent->LayerDown)(fp->parent->object, fp); 112137160Sbrian } 112237160Sbrian} 112337160Sbrian 112437160Sbrianvoid 112537060Sbrianfsm2initial(struct fsm *fp) 112637060Sbrian{ 112744305Sbrian timer_Stop(&fp->FsmTimer); 112844305Sbrian timer_Stop(&fp->OpenTimer); 112944305Sbrian timer_Stop(&fp->StoppedTimer); 113037060Sbrian if (fp->state == ST_STOPPED) 113137060Sbrian fsm_Close(fp); 113237060Sbrian if (fp->state > ST_INITIAL) 113337060Sbrian fsm_Down(fp); 113437060Sbrian if (fp->state > ST_INITIAL) 113537060Sbrian fsm_Close(fp); 113637060Sbrian} 113794894Sbrian 113894894Sbrianstruct fsm_opt * 113994894Sbrianfsm_readopt(u_char **cp) 114094894Sbrian{ 114194894Sbrian struct fsm_opt *o = (struct fsm_opt *)*cp; 114294894Sbrian 114394894Sbrian if (o->hdr.len < sizeof(struct fsm_opt_hdr)) { 114494894Sbrian log_Printf(LogERROR, "Bad option length %d (out of phase?)\n", o->hdr.len); 114594894Sbrian return NULL; 114694894Sbrian } 114794894Sbrian 114894894Sbrian *cp += o->hdr.len; 114994894Sbrian 115094894Sbrian if (o->hdr.len > sizeof(struct fsm_opt)) { 115198244Sbrian log_Printf(LogERROR, "Warning: Truncating option length from %d to %d\n", 115298244Sbrian o->hdr.len, (int)sizeof(struct fsm_opt)); 115394894Sbrian o->hdr.len = sizeof(struct fsm_opt); 115494894Sbrian } 115594894Sbrian 115694894Sbrian return o; 115794894Sbrian} 115894894Sbrian 115994894Sbrianstatic int 116094894Sbrianfsm_opt(u_char *opt, int optlen, const struct fsm_opt *o) 116194894Sbrian{ 1162134789Sbrian unsigned cplen = o->hdr.len; 116394894Sbrian 1164134789Sbrian if (optlen < (int)sizeof(struct fsm_opt_hdr)) 116594894Sbrian optlen = 0; 116694894Sbrian 1167134789Sbrian if ((int)cplen > optlen) { 116894894Sbrian log_Printf(LogERROR, "Can't REJ length %d - trunating to %d\n", 116994894Sbrian cplen, optlen); 117094894Sbrian cplen = optlen; 117194894Sbrian } 117294894Sbrian memcpy(opt, o, cplen); 117394894Sbrian if (cplen) 117494894Sbrian opt[1] = cplen; 117594894Sbrian 117694894Sbrian return cplen; 117794894Sbrian} 117894894Sbrian 117994894Sbrianvoid 118094894Sbrianfsm_rej(struct fsm_decode *dec, const struct fsm_opt *o) 118194894Sbrian{ 118294894Sbrian if (!dec) 118394894Sbrian return; 118494894Sbrian dec->rejend += fsm_opt(dec->rejend, FSM_OPTLEN - (dec->rejend - dec->rej), o); 118594894Sbrian} 118694894Sbrian 118794894Sbrianvoid 118894894Sbrianfsm_ack(struct fsm_decode *dec, const struct fsm_opt *o) 118994894Sbrian{ 119094894Sbrian if (!dec) 119194894Sbrian return; 119294894Sbrian dec->ackend += fsm_opt(dec->ackend, FSM_OPTLEN - (dec->ackend - dec->ack), o); 119394894Sbrian} 119494894Sbrian 119594894Sbrianvoid 119694894Sbrianfsm_nak(struct fsm_decode *dec, const struct fsm_opt *o) 119794894Sbrian{ 119894894Sbrian if (!dec) 119994894Sbrian return; 120094894Sbrian dec->nakend += fsm_opt(dec->nakend, FSM_OPTLEN - (dec->nakend - dec->nak), o); 120194894Sbrian} 120294894Sbrian 120394894Sbrianvoid 120494894Sbrianfsm_opt_normalise(struct fsm_decode *dec) 120594894Sbrian{ 120694894Sbrian if (dec->rejend != dec->rej) { 120794894Sbrian /* rejects are preferred */ 120894894Sbrian dec->ackend = dec->ack; 120994894Sbrian dec->nakend = dec->nak; 121094894Sbrian } else if (dec->nakend != dec->nak) 121194894Sbrian /* then NAKs */ 121294894Sbrian dec->ackend = dec->ack; 121394894Sbrian} 1214