1af57ed9fSAtsushi Murai /* 2af57ed9fSAtsushi Murai * PPP Finite State Machine for LCP/IPCP 3af57ed9fSAtsushi Murai * 4af57ed9fSAtsushi Murai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5af57ed9fSAtsushi Murai * 6af57ed9fSAtsushi Murai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7af57ed9fSAtsushi Murai * 8af57ed9fSAtsushi Murai * Redistribution and use in source and binary forms are permitted 9af57ed9fSAtsushi Murai * provided that the above copyright notice and this paragraph are 10af57ed9fSAtsushi Murai * duplicated in all such forms and that any documentation, 11af57ed9fSAtsushi Murai * advertising materials, and other materials related to such 12af57ed9fSAtsushi Murai * distribution and use acknowledge that the software was developed 13af57ed9fSAtsushi Murai * by the Internet Initiative Japan, Inc. The name of the 14af57ed9fSAtsushi Murai * IIJ may not be used to endorse or promote products derived 15af57ed9fSAtsushi Murai * from this software without specific prior written permission. 16af57ed9fSAtsushi Murai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17af57ed9fSAtsushi Murai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18af57ed9fSAtsushi Murai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19af57ed9fSAtsushi Murai * 2006337856SBrian Somers * $Id: fsm.c,v 1.34 1998/06/27 23:48:43 brian Exp $ 21af57ed9fSAtsushi Murai * 22af57ed9fSAtsushi Murai * TODO: 23af57ed9fSAtsushi Murai */ 2475240ed1SBrian Somers 252764b86aSBrian Somers #include <sys/types.h> 261342caedSBrian Somers #include <netinet/in.h> 271342caedSBrian Somers #include <netinet/in_systm.h> 281342caedSBrian Somers #include <netinet/ip.h> 291fa665f5SBrian Somers #include <sys/un.h> 301ae349f5Scvs2svn 3175240ed1SBrian Somers #include <string.h> 3275240ed1SBrian Somers #include <termios.h> 3375240ed1SBrian Somers 3475240ed1SBrian Somers #include "mbuf.h" 3575240ed1SBrian Somers #include "log.h" 3675240ed1SBrian Somers #include "defs.h" 3775240ed1SBrian Somers #include "timer.h" 38af57ed9fSAtsushi Murai #include "fsm.h" 391342caedSBrian Somers #include "iplist.h" 40af57ed9fSAtsushi Murai #include "lqr.h" 41879ed6faSBrian Somers #include "hdlc.h" 421342caedSBrian Somers #include "throughput.h" 431342caedSBrian Somers #include "slcompress.h" 441342caedSBrian Somers #include "ipcp.h" 451342caedSBrian Somers #include "filter.h" 461342caedSBrian Somers #include "descriptor.h" 47af57ed9fSAtsushi Murai #include "lcp.h" 48ed6a16c1SPoul-Henning Kamp #include "ccp.h" 498c07a7b2SBrian Somers #include "link.h" 501342caedSBrian Somers #include "mp.h" 511342caedSBrian Somers #include "bundle.h" 521342caedSBrian Somers #include "async.h" 5363b73463SBrian Somers #include "physical.h" 541342caedSBrian Somers #include "lcpproto.h" 5575240ed1SBrian Somers 5675240ed1SBrian Somers static void FsmSendConfigReq(struct fsm *); 5775240ed1SBrian Somers static void FsmSendTerminateReq(struct fsm *); 5875240ed1SBrian Somers static void FsmInitRestartCounter(struct fsm *); 59af57ed9fSAtsushi Murai 602267893fSBrian Somers typedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *); 612267893fSBrian Somers static recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak, 622267893fSBrian Somers FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck, 632267893fSBrian Somers FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq, 642267893fSBrian Somers FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent, 652267893fSBrian Somers FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck; 662267893fSBrian Somers 672267893fSBrian Somers static const struct fsmcodedesc { 682267893fSBrian Somers recvfn *recv; 692267893fSBrian Somers unsigned check_reqid : 1; 702267893fSBrian Somers unsigned inc_reqid : 1; 712267893fSBrian Somers const char *name; 722267893fSBrian Somers } FsmCodes[] = { 732267893fSBrian Somers { FsmRecvConfigReq, 0, 0, "ConfigReq" }, 742267893fSBrian Somers { FsmRecvConfigAck, 1, 1, "ConfigAck" }, 752267893fSBrian Somers { FsmRecvConfigNak, 1, 1, "ConfigNak" }, 762267893fSBrian Somers { FsmRecvConfigRej, 1, 1, "ConfigRej" }, 772267893fSBrian Somers { FsmRecvTermReq, 0, 0, "TerminateReq" }, 782267893fSBrian Somers { FsmRecvTermAck, 1, 1, "TerminateAck" }, 792267893fSBrian Somers { FsmRecvCodeRej, 0, 0, "CodeRej" }, 802267893fSBrian Somers { FsmRecvProtoRej, 0, 0, "ProtocolRej" }, 812267893fSBrian Somers { FsmRecvEchoReq, 0, 0, "EchoRequest" }, 822267893fSBrian Somers { FsmRecvEchoRep, 0, 0, "EchoReply" }, 832267893fSBrian Somers { FsmRecvDiscReq, 0, 0, "DiscardReq" }, 842267893fSBrian Somers { FsmRecvIdent, 0, 0, "Ident" }, 852267893fSBrian Somers { FsmRecvTimeRemain,0, 0, "TimeRemain" }, 862267893fSBrian Somers { FsmRecvResetReq, 0, 0, "ResetReqt" }, 872267893fSBrian Somers { FsmRecvResetAck, 0, 1, "ResetAck" } 882267893fSBrian Somers }; 892267893fSBrian Somers 902267893fSBrian Somers static const char * 912267893fSBrian Somers Code2Nam(u_int code) 922267893fSBrian Somers { 932267893fSBrian Somers if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0]) 942267893fSBrian Somers return "Unknown"; 952267893fSBrian Somers return FsmCodes[code-1].name; 962267893fSBrian Somers } 972267893fSBrian Somers 981e991daaSBrian Somers const char * 991e991daaSBrian Somers State2Nam(u_int state) 1001e991daaSBrian Somers { 1011e991daaSBrian Somers static const char *StateNames[] = { 102af57ed9fSAtsushi Murai "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", 103927145beSBrian Somers "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", 104af57ed9fSAtsushi Murai }; 105af57ed9fSAtsushi Murai 1061e991daaSBrian Somers if (state >= sizeof StateNames / sizeof StateNames[0]) 1071e991daaSBrian Somers return "unknown"; 1081e991daaSBrian Somers return StateNames[state]; 1091e991daaSBrian Somers } 1101e991daaSBrian Somers 11171144dc5SBrian Somers static void 112b6e82f33SBrian Somers StoppedTimeout(void *v) 11371144dc5SBrian Somers { 114b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 115b6e82f33SBrian Somers 116dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name); 11749b239e0SBrian Somers if (fp->OpenTimer.state == TIMER_RUNNING) { 118dd7e2610SBrian Somers log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n", 119d47dceb8SBrian Somers fp->link->name, fp->name); 120dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 12149b239e0SBrian Somers } 12209206a6fSBrian Somers if (fp->state == ST_STOPPED) 12309206a6fSBrian Somers fsm2initial(fp); 12471144dc5SBrian Somers } 12571144dc5SBrian Somers 126af57ed9fSAtsushi Murai void 1273b0f8d2eSBrian Somers fsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, 1283b0f8d2eSBrian Somers int maxcode, int maxcfg, int LogLevel, struct bundle *bundle, 1293b0f8d2eSBrian Somers struct link *l, const struct fsm_parent *parent, 1303b0f8d2eSBrian Somers struct fsm_callbacks *fn, const char *timer_names[3]) 131af57ed9fSAtsushi Murai { 132503a7782SBrian Somers fp->name = name; 133503a7782SBrian Somers fp->proto = proto; 1343b0f8d2eSBrian Somers fp->min_code = mincode; 135503a7782SBrian Somers fp->max_code = maxcode; 1363b0f8d2eSBrian Somers fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; 137af57ed9fSAtsushi Murai fp->reqid = 1; 138af57ed9fSAtsushi Murai fp->restart = 1; 139503a7782SBrian Somers fp->maxconfig = maxcfg; 140503a7782SBrian Somers memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); 141503a7782SBrian Somers memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); 142503a7782SBrian Somers memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); 143503a7782SBrian Somers fp->LogLevel = LogLevel; 1448c07a7b2SBrian Somers fp->link = l; 1457a6f8720SBrian Somers fp->bundle = bundle; 1466d666775SBrian Somers fp->parent = parent; 147503a7782SBrian Somers fp->fn = fn; 1483b0f8d2eSBrian Somers fp->FsmTimer.name = timer_names[0]; 1493b0f8d2eSBrian Somers fp->OpenTimer.name = timer_names[1]; 1503b0f8d2eSBrian Somers fp->StoppedTimer.name = timer_names[2]; 151af57ed9fSAtsushi Murai } 152af57ed9fSAtsushi Murai 15375240ed1SBrian Somers static void 154944f7098SBrian Somers NewState(struct fsm * fp, int new) 155af57ed9fSAtsushi Murai { 156dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", 157d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state), State2Nam(new)); 158cb611434SBrian Somers if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) 159dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 160af57ed9fSAtsushi Murai fp->state = new; 16171144dc5SBrian Somers if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { 162dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 163cb611434SBrian Somers if (new == ST_STOPPED && fp->StoppedTimer.load) { 164dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 165cb611434SBrian Somers fp->StoppedTimer.func = StoppedTimeout; 166cb611434SBrian Somers fp->StoppedTimer.arg = (void *) fp; 167dd7e2610SBrian Somers timer_Start(&fp->StoppedTimer); 16871144dc5SBrian Somers } 16971144dc5SBrian Somers } 170af57ed9fSAtsushi Murai } 171af57ed9fSAtsushi Murai 172af57ed9fSAtsushi Murai void 173dd7e2610SBrian Somers fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count) 174af57ed9fSAtsushi Murai { 175af57ed9fSAtsushi Murai int plen; 176af57ed9fSAtsushi Murai struct fsmheader lh; 177af57ed9fSAtsushi Murai struct mbuf *bp; 178af57ed9fSAtsushi Murai 179dd7e2610SBrian Somers if (log_IsKept(fp->LogLevel)) { 180dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 181d47dceb8SBrian Somers fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 1822267893fSBrian Somers switch (code) { 1832267893fSBrian Somers case CODE_CONFIGREQ: 1842267893fSBrian Somers case CODE_CONFIGACK: 1852267893fSBrian Somers case CODE_CONFIGREJ: 1862267893fSBrian Somers case CODE_CONFIGNAK: 1872267893fSBrian Somers (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL); 1882267893fSBrian Somers if (count < sizeof(struct fsmconfig)) 189dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 1902267893fSBrian Somers break; 1912267893fSBrian Somers } 1922267893fSBrian Somers } 1932267893fSBrian Somers 194af57ed9fSAtsushi Murai plen = sizeof(struct fsmheader) + count; 195af57ed9fSAtsushi Murai lh.code = code; 196af57ed9fSAtsushi Murai lh.id = id; 197af57ed9fSAtsushi Murai lh.length = htons(plen); 198dd7e2610SBrian Somers bp = mbuf_Alloc(plen, MB_FSM); 19975240ed1SBrian Somers memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 200af57ed9fSAtsushi Murai if (count) 20175240ed1SBrian Somers memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 202dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "fsm_Output", bp); 203dd7e2610SBrian Somers hdlc_Output(fp->link, PRI_LINK, fp->proto, bp); 204af57ed9fSAtsushi Murai } 205af57ed9fSAtsushi Murai 20649b239e0SBrian Somers static void 20749b239e0SBrian Somers FsmOpenNow(void *v) 20849b239e0SBrian Somers { 20949b239e0SBrian Somers struct fsm *fp = (struct fsm *)v; 21049b239e0SBrian Somers 211dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 21249b239e0SBrian Somers if (fp->state <= ST_STOPPED) { 2133a2e4f62SBrian Somers if (fp->state != ST_STARTING) { 2143a2e4f62SBrian Somers /* 2153a2e4f62SBrian Somers * In practice, we're only here in ST_STOPPED (when delaying the 2163a2e4f62SBrian Somers * first config request) or ST_CLOSED (when openmode == 0). 2173a2e4f62SBrian Somers * 2183a2e4f62SBrian Somers * The ST_STOPPED bit is breaking the RFC already :-( 2193a2e4f62SBrian Somers * 2203a2e4f62SBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 2213a2e4f62SBrian Somers * required for an Open event when state == Closed, but the RFC 2223a2e4f62SBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 2233a2e4f62SBrian Somers * ie, Initial gets an `Up' event, Closing gets a RTA etc. 2243a2e4f62SBrian Somers */ 2253a2e4f62SBrian Somers (*fp->fn->LayerStart)(fp); 2263a2e4f62SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 2273a2e4f62SBrian Somers } 22849b239e0SBrian Somers FsmInitRestartCounter(fp); 22949b239e0SBrian Somers FsmSendConfigReq(fp); 23049b239e0SBrian Somers NewState(fp, ST_REQSENT); 23149b239e0SBrian Somers } 23249b239e0SBrian Somers } 23349b239e0SBrian Somers 234af57ed9fSAtsushi Murai void 235dd7e2610SBrian Somers fsm_Open(struct fsm * fp) 236af57ed9fSAtsushi Murai { 237af57ed9fSAtsushi Murai switch (fp->state) { 238af57ed9fSAtsushi Murai case ST_INITIAL: 239af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 2406d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2416d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 242af57ed9fSAtsushi Murai break; 243af57ed9fSAtsushi Murai case ST_CLOSED: 244af57ed9fSAtsushi Murai if (fp->open_mode == OPEN_PASSIVE) { 2453a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 24649b239e0SBrian Somers } else if (fp->open_mode > 0) { 24749b239e0SBrian Somers if (fp->open_mode > 1) 248dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 249d47dceb8SBrian Somers fp->link->name, fp->open_mode); 2503a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 251dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 25249b239e0SBrian Somers fp->OpenTimer.load = fp->open_mode * SECTICKS; 25349b239e0SBrian Somers fp->OpenTimer.func = FsmOpenNow; 25449b239e0SBrian Somers fp->OpenTimer.arg = (void *)fp; 255dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 25649b239e0SBrian Somers } else 25749b239e0SBrian Somers FsmOpenNow(fp); 258af57ed9fSAtsushi Murai break; 259af57ed9fSAtsushi Murai case ST_STOPPED: /* XXX: restart option */ 260af57ed9fSAtsushi Murai case ST_REQSENT: 261af57ed9fSAtsushi Murai case ST_ACKRCVD: 262af57ed9fSAtsushi Murai case ST_ACKSENT: 263af57ed9fSAtsushi Murai case ST_OPENED: /* XXX: restart option */ 264af57ed9fSAtsushi Murai break; 265af57ed9fSAtsushi Murai case ST_CLOSING: /* XXX: restart option */ 266af57ed9fSAtsushi Murai case ST_STOPPING: /* XXX: restart option */ 267af57ed9fSAtsushi Murai NewState(fp, ST_STOPPING); 268af57ed9fSAtsushi Murai break; 269af57ed9fSAtsushi Murai } 270af57ed9fSAtsushi Murai } 271af57ed9fSAtsushi Murai 272af57ed9fSAtsushi Murai void 273dd7e2610SBrian Somers fsm_Up(struct fsm * fp) 274af57ed9fSAtsushi Murai { 275af57ed9fSAtsushi Murai switch (fp->state) { 276af57ed9fSAtsushi Murai case ST_INITIAL: 277dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 2781fa665f5SBrian Somers fp->link->name); 279af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 280af57ed9fSAtsushi Murai break; 281af57ed9fSAtsushi Murai case ST_STARTING: 282af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 283af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 284af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 285af57ed9fSAtsushi Murai break; 286af57ed9fSAtsushi Murai default: 287dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 288d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 289af57ed9fSAtsushi Murai break; 290af57ed9fSAtsushi Murai } 291af57ed9fSAtsushi Murai } 292af57ed9fSAtsushi Murai 293af57ed9fSAtsushi Murai void 294dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 295af57ed9fSAtsushi Murai { 296af57ed9fSAtsushi Murai switch (fp->state) { 297af57ed9fSAtsushi Murai case ST_CLOSED: 298af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 299af57ed9fSAtsushi Murai break; 300455aabc3SBrian Somers case ST_CLOSING: 3016d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 302455aabc3SBrian Somers NewState(fp, ST_INITIAL); 3036d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 304455aabc3SBrian Somers break; 305af57ed9fSAtsushi Murai case ST_STOPPED: 306455aabc3SBrian Somers NewState(fp, ST_STARTING); 3076d666775SBrian Somers (*fp->fn->LayerStart)(fp); 3086d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 309455aabc3SBrian Somers break; 310af57ed9fSAtsushi Murai case ST_STOPPING: 311af57ed9fSAtsushi Murai case ST_REQSENT: 312af57ed9fSAtsushi Murai case ST_ACKRCVD: 313af57ed9fSAtsushi Murai case ST_ACKSENT: 314af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 315af57ed9fSAtsushi Murai break; 316af57ed9fSAtsushi Murai case ST_OPENED: 3176d666775SBrian Somers (*fp->fn->LayerDown)(fp); 318af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 3196d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 320af57ed9fSAtsushi Murai break; 321af57ed9fSAtsushi Murai } 322af57ed9fSAtsushi Murai } 323af57ed9fSAtsushi Murai 324af57ed9fSAtsushi Murai void 325dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 326af57ed9fSAtsushi Murai { 327af57ed9fSAtsushi Murai switch (fp->state) { 328af57ed9fSAtsushi Murai case ST_STARTING: 3296d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 330af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 3316d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 332af57ed9fSAtsushi Murai break; 333af57ed9fSAtsushi Murai case ST_STOPPED: 334af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 335af57ed9fSAtsushi Murai break; 336af57ed9fSAtsushi Murai case ST_STOPPING: 337af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 338af57ed9fSAtsushi Murai break; 339af57ed9fSAtsushi Murai case ST_OPENED: 3406d666775SBrian Somers (*fp->fn->LayerDown)(fp); 341455aabc3SBrian Somers FsmInitRestartCounter(fp); 342455aabc3SBrian Somers FsmSendTerminateReq(fp); 343455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3446d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 345455aabc3SBrian Somers break; 346af57ed9fSAtsushi Murai case ST_REQSENT: 347af57ed9fSAtsushi Murai case ST_ACKRCVD: 348af57ed9fSAtsushi Murai case ST_ACKSENT: 349af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 350af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 351af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 352af57ed9fSAtsushi Murai break; 353af57ed9fSAtsushi Murai } 354af57ed9fSAtsushi Murai } 355af57ed9fSAtsushi Murai 356af57ed9fSAtsushi Murai /* 357af57ed9fSAtsushi Murai * Send functions 358af57ed9fSAtsushi Murai */ 35975240ed1SBrian Somers static void 360944f7098SBrian Somers FsmSendConfigReq(struct fsm * fp) 361af57ed9fSAtsushi Murai { 362af57ed9fSAtsushi Murai if (--fp->maxconfig > 0) { 36383d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 364dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 365af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 366af57ed9fSAtsushi Murai } else { 367dd7e2610SBrian Somers fsm_Close(fp); 368af57ed9fSAtsushi Murai } 369af57ed9fSAtsushi Murai } 370af57ed9fSAtsushi Murai 37175240ed1SBrian Somers static void 372944f7098SBrian Somers FsmSendTerminateReq(struct fsm *fp) 373af57ed9fSAtsushi Murai { 374dd7e2610SBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0); 3752267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 376dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 377af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 378af57ed9fSAtsushi Murai } 379af57ed9fSAtsushi Murai 380af57ed9fSAtsushi Murai /* 381af57ed9fSAtsushi Murai * Timeout actions 382af57ed9fSAtsushi Murai */ 38375240ed1SBrian Somers static void 384b6e82f33SBrian Somers FsmTimeout(void *v) 385af57ed9fSAtsushi Murai { 386b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 387b6e82f33SBrian Somers 388af57ed9fSAtsushi Murai if (fp->restart) { 389af57ed9fSAtsushi Murai switch (fp->state) { 390af57ed9fSAtsushi Murai case ST_CLOSING: 391af57ed9fSAtsushi Murai case ST_STOPPING: 392af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 393af57ed9fSAtsushi Murai break; 394af57ed9fSAtsushi Murai case ST_REQSENT: 395af57ed9fSAtsushi Murai case ST_ACKSENT: 396af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 397af57ed9fSAtsushi Murai break; 398af57ed9fSAtsushi Murai case ST_ACKRCVD: 399af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 400af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 401af57ed9fSAtsushi Murai break; 402af57ed9fSAtsushi Murai } 403dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 404af57ed9fSAtsushi Murai } else { 405af57ed9fSAtsushi Murai switch (fp->state) { 406af57ed9fSAtsushi Murai case ST_CLOSING: 4076d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 408af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 4096d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 410af57ed9fSAtsushi Murai break; 411af57ed9fSAtsushi Murai case ST_STOPPING: 4126d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 413af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4146d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 415af57ed9fSAtsushi Murai break; 416af57ed9fSAtsushi Murai case ST_REQSENT: /* XXX: 3p */ 417af57ed9fSAtsushi Murai case ST_ACKSENT: 418af57ed9fSAtsushi Murai case ST_ACKRCVD: 4196d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 420af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4216d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 422af57ed9fSAtsushi Murai break; 423af57ed9fSAtsushi Murai } 424af57ed9fSAtsushi Murai } 425af57ed9fSAtsushi Murai } 426af57ed9fSAtsushi Murai 42775240ed1SBrian Somers static void 428944f7098SBrian Somers FsmInitRestartCounter(struct fsm * fp) 429af57ed9fSAtsushi Murai { 430dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 431af57ed9fSAtsushi Murai fp->FsmTimer.func = FsmTimeout; 432af57ed9fSAtsushi Murai fp->FsmTimer.arg = (void *) fp; 43383d1af55SBrian Somers (*fp->fn->InitRestartCounter)(fp); 434af57ed9fSAtsushi Murai } 435af57ed9fSAtsushi Murai 436af57ed9fSAtsushi Murai /* 437af57ed9fSAtsushi Murai * Actions when receive packets 438af57ed9fSAtsushi Murai */ 43975240ed1SBrian Somers static void 440944f7098SBrian Somers FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 441944f7098SBrian Somers /* RCR */ 442af57ed9fSAtsushi Murai { 44330c2f2ffSBrian Somers struct fsm_decode dec; 44453c9f6c0SAtsushi Murai int plen, flen; 445af57ed9fSAtsushi Murai int ackaction = 0; 446af57ed9fSAtsushi Murai 447dd7e2610SBrian Somers plen = mbuf_Length(bp); 44870ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 44953c9f6c0SAtsushi Murai if (plen < flen) { 450a33b2ef7SBrian Somers log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 451d47dceb8SBrian Somers fp->link->name, plen, flen); 452dd7e2610SBrian Somers mbuf_Free(bp); 453af57ed9fSAtsushi Murai return; 454af57ed9fSAtsushi Murai } 455af57ed9fSAtsushi Murai 456af57ed9fSAtsushi Murai /* 457af57ed9fSAtsushi Murai * Check and process easy case 458af57ed9fSAtsushi Murai */ 459af57ed9fSAtsushi Murai switch (fp->state) { 460af57ed9fSAtsushi Murai case ST_INITIAL: 46106337856SBrian Somers if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 46206337856SBrian Somers /* 46306337856SBrian Somers * ccp_SetOpenMode() leaves us in initial if we're disabling 46406337856SBrian Somers * & denying everything. This is a bit smelly, we know that 46506337856SBrian Somers * ``bp'' really has ``fsmheader'' in front of it, and CCP_PROTO 46606337856SBrian Somers * in front of that. CCP_PROTO isn't compressed either 'cos it 46706337856SBrian Somers * doesn't begin with 0x00.... 46806337856SBrian Somers */ 46906337856SBrian Somers bp->offset -= sizeof(struct fsmheader) + 2; 47006337856SBrian Somers bp->cnt += sizeof(struct fsmheader) + 2; 47106337856SBrian Somers lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->cnt); 47206337856SBrian Somers mbuf_Free(bp); 47306337856SBrian Somers return; 47406337856SBrian Somers } 47506337856SBrian Somers /* Drop through */ 476af57ed9fSAtsushi Murai case ST_STARTING: 477dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 478d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 479dd7e2610SBrian Somers mbuf_Free(bp); 480af57ed9fSAtsushi Murai return; 481af57ed9fSAtsushi Murai case ST_CLOSED: 4822267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 483dd7e2610SBrian Somers mbuf_Free(bp); 484af57ed9fSAtsushi Murai return; 485af57ed9fSAtsushi Murai case ST_CLOSING: 486dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 487d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 488a9c503afSBrian Somers case ST_STOPPING: 489dd7e2610SBrian Somers mbuf_Free(bp); 490af57ed9fSAtsushi Murai return; 491af57ed9fSAtsushi Murai } 492af57ed9fSAtsushi Murai 49330c2f2ffSBrian Somers dec.ackend = dec.ack; 49430c2f2ffSBrian Somers dec.nakend = dec.nak; 49530c2f2ffSBrian Somers dec.rejend = dec.rej; 49630c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec); 4972267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 498dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 499af57ed9fSAtsushi Murai 50030c2f2ffSBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 501af57ed9fSAtsushi Murai ackaction = 1; 502af57ed9fSAtsushi Murai 503af57ed9fSAtsushi Murai switch (fp->state) { 504af57ed9fSAtsushi Murai case ST_OPENED: 5056d666775SBrian Somers (*fp->fn->LayerDown)(fp); 506af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 5076d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 508af57ed9fSAtsushi Murai break; 509af57ed9fSAtsushi Murai case ST_STOPPED: 510af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 511af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 512af57ed9fSAtsushi Murai break; 513af57ed9fSAtsushi Murai } 514af57ed9fSAtsushi Murai 51530c2f2ffSBrian Somers if (dec.rejend != dec.rej) 516dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej); 51730c2f2ffSBrian Somers if (dec.nakend != dec.nak) 518dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak); 519af57ed9fSAtsushi Murai if (ackaction) 520dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack); 521af57ed9fSAtsushi Murai 522af57ed9fSAtsushi Murai switch (fp->state) { 523af57ed9fSAtsushi Murai case ST_OPENED: 524455aabc3SBrian Somers case ST_STOPPED: 525af57ed9fSAtsushi Murai if (ackaction) 526af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 527af57ed9fSAtsushi Murai else 528af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 529af57ed9fSAtsushi Murai break; 530af57ed9fSAtsushi Murai case ST_REQSENT: 531af57ed9fSAtsushi Murai if (ackaction) 532af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 533af57ed9fSAtsushi Murai break; 534af57ed9fSAtsushi Murai case ST_ACKRCVD: 535af57ed9fSAtsushi Murai if (ackaction) { 536af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5376f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5386d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5396f384573SBrian Somers else { 5406f384573SBrian Somers (*fp->fn->LayerDown)(fp); 5416f384573SBrian Somers FsmInitRestartCounter(fp); 5426f384573SBrian Somers FsmSendTerminateReq(fp); 5436f384573SBrian Somers NewState(fp, ST_CLOSING); 5446f384573SBrian Somers } 545af57ed9fSAtsushi Murai } 546af57ed9fSAtsushi Murai break; 547af57ed9fSAtsushi Murai case ST_ACKSENT: 548af57ed9fSAtsushi Murai if (!ackaction) 549af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 550af57ed9fSAtsushi Murai break; 551af57ed9fSAtsushi Murai } 552dd7e2610SBrian Somers mbuf_Free(bp); 553af57ed9fSAtsushi Murai } 554af57ed9fSAtsushi Murai 55575240ed1SBrian Somers static void 556944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 557944f7098SBrian Somers /* RCA */ 558af57ed9fSAtsushi Murai { 559af57ed9fSAtsushi Murai switch (fp->state) { 560af57ed9fSAtsushi Murai case ST_CLOSED: 561af57ed9fSAtsushi Murai case ST_STOPPED: 5622267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 563af57ed9fSAtsushi Murai break; 564af57ed9fSAtsushi Murai case ST_CLOSING: 565af57ed9fSAtsushi Murai case ST_STOPPING: 566af57ed9fSAtsushi Murai break; 567af57ed9fSAtsushi Murai case ST_REQSENT: 568af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 569af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 570af57ed9fSAtsushi Murai break; 571af57ed9fSAtsushi Murai case ST_ACKRCVD: 572af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 573af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 574af57ed9fSAtsushi Murai break; 575af57ed9fSAtsushi Murai case ST_ACKSENT: 576af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 577af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5786f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5796d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5806f384573SBrian Somers else { 5816f384573SBrian Somers (*fp->fn->LayerDown)(fp); 5826f384573SBrian Somers FsmInitRestartCounter(fp); 5836f384573SBrian Somers FsmSendTerminateReq(fp); 5846f384573SBrian Somers NewState(fp, ST_CLOSING); 5856f384573SBrian Somers } 586af57ed9fSAtsushi Murai break; 587af57ed9fSAtsushi Murai case ST_OPENED: 5886d666775SBrian Somers (*fp->fn->LayerDown)(fp); 589af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 590af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 5916d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 592af57ed9fSAtsushi Murai break; 593af57ed9fSAtsushi Murai } 594dd7e2610SBrian Somers mbuf_Free(bp); 595af57ed9fSAtsushi Murai } 596af57ed9fSAtsushi Murai 59775240ed1SBrian Somers static void 598944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 599944f7098SBrian Somers /* RCN */ 600af57ed9fSAtsushi Murai { 60130c2f2ffSBrian Somers struct fsm_decode dec; 60253c9f6c0SAtsushi Murai int plen, flen; 603af57ed9fSAtsushi Murai 604dd7e2610SBrian Somers plen = mbuf_Length(bp); 60570ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 60653c9f6c0SAtsushi Murai if (plen < flen) { 607dd7e2610SBrian Somers mbuf_Free(bp); 608af57ed9fSAtsushi Murai return; 609af57ed9fSAtsushi Murai } 610af57ed9fSAtsushi Murai 611af57ed9fSAtsushi Murai /* 612af57ed9fSAtsushi Murai * Check and process easy case 613af57ed9fSAtsushi Murai */ 614af57ed9fSAtsushi Murai switch (fp->state) { 615af57ed9fSAtsushi Murai case ST_INITIAL: 616af57ed9fSAtsushi Murai case ST_STARTING: 617dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 618d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 619dd7e2610SBrian Somers mbuf_Free(bp); 620af57ed9fSAtsushi Murai return; 621af57ed9fSAtsushi Murai case ST_CLOSED: 622af57ed9fSAtsushi Murai case ST_STOPPED: 6232267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 624dd7e2610SBrian Somers mbuf_Free(bp); 625af57ed9fSAtsushi Murai return; 626af57ed9fSAtsushi Murai case ST_CLOSING: 627af57ed9fSAtsushi Murai case ST_STOPPING: 628dd7e2610SBrian Somers mbuf_Free(bp); 629af57ed9fSAtsushi Murai return; 630af57ed9fSAtsushi Murai } 631af57ed9fSAtsushi Murai 63230c2f2ffSBrian Somers dec.ackend = dec.ack; 63330c2f2ffSBrian Somers dec.nakend = dec.nak; 63430c2f2ffSBrian Somers dec.rejend = dec.rej; 63530c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); 6362267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 637dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 638af57ed9fSAtsushi Murai 639af57ed9fSAtsushi Murai switch (fp->state) { 640af57ed9fSAtsushi Murai case ST_REQSENT: 641af57ed9fSAtsushi Murai case ST_ACKSENT: 642af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 643af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 644af57ed9fSAtsushi Murai break; 645af57ed9fSAtsushi Murai case ST_OPENED: 6466d666775SBrian Somers (*fp->fn->LayerDown)(fp); 647455aabc3SBrian Somers FsmSendConfigReq(fp); 648455aabc3SBrian Somers NewState(fp, ST_REQSENT); 6496d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 650455aabc3SBrian Somers break; 651af57ed9fSAtsushi Murai case ST_ACKRCVD: 652af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 653af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 654af57ed9fSAtsushi Murai break; 655af57ed9fSAtsushi Murai } 656af57ed9fSAtsushi Murai 657dd7e2610SBrian Somers mbuf_Free(bp); 658af57ed9fSAtsushi Murai } 659af57ed9fSAtsushi Murai 66075240ed1SBrian Somers static void 661944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 662944f7098SBrian Somers /* RTR */ 663af57ed9fSAtsushi Murai { 664af57ed9fSAtsushi Murai switch (fp->state) { 665af57ed9fSAtsushi Murai case ST_INITIAL: 666af57ed9fSAtsushi Murai case ST_STARTING: 667dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 668d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 669af57ed9fSAtsushi Murai break; 670af57ed9fSAtsushi Murai case ST_CLOSED: 671af57ed9fSAtsushi Murai case ST_STOPPED: 672af57ed9fSAtsushi Murai case ST_CLOSING: 673af57ed9fSAtsushi Murai case ST_STOPPING: 674af57ed9fSAtsushi Murai case ST_REQSENT: 6752267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 676af57ed9fSAtsushi Murai break; 677af57ed9fSAtsushi Murai case ST_ACKRCVD: 678af57ed9fSAtsushi Murai case ST_ACKSENT: 6792267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 680af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 681af57ed9fSAtsushi Murai break; 682af57ed9fSAtsushi Murai case ST_OPENED: 6836d666775SBrian Somers (*fp->fn->LayerDown)(fp); 6842267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 68574d14b4cSBrian Somers FsmInitRestartCounter(fp); 686dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 6878f2fa0eeSBrian Somers fp->restart = 0; 6888f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 6896d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 690af57ed9fSAtsushi Murai break; 691af57ed9fSAtsushi Murai } 692dd7e2610SBrian Somers mbuf_Free(bp); 693af57ed9fSAtsushi Murai } 694af57ed9fSAtsushi Murai 69575240ed1SBrian Somers static void 696944f7098SBrian Somers FsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 697944f7098SBrian Somers /* RTA */ 698af57ed9fSAtsushi Murai { 699af57ed9fSAtsushi Murai switch (fp->state) { 700af57ed9fSAtsushi Murai case ST_CLOSING: 7016d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 702af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 7036d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 704af57ed9fSAtsushi Murai break; 705af57ed9fSAtsushi Murai case ST_STOPPING: 7066d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 707af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 7086d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 709af57ed9fSAtsushi Murai break; 710af57ed9fSAtsushi Murai case ST_ACKRCVD: 711af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 712af57ed9fSAtsushi Murai break; 713af57ed9fSAtsushi Murai case ST_OPENED: 7146d666775SBrian Somers (*fp->fn->LayerDown)(fp); 715af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 716af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 7176d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 718af57ed9fSAtsushi Murai break; 719af57ed9fSAtsushi Murai } 720dd7e2610SBrian Somers mbuf_Free(bp); 721af57ed9fSAtsushi Murai } 722af57ed9fSAtsushi Murai 72375240ed1SBrian Somers static void 724944f7098SBrian Somers FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 725944f7098SBrian Somers /* RCJ */ 726af57ed9fSAtsushi Murai { 72730c2f2ffSBrian Somers struct fsm_decode dec; 72853c9f6c0SAtsushi Murai int plen, flen; 729af57ed9fSAtsushi Murai 730dd7e2610SBrian Somers plen = mbuf_Length(bp); 73170ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 73253c9f6c0SAtsushi Murai if (plen < flen) { 733dd7e2610SBrian Somers mbuf_Free(bp); 734af57ed9fSAtsushi Murai return; 735af57ed9fSAtsushi Murai } 736af57ed9fSAtsushi Murai 737af57ed9fSAtsushi Murai /* 738af57ed9fSAtsushi Murai * Check and process easy case 739af57ed9fSAtsushi Murai */ 740af57ed9fSAtsushi Murai switch (fp->state) { 741af57ed9fSAtsushi Murai case ST_INITIAL: 742af57ed9fSAtsushi Murai case ST_STARTING: 743dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 744d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 745dd7e2610SBrian Somers mbuf_Free(bp); 746af57ed9fSAtsushi Murai return; 747af57ed9fSAtsushi Murai case ST_CLOSED: 748af57ed9fSAtsushi Murai case ST_STOPPED: 7492267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 750dd7e2610SBrian Somers mbuf_Free(bp); 751af57ed9fSAtsushi Murai return; 752af57ed9fSAtsushi Murai case ST_CLOSING: 753af57ed9fSAtsushi Murai case ST_STOPPING: 754dd7e2610SBrian Somers mbuf_Free(bp); 755af57ed9fSAtsushi Murai return; 756af57ed9fSAtsushi Murai } 757af57ed9fSAtsushi Murai 75830c2f2ffSBrian Somers dec.ackend = dec.ack; 75930c2f2ffSBrian Somers dec.nakend = dec.nak; 76030c2f2ffSBrian Somers dec.rejend = dec.rej; 76130c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); 7622267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 763dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 764af57ed9fSAtsushi Murai 765af57ed9fSAtsushi Murai switch (fp->state) { 766af57ed9fSAtsushi Murai case ST_REQSENT: 767af57ed9fSAtsushi Murai case ST_ACKSENT: 768af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 769af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 770af57ed9fSAtsushi Murai break; 771af57ed9fSAtsushi Murai case ST_OPENED: 7726d666775SBrian Somers (*fp->fn->LayerDown)(fp); 773455aabc3SBrian Somers FsmSendConfigReq(fp); 774455aabc3SBrian Somers NewState(fp, ST_REQSENT); 7756d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 776455aabc3SBrian Somers break; 777af57ed9fSAtsushi Murai case ST_ACKRCVD: 778af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 779af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 780af57ed9fSAtsushi Murai break; 781af57ed9fSAtsushi Murai } 782dd7e2610SBrian Somers mbuf_Free(bp); 783af57ed9fSAtsushi Murai } 784af57ed9fSAtsushi Murai 78575240ed1SBrian Somers static void 786944f7098SBrian Somers FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 787af57ed9fSAtsushi Murai { 788dd7e2610SBrian Somers mbuf_Free(bp); 789af57ed9fSAtsushi Murai } 790af57ed9fSAtsushi Murai 79175240ed1SBrian Somers static void 792944f7098SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 793af57ed9fSAtsushi Murai { 7948c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 795af57ed9fSAtsushi Murai u_short *sp, proto; 796af57ed9fSAtsushi Murai 797af57ed9fSAtsushi Murai sp = (u_short *)MBUF_CTOP(bp); 798af57ed9fSAtsushi Murai proto = ntohs(*sp); 799dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 800d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 801af57ed9fSAtsushi Murai 802af57ed9fSAtsushi Murai switch (proto) { 803af57ed9fSAtsushi Murai case PROTO_LQR: 8048c07a7b2SBrian Somers if (p) 805dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 8068c07a7b2SBrian Somers else 807dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 808d47dceb8SBrian Somers fp->link->name); 809af57ed9fSAtsushi Murai break; 810af57ed9fSAtsushi Murai case PROTO_CCP: 811dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 8123b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 8136d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 814af57ed9fSAtsushi Murai switch (fp->state) { 815af57ed9fSAtsushi Murai case ST_CLOSED: 816af57ed9fSAtsushi Murai case ST_CLOSING: 817af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 818af57ed9fSAtsushi Murai default: 819af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 820af57ed9fSAtsushi Murai break; 821af57ed9fSAtsushi Murai } 8226d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 823dc0fdb6bSBrian Somers } 8241ae349f5Scvs2svn break; 825673903ecSBrian Somers case PROTO_MP: 826673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 827673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 828673903ecSBrian Somers 829673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 830dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 831d47dceb8SBrian Somers fp->link->name); 832dd7e2610SBrian Somers fsm_Close(fp); 833673903ecSBrian Somers } 834673903ecSBrian Somers } 835af57ed9fSAtsushi Murai break; 836af57ed9fSAtsushi Murai } 837dd7e2610SBrian Somers mbuf_Free(bp); 838af57ed9fSAtsushi Murai } 839af57ed9fSAtsushi Murai 84075240ed1SBrian Somers static void 841944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 842af57ed9fSAtsushi Murai { 843dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 844af57ed9fSAtsushi Murai u_char *cp; 845fe3125a0SBrian Somers u_int32_t magic; 846af57ed9fSAtsushi Murai 847dc0fdb6bSBrian Somers if (lcp) { 848af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 849fe3125a0SBrian Somers magic = ntohl(*(u_int32_t *)cp); 850dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 851dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: Error: His magic is bad!!\n", 852d47dceb8SBrian Somers fp->link->name); 853af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 854af57ed9fSAtsushi Murai } 855af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 856fe3125a0SBrian Somers *(u_int32_t *)cp = htonl(lcp->want_magic); /* local magic */ 857dd7e2610SBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, mbuf_Length(bp)); 858af57ed9fSAtsushi Murai } 859dc0fdb6bSBrian Somers } 860dd7e2610SBrian Somers mbuf_Free(bp); 861af57ed9fSAtsushi Murai } 862af57ed9fSAtsushi Murai 86375240ed1SBrian Somers static void 864944f7098SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 865af57ed9fSAtsushi Murai { 866dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 867fe3125a0SBrian Somers u_int32_t magic; 868af57ed9fSAtsushi Murai 869dc0fdb6bSBrian Somers if (lcp) { 870fe3125a0SBrian Somers magic = ntohl(*(u_int32_t *)MBUF_CTOP(bp)); 871879ed6faSBrian Somers /* Tolerate echo replies with either magic number */ 872dc0fdb6bSBrian Somers if (magic != 0 && magic != lcp->his_magic && magic != lcp->want_magic) { 873dd7e2610SBrian Somers log_Printf(LogWARN, 874d47dceb8SBrian Somers "%s: RecvEchoRep: Bad magic: expected 0x%08x, got: 0x%08x\n", 875d47dceb8SBrian Somers fp->link->name, lcp->his_magic, magic); 87685c59f05SJoerg Wunsch /* 877fe3125a0SBrian Somers * XXX: We should send terminate request. But poor implementations may 878fe3125a0SBrian Somers * die as a result. 879af57ed9fSAtsushi Murai */ 880af57ed9fSAtsushi Murai } 881dd7e2610SBrian Somers lqr_RecvEcho(fp, bp); 882dc0fdb6bSBrian Somers } 883dd7e2610SBrian Somers mbuf_Free(bp); 884af57ed9fSAtsushi Murai } 885af57ed9fSAtsushi Murai 88675240ed1SBrian Somers static void 887944f7098SBrian Somers FsmRecvDiscReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 888af57ed9fSAtsushi Murai { 889dd7e2610SBrian Somers mbuf_Free(bp); 890af57ed9fSAtsushi Murai } 891af57ed9fSAtsushi Murai 89275240ed1SBrian Somers static void 893944f7098SBrian Somers FsmRecvIdent(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 894af57ed9fSAtsushi Murai { 895dd7e2610SBrian Somers mbuf_Free(bp); 896af57ed9fSAtsushi Murai } 897af57ed9fSAtsushi Murai 89875240ed1SBrian Somers static void 899944f7098SBrian Somers FsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 900af57ed9fSAtsushi Murai { 901dd7e2610SBrian Somers mbuf_Free(bp); 902af57ed9fSAtsushi Murai } 903af57ed9fSAtsushi Murai 90475240ed1SBrian Somers static void 905944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 906af57ed9fSAtsushi Murai { 907503a7782SBrian Somers (*fp->fn->RecvResetReq)(fp); 90898baf7c8SBrian Somers /* 90998baf7c8SBrian Somers * All sendable compressed packets are queued in the PRI_NORMAL modem 91098baf7c8SBrian Somers * output queue.... dump 'em to the priority queue so that they arrive 91198baf7c8SBrian Somers * at the peer before our ResetAck. 91298baf7c8SBrian Somers */ 9138c07a7b2SBrian Somers link_SequenceQueue(fp->link); 914dd7e2610SBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0); 915dd7e2610SBrian Somers mbuf_Free(bp); 916af57ed9fSAtsushi Murai } 917af57ed9fSAtsushi Murai 91875240ed1SBrian Somers static void 919944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 920af57ed9fSAtsushi Murai { 921503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 922dd7e2610SBrian Somers mbuf_Free(bp); 923af57ed9fSAtsushi Murai } 924af57ed9fSAtsushi Murai 925af57ed9fSAtsushi Murai void 926dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 927af57ed9fSAtsushi Murai { 928af57ed9fSAtsushi Murai int len; 929af57ed9fSAtsushi Murai struct fsmheader *lhp; 9300053cc58SBrian Somers const struct fsmcodedesc *codep; 931af57ed9fSAtsushi Murai 932dd7e2610SBrian Somers len = mbuf_Length(bp); 933af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 934dd7e2610SBrian Somers mbuf_Free(bp); 935af57ed9fSAtsushi Murai return; 936af57ed9fSAtsushi Murai } 937af57ed9fSAtsushi Murai lhp = (struct fsmheader *) MBUF_CTOP(bp); 9383b0f8d2eSBrian Somers if (lhp->code < fp->min_code || lhp->code > fp->max_code || 9397308ec68SBrian Somers lhp->code > sizeof FsmCodes / sizeof *FsmCodes) { 9403b0f8d2eSBrian Somers /* 9413b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 9423b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 9433b0f8d2eSBrian Somers */ 9443b0f8d2eSBrian Somers static u_char id; 945d93d3a9cSBrian Somers 946dd7e2610SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->cnt); 947dd7e2610SBrian Somers mbuf_Free(bp); 948af57ed9fSAtsushi Murai return; 949af57ed9fSAtsushi Murai } 950af57ed9fSAtsushi Murai bp->offset += sizeof(struct fsmheader); 951af57ed9fSAtsushi Murai bp->cnt -= sizeof(struct fsmheader); 952af57ed9fSAtsushi Murai 953af57ed9fSAtsushi Murai codep = FsmCodes + lhp->code - 1; 9541342caedSBrian Somers if (lhp->id != fp->reqid && codep->check_reqid && 9551342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 956dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 957d47dceb8SBrian Somers fp->link->name, codep->name, lhp->id, fp->reqid); 9582267893fSBrian Somers return; 9592267893fSBrian Somers } 9602267893fSBrian Somers 961dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 962d47dceb8SBrian Somers fp->link->name, codep->name, lhp->id, State2Nam(fp->state)); 9632267893fSBrian Somers 964dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 965dd7e2610SBrian Somers mbuf_Log(); 9662267893fSBrian Somers 9672267893fSBrian Somers if (codep->inc_reqid && (lhp->id == fp->reqid || 9681342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 9692267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 9702267893fSBrian Somers 9711342caedSBrian Somers (*codep->recv)(fp, lhp, bp); 9722267893fSBrian Somers 973dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 974dd7e2610SBrian Somers mbuf_Log(); 9751ae349f5Scvs2svn } 976503a7782SBrian Somers 977503a7782SBrian Somers void 978dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 979503a7782SBrian Somers { 980dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 981d47dceb8SBrian Somers fp->link->name); 982503a7782SBrian Somers } 983503a7782SBrian Somers 984503a7782SBrian Somers void 985dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 986503a7782SBrian Somers { 987dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 988d47dceb8SBrian Somers fp->link->name); 989af57ed9fSAtsushi Murai } 99009206a6fSBrian Somers 99109206a6fSBrian Somers void 992897f9429SBrian Somers fsm_Reopen(struct fsm *fp) 993897f9429SBrian Somers { 994897f9429SBrian Somers if (fp->state == ST_OPENED) { 995897f9429SBrian Somers (*fp->fn->LayerDown)(fp); 996897f9429SBrian Somers FsmInitRestartCounter(fp); 997897f9429SBrian Somers FsmSendConfigReq(fp); 998897f9429SBrian Somers NewState(fp, ST_REQSENT); 999897f9429SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 1000897f9429SBrian Somers } 1001897f9429SBrian Somers } 1002897f9429SBrian Somers 1003897f9429SBrian Somers void 100409206a6fSBrian Somers fsm2initial(struct fsm *fp) 100509206a6fSBrian Somers { 100609206a6fSBrian Somers if (fp->state == ST_STOPPED) 100709206a6fSBrian Somers fsm_Close(fp); 100809206a6fSBrian Somers if (fp->state > ST_INITIAL) 100909206a6fSBrian Somers fsm_Down(fp); 101009206a6fSBrian Somers if (fp->state > ST_INITIAL) 101109206a6fSBrian Somers fsm_Close(fp); 101209206a6fSBrian Somers } 1013