165309e5cSBrian Somers /*- 265309e5cSBrian Somers * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 365309e5cSBrian Somers * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 465309e5cSBrian Somers * Internet Initiative Japan, Inc (IIJ) 565309e5cSBrian Somers * All rights reserved. 6af57ed9fSAtsushi Murai * 765309e5cSBrian Somers * Redistribution and use in source and binary forms, with or without 865309e5cSBrian Somers * modification, are permitted provided that the following conditions 965309e5cSBrian Somers * are met: 1065309e5cSBrian Somers * 1. Redistributions of source code must retain the above copyright 1165309e5cSBrian Somers * notice, this list of conditions and the following disclaimer. 1265309e5cSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 1365309e5cSBrian Somers * notice, this list of conditions and the following disclaimer in the 1465309e5cSBrian Somers * documentation and/or other materials provided with the distribution. 15af57ed9fSAtsushi Murai * 1665309e5cSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1765309e5cSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1865309e5cSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1965309e5cSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2065309e5cSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2165309e5cSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2265309e5cSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2365309e5cSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2465309e5cSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2565309e5cSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2665309e5cSBrian Somers * SUCH DAMAGE. 27af57ed9fSAtsushi Murai * 2897d92980SPeter Wemm * $FreeBSD$ 29af57ed9fSAtsushi Murai */ 3075240ed1SBrian Somers 31972a1bcfSBrian Somers #include <sys/param.h> 321342caedSBrian Somers #include <netinet/in.h> 331342caedSBrian Somers #include <netinet/in_systm.h> 341342caedSBrian Somers #include <netinet/ip.h> 3530949fd4SBrian Somers #include <sys/socket.h> 361fa665f5SBrian Somers #include <sys/un.h> 371ae349f5Scvs2svn 3875240ed1SBrian Somers #include <string.h> 3975240ed1SBrian Somers #include <termios.h> 4075240ed1SBrian Somers 415d9e6103SBrian Somers #include "layer.h" 429e8ec64bSBrian Somers #include "ua.h" 4375240ed1SBrian Somers #include "mbuf.h" 4475240ed1SBrian Somers #include "log.h" 4575240ed1SBrian Somers #include "defs.h" 4675240ed1SBrian Somers #include "timer.h" 47af57ed9fSAtsushi Murai #include "fsm.h" 481342caedSBrian Somers #include "iplist.h" 49af57ed9fSAtsushi Murai #include "lqr.h" 50879ed6faSBrian Somers #include "hdlc.h" 511342caedSBrian Somers #include "throughput.h" 521342caedSBrian Somers #include "slcompress.h" 5330949fd4SBrian Somers #include "ncpaddr.h" 5430949fd4SBrian Somers #include "ip.h" 551342caedSBrian Somers #include "ipcp.h" 561342caedSBrian Somers #include "filter.h" 571342caedSBrian Somers #include "descriptor.h" 58af57ed9fSAtsushi Murai #include "lcp.h" 59ed6a16c1SPoul-Henning Kamp #include "ccp.h" 608c07a7b2SBrian Somers #include "link.h" 611342caedSBrian Somers #include "mp.h" 62972a1bcfSBrian Somers #ifndef NORADIUS 63972a1bcfSBrian Somers #include "radius.h" 64972a1bcfSBrian Somers #endif 6530949fd4SBrian Somers #include "ipv6cp.h" 6630949fd4SBrian Somers #include "ncp.h" 671342caedSBrian Somers #include "bundle.h" 681342caedSBrian Somers #include "async.h" 6963b73463SBrian Somers #include "physical.h" 705d9e6103SBrian Somers #include "proto.h" 7175240ed1SBrian Somers 7275240ed1SBrian Somers static void FsmSendConfigReq(struct fsm *); 7375240ed1SBrian Somers static void FsmSendTerminateReq(struct fsm *); 74479508cfSBrian Somers static void FsmInitRestartCounter(struct fsm *, int); 75af57ed9fSAtsushi Murai 762267893fSBrian Somers typedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *); 772267893fSBrian Somers static recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak, 782267893fSBrian Somers FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck, 792267893fSBrian Somers FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq, 802267893fSBrian Somers FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent, 812267893fSBrian Somers FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck; 822267893fSBrian Somers 832267893fSBrian Somers static const struct fsmcodedesc { 842267893fSBrian Somers recvfn *recv; 852267893fSBrian Somers unsigned check_reqid : 1; 862267893fSBrian Somers unsigned inc_reqid : 1; 872267893fSBrian Somers const char *name; 882267893fSBrian Somers } FsmCodes[] = { 892267893fSBrian Somers { FsmRecvConfigReq, 0, 0, "ConfigReq" }, 902267893fSBrian Somers { FsmRecvConfigAck, 1, 1, "ConfigAck" }, 912267893fSBrian Somers { FsmRecvConfigNak, 1, 1, "ConfigNak" }, 922267893fSBrian Somers { FsmRecvConfigRej, 1, 1, "ConfigRej" }, 932267893fSBrian Somers { FsmRecvTermReq, 0, 0, "TerminateReq" }, 942267893fSBrian Somers { FsmRecvTermAck, 1, 1, "TerminateAck" }, 952267893fSBrian Somers { FsmRecvCodeRej, 0, 0, "CodeRej" }, 962267893fSBrian Somers { FsmRecvProtoRej, 0, 0, "ProtocolRej" }, 972267893fSBrian Somers { FsmRecvEchoReq, 0, 0, "EchoRequest" }, 982267893fSBrian Somers { FsmRecvEchoRep, 0, 0, "EchoReply" }, 992267893fSBrian Somers { FsmRecvDiscReq, 0, 0, "DiscardReq" }, 1001038894eSBrian Somers { FsmRecvIdent, 0, 1, "Ident" }, 1012267893fSBrian Somers { FsmRecvTimeRemain,0, 0, "TimeRemain" }, 1025d9e6103SBrian Somers { FsmRecvResetReq, 0, 0, "ResetReq" }, 1032267893fSBrian Somers { FsmRecvResetAck, 0, 1, "ResetAck" } 1042267893fSBrian Somers }; 1052267893fSBrian Somers 1062267893fSBrian Somers static const char * 1072267893fSBrian Somers Code2Nam(u_int code) 1082267893fSBrian Somers { 1092267893fSBrian Somers if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0]) 1102267893fSBrian Somers return "Unknown"; 1112267893fSBrian Somers return FsmCodes[code-1].name; 1122267893fSBrian Somers } 1132267893fSBrian Somers 1141e991daaSBrian Somers const char * 1151e991daaSBrian Somers State2Nam(u_int state) 1161e991daaSBrian Somers { 117182c898aSBrian Somers static const char * const StateNames[] = { 118af57ed9fSAtsushi Murai "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", 119927145beSBrian Somers "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", 120af57ed9fSAtsushi Murai }; 121af57ed9fSAtsushi Murai 1221e991daaSBrian Somers if (state >= sizeof StateNames / sizeof StateNames[0]) 1231e991daaSBrian Somers return "unknown"; 1241e991daaSBrian Somers return StateNames[state]; 1251e991daaSBrian Somers } 1261e991daaSBrian Somers 12771144dc5SBrian Somers static void 128b6e82f33SBrian Somers StoppedTimeout(void *v) 12971144dc5SBrian Somers { 130b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 131b6e82f33SBrian Somers 132dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name); 13349b239e0SBrian Somers if (fp->OpenTimer.state == TIMER_RUNNING) { 134dd7e2610SBrian Somers log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n", 135d47dceb8SBrian Somers fp->link->name, fp->name); 136dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 13749b239e0SBrian Somers } 13809206a6fSBrian Somers if (fp->state == ST_STOPPED) 13909206a6fSBrian Somers fsm2initial(fp); 14071144dc5SBrian Somers } 14171144dc5SBrian Somers 142af57ed9fSAtsushi Murai void 1433b0f8d2eSBrian Somers fsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, 144479508cfSBrian Somers int maxcode, int LogLevel, struct bundle *bundle, 1453b0f8d2eSBrian Somers struct link *l, const struct fsm_parent *parent, 146182c898aSBrian Somers struct fsm_callbacks *fn, const char * const timer_names[3]) 147af57ed9fSAtsushi Murai { 148503a7782SBrian Somers fp->name = name; 149503a7782SBrian Somers fp->proto = proto; 1503b0f8d2eSBrian Somers fp->min_code = mincode; 151503a7782SBrian Somers fp->max_code = maxcode; 1523b0f8d2eSBrian Somers fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; 153af57ed9fSAtsushi Murai fp->reqid = 1; 154af57ed9fSAtsushi Murai fp->restart = 1; 1555d9e6103SBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = 3; 156503a7782SBrian Somers memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); 157503a7782SBrian Somers memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); 158503a7782SBrian Somers memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); 159503a7782SBrian Somers fp->LogLevel = LogLevel; 1608c07a7b2SBrian Somers fp->link = l; 1617a6f8720SBrian Somers fp->bundle = bundle; 1626d666775SBrian Somers fp->parent = parent; 163503a7782SBrian Somers fp->fn = fn; 1643b0f8d2eSBrian Somers fp->FsmTimer.name = timer_names[0]; 1653b0f8d2eSBrian Somers fp->OpenTimer.name = timer_names[1]; 1663b0f8d2eSBrian Somers fp->StoppedTimer.name = timer_names[2]; 167af57ed9fSAtsushi Murai } 168af57ed9fSAtsushi Murai 16975240ed1SBrian Somers static void 170944f7098SBrian Somers NewState(struct fsm *fp, int new) 171af57ed9fSAtsushi Murai { 172dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", 173d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state), State2Nam(new)); 174cb611434SBrian Somers if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) 175dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 176af57ed9fSAtsushi Murai fp->state = new; 17771144dc5SBrian Somers if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { 178dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 179cb611434SBrian Somers if (new == ST_STOPPED && fp->StoppedTimer.load) { 180dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 181cb611434SBrian Somers fp->StoppedTimer.func = StoppedTimeout; 182cb611434SBrian Somers fp->StoppedTimer.arg = (void *) fp; 183dd7e2610SBrian Somers timer_Start(&fp->StoppedTimer); 18471144dc5SBrian Somers } 18571144dc5SBrian Somers } 186af57ed9fSAtsushi Murai } 187af57ed9fSAtsushi Murai 188af57ed9fSAtsushi Murai void 189411675baSBrian Somers fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count, 190411675baSBrian Somers int mtype) 191af57ed9fSAtsushi Murai { 192af57ed9fSAtsushi Murai int plen; 193af57ed9fSAtsushi Murai struct fsmheader lh; 194af57ed9fSAtsushi Murai struct mbuf *bp; 195af57ed9fSAtsushi Murai 196dd7e2610SBrian Somers if (log_IsKept(fp->LogLevel)) { 197dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 198d47dceb8SBrian Somers fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 1992267893fSBrian Somers switch (code) { 2002267893fSBrian Somers case CODE_CONFIGREQ: 2012267893fSBrian Somers case CODE_CONFIGACK: 2022267893fSBrian Somers case CODE_CONFIGREJ: 2032267893fSBrian Somers case CODE_CONFIGNAK: 2042267893fSBrian Somers (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL); 2052267893fSBrian Somers if (count < sizeof(struct fsmconfig)) 206dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 2072267893fSBrian Somers break; 2082267893fSBrian Somers } 2092267893fSBrian Somers } 2102267893fSBrian Somers 211af57ed9fSAtsushi Murai plen = sizeof(struct fsmheader) + count; 212af57ed9fSAtsushi Murai lh.code = code; 213af57ed9fSAtsushi Murai lh.id = id; 214af57ed9fSAtsushi Murai lh.length = htons(plen); 21526af0ae9SBrian Somers bp = m_get(plen, mtype); 21675240ed1SBrian Somers memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 217af57ed9fSAtsushi Murai if (count) 21875240ed1SBrian Somers memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 219dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "fsm_Output", bp); 220442f8495SBrian Somers link_PushPacket(fp->link, bp, fp->bundle, LINK_QUEUES(fp->link) - 1, 221442f8495SBrian Somers fp->proto); 2221038894eSBrian Somers 2231038894eSBrian Somers if (code == CODE_CONFIGREJ) 2241038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 225af57ed9fSAtsushi Murai } 226af57ed9fSAtsushi Murai 22749b239e0SBrian Somers static void 22849b239e0SBrian Somers FsmOpenNow(void *v) 22949b239e0SBrian Somers { 23049b239e0SBrian Somers struct fsm *fp = (struct fsm *)v; 23149b239e0SBrian Somers 232dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 23349b239e0SBrian Somers if (fp->state <= ST_STOPPED) { 2343a2e4f62SBrian Somers if (fp->state != ST_STARTING) { 2353a2e4f62SBrian Somers /* 2363a2e4f62SBrian Somers * In practice, we're only here in ST_STOPPED (when delaying the 2373a2e4f62SBrian Somers * first config request) or ST_CLOSED (when openmode == 0). 2383a2e4f62SBrian Somers * 2393a2e4f62SBrian Somers * The ST_STOPPED bit is breaking the RFC already :-( 2403a2e4f62SBrian Somers * 2413a2e4f62SBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 2423a2e4f62SBrian Somers * required for an Open event when state == Closed, but the RFC 2433a2e4f62SBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 2443a2e4f62SBrian Somers * ie, Initial gets an `Up' event, Closing gets a RTA etc. 2453a2e4f62SBrian Somers */ 2463a2e4f62SBrian Somers (*fp->fn->LayerStart)(fp); 2473a2e4f62SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 2483a2e4f62SBrian Somers } 249479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 25049b239e0SBrian Somers FsmSendConfigReq(fp); 25149b239e0SBrian Somers NewState(fp, ST_REQSENT); 25249b239e0SBrian Somers } 25349b239e0SBrian Somers } 25449b239e0SBrian Somers 255af57ed9fSAtsushi Murai void 256dd7e2610SBrian Somers fsm_Open(struct fsm *fp) 257af57ed9fSAtsushi Murai { 258af57ed9fSAtsushi Murai switch (fp->state) { 259af57ed9fSAtsushi Murai case ST_INITIAL: 260af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 2616d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2626d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 263af57ed9fSAtsushi Murai break; 264af57ed9fSAtsushi Murai case ST_CLOSED: 265af57ed9fSAtsushi Murai if (fp->open_mode == OPEN_PASSIVE) { 2663a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 26749b239e0SBrian Somers } else if (fp->open_mode > 0) { 26849b239e0SBrian Somers if (fp->open_mode > 1) 269dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 270d47dceb8SBrian Somers fp->link->name, fp->open_mode); 2713a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 272dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 27349b239e0SBrian Somers fp->OpenTimer.load = fp->open_mode * SECTICKS; 27449b239e0SBrian Somers fp->OpenTimer.func = FsmOpenNow; 27549b239e0SBrian Somers fp->OpenTimer.arg = (void *)fp; 276dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 27749b239e0SBrian Somers } else 27849b239e0SBrian Somers FsmOpenNow(fp); 279af57ed9fSAtsushi Murai break; 280af57ed9fSAtsushi Murai case ST_STOPPED: /* XXX: restart option */ 281af57ed9fSAtsushi Murai case ST_REQSENT: 282af57ed9fSAtsushi Murai case ST_ACKRCVD: 283af57ed9fSAtsushi Murai case ST_ACKSENT: 284af57ed9fSAtsushi Murai case ST_OPENED: /* XXX: restart option */ 285af57ed9fSAtsushi Murai break; 286af57ed9fSAtsushi Murai case ST_CLOSING: /* XXX: restart option */ 287af57ed9fSAtsushi Murai case ST_STOPPING: /* XXX: restart option */ 288af57ed9fSAtsushi Murai NewState(fp, ST_STOPPING); 289af57ed9fSAtsushi Murai break; 290af57ed9fSAtsushi Murai } 291af57ed9fSAtsushi Murai } 292af57ed9fSAtsushi Murai 293af57ed9fSAtsushi Murai void 294dd7e2610SBrian Somers fsm_Up(struct fsm *fp) 295af57ed9fSAtsushi Murai { 296af57ed9fSAtsushi Murai switch (fp->state) { 297af57ed9fSAtsushi Murai case ST_INITIAL: 298dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 2991fa665f5SBrian Somers fp->link->name); 300af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 301af57ed9fSAtsushi Murai break; 302af57ed9fSAtsushi Murai case ST_STARTING: 303479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 304af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 305af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 306af57ed9fSAtsushi Murai break; 307af57ed9fSAtsushi Murai default: 308dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 309d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 310af57ed9fSAtsushi Murai break; 311af57ed9fSAtsushi Murai } 312af57ed9fSAtsushi Murai } 313af57ed9fSAtsushi Murai 314af57ed9fSAtsushi Murai void 315dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 316af57ed9fSAtsushi Murai { 317af57ed9fSAtsushi Murai switch (fp->state) { 318af57ed9fSAtsushi Murai case ST_CLOSED: 319af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 320af57ed9fSAtsushi Murai break; 321455aabc3SBrian Somers case ST_CLOSING: 3228a8d9927SBrian Somers /* This TLF contradicts the RFC (1661), which ``misses it out'' ! */ 3236d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 324455aabc3SBrian Somers NewState(fp, ST_INITIAL); 3256d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 326455aabc3SBrian Somers break; 327af57ed9fSAtsushi Murai case ST_STOPPED: 328455aabc3SBrian Somers NewState(fp, ST_STARTING); 3296d666775SBrian Somers (*fp->fn->LayerStart)(fp); 3306d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 331455aabc3SBrian Somers break; 332af57ed9fSAtsushi Murai case ST_STOPPING: 333af57ed9fSAtsushi Murai case ST_REQSENT: 334af57ed9fSAtsushi Murai case ST_ACKRCVD: 335af57ed9fSAtsushi Murai case ST_ACKSENT: 336af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 337af57ed9fSAtsushi Murai break; 338af57ed9fSAtsushi Murai case ST_OPENED: 3396d666775SBrian Somers (*fp->fn->LayerDown)(fp); 340af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 3416d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 342af57ed9fSAtsushi Murai break; 343af57ed9fSAtsushi Murai } 344af57ed9fSAtsushi Murai } 345af57ed9fSAtsushi Murai 346af57ed9fSAtsushi Murai void 347dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 348af57ed9fSAtsushi Murai { 349af57ed9fSAtsushi Murai switch (fp->state) { 350af57ed9fSAtsushi Murai case ST_STARTING: 3516d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 352af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 3536d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 354af57ed9fSAtsushi Murai break; 355af57ed9fSAtsushi Murai case ST_STOPPED: 356af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 357af57ed9fSAtsushi Murai break; 358af57ed9fSAtsushi Murai case ST_STOPPING: 359af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 360af57ed9fSAtsushi Murai break; 361af57ed9fSAtsushi Murai case ST_OPENED: 3626d666775SBrian Somers (*fp->fn->LayerDown)(fp); 36315c8dc2aSBrian Somers if (fp->state == ST_OPENED) { 364479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 365455aabc3SBrian Somers FsmSendTerminateReq(fp); 366455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3676d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 36815c8dc2aSBrian Somers } 369455aabc3SBrian Somers break; 370af57ed9fSAtsushi Murai case ST_REQSENT: 371af57ed9fSAtsushi Murai case ST_ACKRCVD: 372af57ed9fSAtsushi Murai case ST_ACKSENT: 373479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 374af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 375af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 376af57ed9fSAtsushi Murai break; 377af57ed9fSAtsushi Murai } 378af57ed9fSAtsushi Murai } 379af57ed9fSAtsushi Murai 380af57ed9fSAtsushi Murai /* 381af57ed9fSAtsushi Murai * Send functions 382af57ed9fSAtsushi Murai */ 38375240ed1SBrian Somers static void 384944f7098SBrian Somers FsmSendConfigReq(struct fsm *fp) 385af57ed9fSAtsushi Murai { 386479508cfSBrian Somers if (fp->more.reqs-- > 0 && fp->restart-- > 0) { 38783d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 388dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 389af57ed9fSAtsushi Murai } else { 390479508cfSBrian Somers if (fp->more.reqs < 0) 391479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REQs sent - abandoning " 392479508cfSBrian Somers "negotiation\n", fp->link->name, fp->name); 3931038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 394dd7e2610SBrian Somers fsm_Close(fp); 395af57ed9fSAtsushi Murai } 396af57ed9fSAtsushi Murai } 397af57ed9fSAtsushi Murai 39875240ed1SBrian Somers static void 399944f7098SBrian Somers FsmSendTerminateReq(struct fsm *fp) 400af57ed9fSAtsushi Murai { 401411675baSBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0, MB_UNKNOWN); 4022267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 403dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 404af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 405af57ed9fSAtsushi Murai } 406af57ed9fSAtsushi Murai 407af57ed9fSAtsushi Murai /* 408af57ed9fSAtsushi Murai * Timeout actions 409af57ed9fSAtsushi Murai */ 41075240ed1SBrian Somers static void 411b6e82f33SBrian Somers FsmTimeout(void *v) 412af57ed9fSAtsushi Murai { 413b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 414b6e82f33SBrian Somers 415af57ed9fSAtsushi Murai if (fp->restart) { 416af57ed9fSAtsushi Murai switch (fp->state) { 417af57ed9fSAtsushi Murai case ST_CLOSING: 418af57ed9fSAtsushi Murai case ST_STOPPING: 419af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 420af57ed9fSAtsushi Murai break; 421af57ed9fSAtsushi Murai case ST_REQSENT: 422af57ed9fSAtsushi Murai case ST_ACKSENT: 423af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 424af57ed9fSAtsushi Murai break; 425af57ed9fSAtsushi Murai case ST_ACKRCVD: 426af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 427af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 428af57ed9fSAtsushi Murai break; 429af57ed9fSAtsushi Murai } 430dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 431af57ed9fSAtsushi Murai } else { 432af57ed9fSAtsushi Murai switch (fp->state) { 433af57ed9fSAtsushi Murai case ST_CLOSING: 4346d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 435af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 4366d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 437af57ed9fSAtsushi Murai break; 438af57ed9fSAtsushi Murai case ST_STOPPING: 4396d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 440af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4416d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 442af57ed9fSAtsushi Murai break; 443af57ed9fSAtsushi Murai case ST_REQSENT: /* XXX: 3p */ 444af57ed9fSAtsushi Murai case ST_ACKSENT: 445af57ed9fSAtsushi Murai case ST_ACKRCVD: 4466d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 447af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4486d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 449af57ed9fSAtsushi Murai break; 450af57ed9fSAtsushi Murai } 451af57ed9fSAtsushi Murai } 452af57ed9fSAtsushi Murai } 453af57ed9fSAtsushi Murai 45475240ed1SBrian Somers static void 455479508cfSBrian Somers FsmInitRestartCounter(struct fsm *fp, int what) 456af57ed9fSAtsushi Murai { 457dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 458af57ed9fSAtsushi Murai fp->FsmTimer.func = FsmTimeout; 459af57ed9fSAtsushi Murai fp->FsmTimer.arg = (void *)fp; 460479508cfSBrian Somers (*fp->fn->InitRestartCounter)(fp, what); 461af57ed9fSAtsushi Murai } 462af57ed9fSAtsushi Murai 463af57ed9fSAtsushi Murai /* 464af57ed9fSAtsushi Murai * Actions when receive packets 465af57ed9fSAtsushi Murai */ 46675240ed1SBrian Somers static void 467944f7098SBrian Somers FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 468944f7098SBrian Somers /* RCR */ 469af57ed9fSAtsushi Murai { 47030c2f2ffSBrian Somers struct fsm_decode dec; 47153c9f6c0SAtsushi Murai int plen, flen; 472af57ed9fSAtsushi Murai int ackaction = 0; 473af57ed9fSAtsushi Murai 47426af0ae9SBrian Somers plen = m_length(bp); 47570ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 47653c9f6c0SAtsushi Murai if (plen < flen) { 477a33b2ef7SBrian Somers log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 478d47dceb8SBrian Somers fp->link->name, plen, flen); 47926af0ae9SBrian Somers m_freem(bp); 480af57ed9fSAtsushi Murai return; 481af57ed9fSAtsushi Murai } 482af57ed9fSAtsushi Murai 4833377c28cSBrian Somers /* Check and process easy case */ 484af57ed9fSAtsushi Murai switch (fp->state) { 485af57ed9fSAtsushi Murai case ST_INITIAL: 48606337856SBrian Somers if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 48706337856SBrian Somers /* 48806337856SBrian Somers * ccp_SetOpenMode() leaves us in initial if we're disabling 4895d9e6103SBrian Somers * & denying everything. 49006337856SBrian Somers */ 49126af0ae9SBrian Somers bp = m_prepend(bp, lhp, sizeof *lhp, 2); 4925d9e6103SBrian Somers bp = proto_Prepend(bp, fp->proto, 0, 0); 49326af0ae9SBrian Somers bp = m_pullup(bp); 49426af0ae9SBrian Somers lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->m_len); 49526af0ae9SBrian Somers m_freem(bp); 49606337856SBrian Somers return; 49706337856SBrian Somers } 49806337856SBrian Somers /* Drop through */ 499af57ed9fSAtsushi Murai case ST_STARTING: 500dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 501d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 50226af0ae9SBrian Somers m_freem(bp); 503af57ed9fSAtsushi Murai return; 504af57ed9fSAtsushi Murai case ST_CLOSED: 5052267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 50626af0ae9SBrian Somers m_freem(bp); 507af57ed9fSAtsushi Murai return; 508af57ed9fSAtsushi Murai case ST_CLOSING: 509dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 510d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 511a9c503afSBrian Somers case ST_STOPPING: 51226af0ae9SBrian Somers m_freem(bp); 513af57ed9fSAtsushi Murai return; 51468a0e171SBrian Somers case ST_OPENED: 51568a0e171SBrian Somers (*fp->fn->LayerDown)(fp); 51668a0e171SBrian Somers break; 517af57ed9fSAtsushi Murai } 518af57ed9fSAtsushi Murai 51926af0ae9SBrian Somers bp = m_pullup(bp); 52030c2f2ffSBrian Somers dec.ackend = dec.ack; 52130c2f2ffSBrian Somers dec.nakend = dec.nak; 52230c2f2ffSBrian Somers dec.rejend = dec.rej; 52330c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec); 5242267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 525dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 526af57ed9fSAtsushi Murai 52730c2f2ffSBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 528af57ed9fSAtsushi Murai ackaction = 1; 529af57ed9fSAtsushi Murai 530af57ed9fSAtsushi Murai switch (fp->state) { 531af57ed9fSAtsushi Murai case ST_STOPPED: 532479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 53368a0e171SBrian Somers /* Fall through */ 53468a0e171SBrian Somers 53568a0e171SBrian Somers case ST_OPENED: 536af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 537af57ed9fSAtsushi Murai break; 538af57ed9fSAtsushi Murai } 539af57ed9fSAtsushi Murai 54030c2f2ffSBrian Somers if (dec.rejend != dec.rej) 541411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej, 542411675baSBrian Somers MB_UNKNOWN); 54330c2f2ffSBrian Somers if (dec.nakend != dec.nak) 544411675baSBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak, 545411675baSBrian Somers MB_UNKNOWN); 546af57ed9fSAtsushi Murai if (ackaction) 547411675baSBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack, 548411675baSBrian Somers MB_UNKNOWN); 549af57ed9fSAtsushi Murai 550af57ed9fSAtsushi Murai switch (fp->state) { 551455aabc3SBrian Somers case ST_STOPPED: 552479508cfSBrian Somers /* 553479508cfSBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 554479508cfSBrian Somers * required for a RCR when state == ST_STOPPED, but the RFC 555479508cfSBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 556479508cfSBrian Somers */ 557479508cfSBrian Somers (*fp->fn->LayerStart)(fp); 558479508cfSBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 559479508cfSBrian Somers /* Fall through */ 560479508cfSBrian Somers 561479508cfSBrian Somers case ST_OPENED: 562af57ed9fSAtsushi Murai if (ackaction) 563af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 564af57ed9fSAtsushi Murai else 565af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 56630949fd4SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 567af57ed9fSAtsushi Murai break; 568af57ed9fSAtsushi Murai case ST_REQSENT: 569af57ed9fSAtsushi Murai if (ackaction) 570af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 571af57ed9fSAtsushi Murai break; 572af57ed9fSAtsushi Murai case ST_ACKRCVD: 573af57ed9fSAtsushi Murai if (ackaction) { 574af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5756f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5766d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5776f384573SBrian Somers else { 5786f384573SBrian Somers (*fp->fn->LayerDown)(fp); 579479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 5806f384573SBrian Somers FsmSendTerminateReq(fp); 5816f384573SBrian Somers NewState(fp, ST_CLOSING); 5821038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 5836f384573SBrian Somers } 584af57ed9fSAtsushi Murai } 585af57ed9fSAtsushi Murai break; 586af57ed9fSAtsushi Murai case ST_ACKSENT: 587af57ed9fSAtsushi Murai if (!ackaction) 588af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 589af57ed9fSAtsushi Murai break; 590af57ed9fSAtsushi Murai } 59126af0ae9SBrian Somers m_freem(bp); 592479508cfSBrian Somers 593479508cfSBrian Somers if (dec.rejend != dec.rej && --fp->more.rejs <= 0) { 594479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REJs sent - abandoning negotiation\n", 595479508cfSBrian Somers fp->link->name, fp->name); 5961038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 597479508cfSBrian Somers fsm_Close(fp); 598479508cfSBrian Somers } 599479508cfSBrian Somers 600479508cfSBrian Somers if (dec.nakend != dec.nak && --fp->more.naks <= 0) { 601479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s NAKs sent - abandoning negotiation\n", 602479508cfSBrian Somers fp->link->name, fp->name); 6031038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 604479508cfSBrian Somers fsm_Close(fp); 605479508cfSBrian Somers } 606af57ed9fSAtsushi Murai } 607af57ed9fSAtsushi Murai 60875240ed1SBrian Somers static void 609944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 610944f7098SBrian Somers /* RCA */ 611af57ed9fSAtsushi Murai { 612af57ed9fSAtsushi Murai switch (fp->state) { 613af57ed9fSAtsushi Murai case ST_CLOSED: 614af57ed9fSAtsushi Murai case ST_STOPPED: 6152267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 616af57ed9fSAtsushi Murai break; 617af57ed9fSAtsushi Murai case ST_CLOSING: 618af57ed9fSAtsushi Murai case ST_STOPPING: 619af57ed9fSAtsushi Murai break; 620af57ed9fSAtsushi Murai case ST_REQSENT: 621479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 622af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 623af57ed9fSAtsushi Murai break; 624af57ed9fSAtsushi Murai case ST_ACKRCVD: 625af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 626af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 627af57ed9fSAtsushi Murai break; 628af57ed9fSAtsushi Murai case ST_ACKSENT: 629479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 630af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 6316f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 6326d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 6336f384573SBrian Somers else { 6346f384573SBrian Somers (*fp->fn->LayerDown)(fp); 635479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 6366f384573SBrian Somers FsmSendTerminateReq(fp); 6376f384573SBrian Somers NewState(fp, ST_CLOSING); 6381038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 6396f384573SBrian Somers } 640af57ed9fSAtsushi Murai break; 641af57ed9fSAtsushi Murai case ST_OPENED: 6426d666775SBrian Somers (*fp->fn->LayerDown)(fp); 643af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 644af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 6456d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 646af57ed9fSAtsushi Murai break; 647af57ed9fSAtsushi Murai } 64826af0ae9SBrian Somers m_freem(bp); 649af57ed9fSAtsushi Murai } 650af57ed9fSAtsushi Murai 65175240ed1SBrian Somers static void 652944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 653944f7098SBrian Somers /* RCN */ 654af57ed9fSAtsushi Murai { 65530c2f2ffSBrian Somers struct fsm_decode dec; 65653c9f6c0SAtsushi Murai int plen, flen; 657af57ed9fSAtsushi Murai 65826af0ae9SBrian Somers plen = m_length(bp); 65970ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 66053c9f6c0SAtsushi Murai if (plen < flen) { 66126af0ae9SBrian Somers m_freem(bp); 662af57ed9fSAtsushi Murai return; 663af57ed9fSAtsushi Murai } 664af57ed9fSAtsushi Murai 665af57ed9fSAtsushi Murai /* 666af57ed9fSAtsushi Murai * Check and process easy case 667af57ed9fSAtsushi Murai */ 668af57ed9fSAtsushi Murai switch (fp->state) { 669af57ed9fSAtsushi Murai case ST_INITIAL: 670af57ed9fSAtsushi Murai case ST_STARTING: 671dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 672d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 67326af0ae9SBrian Somers m_freem(bp); 674af57ed9fSAtsushi Murai return; 675af57ed9fSAtsushi Murai case ST_CLOSED: 676af57ed9fSAtsushi Murai case ST_STOPPED: 6772267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 67826af0ae9SBrian Somers m_freem(bp); 679af57ed9fSAtsushi Murai return; 680af57ed9fSAtsushi Murai case ST_CLOSING: 681af57ed9fSAtsushi Murai case ST_STOPPING: 68226af0ae9SBrian Somers m_freem(bp); 683af57ed9fSAtsushi Murai return; 684af57ed9fSAtsushi Murai } 685af57ed9fSAtsushi Murai 68626af0ae9SBrian Somers bp = m_pullup(bp); 68730c2f2ffSBrian Somers dec.ackend = dec.ack; 68830c2f2ffSBrian Somers dec.nakend = dec.nak; 68930c2f2ffSBrian Somers dec.rejend = dec.rej; 69030c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); 6912267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 692dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 693af57ed9fSAtsushi Murai 694af57ed9fSAtsushi Murai switch (fp->state) { 695af57ed9fSAtsushi Murai case ST_REQSENT: 696af57ed9fSAtsushi Murai case ST_ACKSENT: 697479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 698af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 699af57ed9fSAtsushi Murai break; 700af57ed9fSAtsushi Murai case ST_OPENED: 7016d666775SBrian Somers (*fp->fn->LayerDown)(fp); 702455aabc3SBrian Somers FsmSendConfigReq(fp); 703455aabc3SBrian Somers NewState(fp, ST_REQSENT); 7046d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 705455aabc3SBrian Somers break; 706af57ed9fSAtsushi Murai case ST_ACKRCVD: 707af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 708af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 709af57ed9fSAtsushi Murai break; 710af57ed9fSAtsushi Murai } 711af57ed9fSAtsushi Murai 71226af0ae9SBrian Somers m_freem(bp); 713af57ed9fSAtsushi Murai } 714af57ed9fSAtsushi Murai 71575240ed1SBrian Somers static void 716944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 717944f7098SBrian Somers /* RTR */ 718af57ed9fSAtsushi Murai { 719af57ed9fSAtsushi Murai switch (fp->state) { 720af57ed9fSAtsushi Murai case ST_INITIAL: 721af57ed9fSAtsushi Murai case ST_STARTING: 722dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 723d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 724af57ed9fSAtsushi Murai break; 725af57ed9fSAtsushi Murai case ST_CLOSED: 726af57ed9fSAtsushi Murai case ST_STOPPED: 727af57ed9fSAtsushi Murai case ST_CLOSING: 728af57ed9fSAtsushi Murai case ST_STOPPING: 729af57ed9fSAtsushi Murai case ST_REQSENT: 7302267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 731af57ed9fSAtsushi Murai break; 732af57ed9fSAtsushi Murai case ST_ACKRCVD: 733af57ed9fSAtsushi Murai case ST_ACKSENT: 7342267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 735af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 736af57ed9fSAtsushi Murai break; 737af57ed9fSAtsushi Murai case ST_OPENED: 7386d666775SBrian Somers (*fp->fn->LayerDown)(fp); 7392267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 740479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 741dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 7428f2fa0eeSBrian Somers fp->restart = 0; 7438f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 7446d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 745479508cfSBrian Somers /* A delayed ST_STOPPED is now scheduled */ 746af57ed9fSAtsushi Murai break; 747af57ed9fSAtsushi Murai } 74826af0ae9SBrian Somers m_freem(bp); 749af57ed9fSAtsushi Murai } 750af57ed9fSAtsushi Murai 75175240ed1SBrian Somers static void 752944f7098SBrian Somers FsmRecvTermAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 753944f7098SBrian Somers /* RTA */ 754af57ed9fSAtsushi Murai { 755af57ed9fSAtsushi Murai switch (fp->state) { 756af57ed9fSAtsushi Murai case ST_CLOSING: 7576d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 758af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 7596d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 760af57ed9fSAtsushi Murai break; 761af57ed9fSAtsushi Murai case ST_STOPPING: 7626d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 763af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 7646d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 765af57ed9fSAtsushi Murai break; 766af57ed9fSAtsushi Murai case ST_ACKRCVD: 767af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 768af57ed9fSAtsushi Murai break; 769af57ed9fSAtsushi Murai case ST_OPENED: 7706d666775SBrian Somers (*fp->fn->LayerDown)(fp); 771af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 772af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 7736d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 774af57ed9fSAtsushi Murai break; 775af57ed9fSAtsushi Murai } 77626af0ae9SBrian Somers m_freem(bp); 777af57ed9fSAtsushi Murai } 778af57ed9fSAtsushi Murai 77975240ed1SBrian Somers static void 780944f7098SBrian Somers FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 781944f7098SBrian Somers /* RCJ */ 782af57ed9fSAtsushi Murai { 78330c2f2ffSBrian Somers struct fsm_decode dec; 78453c9f6c0SAtsushi Murai int plen, flen; 785af57ed9fSAtsushi Murai 78626af0ae9SBrian Somers plen = m_length(bp); 78770ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 78853c9f6c0SAtsushi Murai if (plen < flen) { 78926af0ae9SBrian Somers m_freem(bp); 790af57ed9fSAtsushi Murai return; 791af57ed9fSAtsushi Murai } 792af57ed9fSAtsushi Murai 7931038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 7941038894eSBrian Somers 795af57ed9fSAtsushi Murai /* 796af57ed9fSAtsushi Murai * Check and process easy case 797af57ed9fSAtsushi Murai */ 798af57ed9fSAtsushi Murai switch (fp->state) { 799af57ed9fSAtsushi Murai case ST_INITIAL: 800af57ed9fSAtsushi Murai case ST_STARTING: 801dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 802d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 80326af0ae9SBrian Somers m_freem(bp); 804af57ed9fSAtsushi Murai return; 805af57ed9fSAtsushi Murai case ST_CLOSED: 806af57ed9fSAtsushi Murai case ST_STOPPED: 8072267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 80826af0ae9SBrian Somers m_freem(bp); 809af57ed9fSAtsushi Murai return; 810af57ed9fSAtsushi Murai case ST_CLOSING: 811af57ed9fSAtsushi Murai case ST_STOPPING: 81226af0ae9SBrian Somers m_freem(bp); 813af57ed9fSAtsushi Murai return; 814af57ed9fSAtsushi Murai } 815af57ed9fSAtsushi Murai 81626af0ae9SBrian Somers bp = m_pullup(bp); 81730c2f2ffSBrian Somers dec.ackend = dec.ack; 81830c2f2ffSBrian Somers dec.nakend = dec.nak; 81930c2f2ffSBrian Somers dec.rejend = dec.rej; 82030c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); 8212267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 822dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 823af57ed9fSAtsushi Murai 824af57ed9fSAtsushi Murai switch (fp->state) { 825af57ed9fSAtsushi Murai case ST_REQSENT: 826af57ed9fSAtsushi Murai case ST_ACKSENT: 827479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 828af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 829af57ed9fSAtsushi Murai break; 830af57ed9fSAtsushi Murai case ST_OPENED: 8316d666775SBrian Somers (*fp->fn->LayerDown)(fp); 832455aabc3SBrian Somers FsmSendConfigReq(fp); 833455aabc3SBrian Somers NewState(fp, ST_REQSENT); 8346d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 835455aabc3SBrian Somers break; 836af57ed9fSAtsushi Murai case ST_ACKRCVD: 837af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 838af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 839af57ed9fSAtsushi Murai break; 840af57ed9fSAtsushi Murai } 84126af0ae9SBrian Somers m_freem(bp); 842af57ed9fSAtsushi Murai } 843af57ed9fSAtsushi Murai 84475240ed1SBrian Somers static void 845944f7098SBrian Somers FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 846af57ed9fSAtsushi Murai { 84726af0ae9SBrian Somers m_freem(bp); 848af57ed9fSAtsushi Murai } 849af57ed9fSAtsushi Murai 85075240ed1SBrian Somers static void 851944f7098SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 852af57ed9fSAtsushi Murai { 8538c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 8543377c28cSBrian Somers u_short proto; 855af57ed9fSAtsushi Murai 85626af0ae9SBrian Somers if (m_length(bp) < 2) { 85726af0ae9SBrian Somers m_freem(bp); 8583377c28cSBrian Somers return; 8593377c28cSBrian Somers } 8603377c28cSBrian Somers bp = mbuf_Read(bp, &proto, 2); 8613377c28cSBrian Somers proto = ntohs(proto); 862dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 863d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 864af57ed9fSAtsushi Murai 865af57ed9fSAtsushi Murai switch (proto) { 866af57ed9fSAtsushi Murai case PROTO_LQR: 8678c07a7b2SBrian Somers if (p) 868dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 8698c07a7b2SBrian Somers else 870dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 871d47dceb8SBrian Somers fp->link->name); 872af57ed9fSAtsushi Murai break; 873af57ed9fSAtsushi Murai case PROTO_CCP: 874dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 8753b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 8768a8d9927SBrian Somers /* Despite the RFC (1661), don't do an out-of-place TLF */ 8778a8d9927SBrian Somers /* (*fp->fn->LayerFinish)(fp); */ 878af57ed9fSAtsushi Murai switch (fp->state) { 879af57ed9fSAtsushi Murai case ST_CLOSED: 880af57ed9fSAtsushi Murai case ST_CLOSING: 881af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 882ad65ae3aSBrian Somers break; 883af57ed9fSAtsushi Murai default: 884af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 885af57ed9fSAtsushi Murai break; 886af57ed9fSAtsushi Murai } 8878a8d9927SBrian Somers /* See above */ 8888a8d9927SBrian Somers /* (*fp->parent->LayerFinish)(fp->parent->object, fp); */ 889dc0fdb6bSBrian Somers } 8901ae349f5Scvs2svn break; 8918a59beb7SBrian Somers case PROTO_IPCP: 8928a59beb7SBrian Somers if (fp->proto == PROTO_LCP) { 8938a59beb7SBrian Somers log_Printf(LogPHASE, "%s: IPCP protocol reject closes IPCP !\n", 8948a59beb7SBrian Somers fp->link->name); 8958a59beb7SBrian Somers fsm_Close(&fp->bundle->ncp.ipcp.fsm); 8968a59beb7SBrian Somers } 8978a59beb7SBrian Somers break; 89830949fd4SBrian Somers #ifndef NOINET6 89930949fd4SBrian Somers case PROTO_IPV6CP: 9001136c6acSBrian Somers if (fp->proto == PROTO_LCP) { 90130949fd4SBrian Somers log_Printf(LogPHASE, "%s: IPV6CP protocol reject closes IPV6CP !\n", 90230949fd4SBrian Somers fp->link->name); 90330949fd4SBrian Somers fsm_Close(&fp->bundle->ncp.ipv6cp.fsm); 90430949fd4SBrian Somers } 90530949fd4SBrian Somers break; 90630949fd4SBrian Somers #endif 907673903ecSBrian Somers case PROTO_MP: 908673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 909673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 910673903ecSBrian Somers 911673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 912dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 913d47dceb8SBrian Somers fp->link->name); 914dd7e2610SBrian Somers fsm_Close(fp); 915673903ecSBrian Somers } 916673903ecSBrian Somers } 917af57ed9fSAtsushi Murai break; 918af57ed9fSAtsushi Murai } 91926af0ae9SBrian Somers m_freem(bp); 920af57ed9fSAtsushi Murai } 921af57ed9fSAtsushi Murai 92275240ed1SBrian Somers static void 923944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 924af57ed9fSAtsushi Murai { 925dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 926af57ed9fSAtsushi Murai u_char *cp; 927fe3125a0SBrian Somers u_int32_t magic; 928af57ed9fSAtsushi Murai 92926af0ae9SBrian Somers bp = m_pullup(bp); 93026af0ae9SBrian Somers m_settype(bp, MB_ECHOIN); 93187c3786eSBrian Somers 93287c3786eSBrian Somers if (lcp && ntohs(lhp->length) - sizeof *lhp >= 4) { 933af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 9349e8ec64bSBrian Somers ua_ntohl(cp, &magic); 935dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 936990a543fSBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: magic 0x%08lx is wrong," 937990a543fSBrian Somers " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 938990a543fSBrian Somers (u_long)lcp->his_magic); 939af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 940af57ed9fSAtsushi Murai } 941af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 9429e8ec64bSBrian Somers ua_htonl(&lcp->want_magic, cp); /* local magic */ 94387c3786eSBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, 94487c3786eSBrian Somers ntohs(lhp->length) - sizeof *lhp, MB_ECHOOUT); 945af57ed9fSAtsushi Murai } 946dc0fdb6bSBrian Somers } 94726af0ae9SBrian Somers m_freem(bp); 948af57ed9fSAtsushi Murai } 949af57ed9fSAtsushi Murai 95075240ed1SBrian Somers static void 951944f7098SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 952af57ed9fSAtsushi Murai { 9536471628dSBrian Somers if (fsm2lcp(fp)) 9543377c28cSBrian Somers bp = lqr_RecvEcho(fp, bp); 9556471628dSBrian Somers 95626af0ae9SBrian Somers m_freem(bp); 957af57ed9fSAtsushi Murai } 958af57ed9fSAtsushi Murai 95975240ed1SBrian Somers static void 960944f7098SBrian Somers FsmRecvDiscReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 961af57ed9fSAtsushi Murai { 96226af0ae9SBrian Somers m_freem(bp); 963af57ed9fSAtsushi Murai } 964af57ed9fSAtsushi Murai 96575240ed1SBrian Somers static void 966944f7098SBrian Somers FsmRecvIdent(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 967af57ed9fSAtsushi Murai { 9681038894eSBrian Somers u_int32_t magic; 9691038894eSBrian Somers u_short len; 9701038894eSBrian Somers u_char *cp; 9711038894eSBrian Somers 9721038894eSBrian Somers len = ntohs(lhp->length) - sizeof *lhp; 9731038894eSBrian Somers if (len >= 4) { 9741038894eSBrian Somers bp = m_pullup(m_append(bp, "", 1)); 9751038894eSBrian Somers cp = MBUF_CTOP(bp); 9761038894eSBrian Somers ua_ntohl(cp, &magic); 9771038894eSBrian Somers if (magic != fp->link->lcp.his_magic) 9781038894eSBrian Somers log_Printf(fp->LogLevel, "%s: RecvIdent: magic 0x%08lx is wrong," 9791038894eSBrian Somers " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 9801038894eSBrian Somers (u_long)fp->link->lcp.his_magic); 9811038894eSBrian Somers cp[len] = '\0'; 9821038894eSBrian Somers lcp_RecvIdentification(&fp->link->lcp, cp + 4); 9831038894eSBrian Somers } 98426af0ae9SBrian Somers m_freem(bp); 985af57ed9fSAtsushi Murai } 986af57ed9fSAtsushi Murai 98775240ed1SBrian Somers static void 988944f7098SBrian Somers FsmRecvTimeRemain(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 989af57ed9fSAtsushi Murai { 99026af0ae9SBrian Somers m_freem(bp); 991af57ed9fSAtsushi Murai } 992af57ed9fSAtsushi Murai 99375240ed1SBrian Somers static void 994944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 995af57ed9fSAtsushi Murai { 9966cf6ee76SBrian Somers if ((*fp->fn->RecvResetReq)(fp)) { 99798baf7c8SBrian Somers /* 998442f8495SBrian Somers * All sendable compressed packets are queued in the first (lowest 999442f8495SBrian Somers * priority) modem output queue.... dump 'em to the priority queue 1000442f8495SBrian Somers * so that they arrive at the peer before our ResetAck. 100198baf7c8SBrian Somers */ 10028c07a7b2SBrian Somers link_SequenceQueue(fp->link); 1003411675baSBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0, MB_CCPOUT); 10046cf6ee76SBrian Somers } 100526af0ae9SBrian Somers m_freem(bp); 1006af57ed9fSAtsushi Murai } 1007af57ed9fSAtsushi Murai 100875240ed1SBrian Somers static void 1009944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 1010af57ed9fSAtsushi Murai { 1011503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 101226af0ae9SBrian Somers m_freem(bp); 1013af57ed9fSAtsushi Murai } 1014af57ed9fSAtsushi Murai 1015af57ed9fSAtsushi Murai void 1016dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 1017af57ed9fSAtsushi Murai { 1018af57ed9fSAtsushi Murai int len; 10195d9e6103SBrian Somers struct fsmheader lh; 10200053cc58SBrian Somers const struct fsmcodedesc *codep; 1021af57ed9fSAtsushi Murai 102226af0ae9SBrian Somers len = m_length(bp); 1023af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 102426af0ae9SBrian Somers m_freem(bp); 1025af57ed9fSAtsushi Murai return; 1026af57ed9fSAtsushi Murai } 10275d9e6103SBrian Somers bp = mbuf_Read(bp, &lh, sizeof lh); 102887c3786eSBrian Somers 1029962a3cbcSBrian Somers if (ntohs(lh.length) > len) { 1030962a3cbcSBrian Somers log_Printf(LogWARN, "%s: Oops: Got %d bytes but %d byte payload " 1031962a3cbcSBrian Somers "- dropped\n", fp->link->name, len, (int)ntohs(lh.length)); 1032962a3cbcSBrian Somers m_freem(bp); 1033962a3cbcSBrian Somers return; 1034962a3cbcSBrian Somers } 103587c3786eSBrian Somers 10365d9e6103SBrian Somers if (lh.code < fp->min_code || lh.code > fp->max_code || 10375d9e6103SBrian Somers lh.code > sizeof FsmCodes / sizeof *FsmCodes) { 10383b0f8d2eSBrian Somers /* 10393b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 10403b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 10413b0f8d2eSBrian Somers */ 10423b0f8d2eSBrian Somers static u_char id; 1043d93d3a9cSBrian Somers 104426af0ae9SBrian Somers bp = m_prepend(bp, &lh, sizeof lh, 0); 104526af0ae9SBrian Somers bp = m_pullup(bp); 104626af0ae9SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->m_len, MB_UNKNOWN); 104726af0ae9SBrian Somers m_freem(bp); 1048af57ed9fSAtsushi Murai return; 1049af57ed9fSAtsushi Murai } 1050af57ed9fSAtsushi Murai 10515d9e6103SBrian Somers codep = FsmCodes + lh.code - 1; 10525d9e6103SBrian Somers if (lh.id != fp->reqid && codep->check_reqid && 10531342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 1054dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 10555d9e6103SBrian Somers fp->link->name, codep->name, lh.id, fp->reqid); 10562267893fSBrian Somers return; 10572267893fSBrian Somers } 10582267893fSBrian Somers 1059dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 10605d9e6103SBrian Somers fp->link->name, codep->name, lh.id, State2Nam(fp->state)); 10612267893fSBrian Somers 10625d9e6103SBrian Somers if (codep->inc_reqid && (lh.id == fp->reqid || 10631342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 10642267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 10652267893fSBrian Somers 10665d9e6103SBrian Somers (*codep->recv)(fp, &lh, bp); 10671ae349f5Scvs2svn } 1068503a7782SBrian Somers 10696cf6ee76SBrian Somers int 1070dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 1071503a7782SBrian Somers { 1072dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 1073d47dceb8SBrian Somers fp->link->name); 10746cf6ee76SBrian Somers return 1; 1075503a7782SBrian Somers } 1076503a7782SBrian Somers 1077503a7782SBrian Somers void 1078dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 1079503a7782SBrian Somers { 1080dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 1081d47dceb8SBrian Somers fp->link->name); 1082af57ed9fSAtsushi Murai } 108309206a6fSBrian Somers 108409206a6fSBrian Somers void 1085897f9429SBrian Somers fsm_Reopen(struct fsm *fp) 1086897f9429SBrian Somers { 1087897f9429SBrian Somers if (fp->state == ST_OPENED) { 1088897f9429SBrian Somers (*fp->fn->LayerDown)(fp); 1089479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 1090897f9429SBrian Somers FsmSendConfigReq(fp); 1091897f9429SBrian Somers NewState(fp, ST_REQSENT); 1092897f9429SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 1093897f9429SBrian Somers } 1094897f9429SBrian Somers } 1095897f9429SBrian Somers 1096897f9429SBrian Somers void 109709206a6fSBrian Somers fsm2initial(struct fsm *fp) 109809206a6fSBrian Somers { 1099479508cfSBrian Somers timer_Stop(&fp->FsmTimer); 1100479508cfSBrian Somers timer_Stop(&fp->OpenTimer); 1101479508cfSBrian Somers timer_Stop(&fp->StoppedTimer); 110209206a6fSBrian Somers if (fp->state == ST_STOPPED) 110309206a6fSBrian Somers fsm_Close(fp); 110409206a6fSBrian Somers if (fp->state > ST_INITIAL) 110509206a6fSBrian Somers fsm_Down(fp); 110609206a6fSBrian Somers if (fp->state > ST_INITIAL) 110709206a6fSBrian Somers fsm_Close(fp); 110809206a6fSBrian Somers } 1109