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 * 20a33b2ef7SBrian Somers * $Id: fsm.c,v 1.29 1998/06/15 19:06:42 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 } 1223b0f8d2eSBrian Somers if (fp->state == ST_STOPPED) { 1233b0f8d2eSBrian Somers /* Force ourselves back to initial */ 124dd7e2610SBrian Somers fsm_Down(fp); 125dd7e2610SBrian Somers fsm_Close(fp); 1263b0f8d2eSBrian Somers } 12771144dc5SBrian Somers } 12871144dc5SBrian Somers 129af57ed9fSAtsushi Murai void 1303b0f8d2eSBrian Somers fsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, 1313b0f8d2eSBrian Somers int maxcode, int maxcfg, int LogLevel, struct bundle *bundle, 1323b0f8d2eSBrian Somers struct link *l, const struct fsm_parent *parent, 1333b0f8d2eSBrian Somers struct fsm_callbacks *fn, const char *timer_names[3]) 134af57ed9fSAtsushi Murai { 135503a7782SBrian Somers fp->name = name; 136503a7782SBrian Somers fp->proto = proto; 1373b0f8d2eSBrian Somers fp->min_code = mincode; 138503a7782SBrian Somers fp->max_code = maxcode; 1393b0f8d2eSBrian Somers fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; 140af57ed9fSAtsushi Murai fp->reqid = 1; 141af57ed9fSAtsushi Murai fp->restart = 1; 142503a7782SBrian Somers fp->maxconfig = maxcfg; 143503a7782SBrian Somers memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); 144503a7782SBrian Somers memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); 145503a7782SBrian Somers memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); 146503a7782SBrian Somers fp->LogLevel = LogLevel; 1478c07a7b2SBrian Somers fp->link = l; 1487a6f8720SBrian Somers fp->bundle = bundle; 1496d666775SBrian Somers fp->parent = parent; 150503a7782SBrian Somers fp->fn = fn; 1513b0f8d2eSBrian Somers fp->FsmTimer.name = timer_names[0]; 1523b0f8d2eSBrian Somers fp->OpenTimer.name = timer_names[1]; 1533b0f8d2eSBrian Somers fp->StoppedTimer.name = timer_names[2]; 154af57ed9fSAtsushi Murai } 155af57ed9fSAtsushi Murai 15675240ed1SBrian Somers static void 157944f7098SBrian Somers NewState(struct fsm * fp, int new) 158af57ed9fSAtsushi Murai { 159dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", 160d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state), State2Nam(new)); 161cb611434SBrian Somers if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) 162dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 163af57ed9fSAtsushi Murai fp->state = new; 16471144dc5SBrian Somers if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { 165dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 166cb611434SBrian Somers if (new == ST_STOPPED && fp->StoppedTimer.load) { 167dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 168cb611434SBrian Somers fp->StoppedTimer.func = StoppedTimeout; 169cb611434SBrian Somers fp->StoppedTimer.arg = (void *) fp; 170dd7e2610SBrian Somers timer_Start(&fp->StoppedTimer); 17171144dc5SBrian Somers } 17271144dc5SBrian Somers } 173af57ed9fSAtsushi Murai } 174af57ed9fSAtsushi Murai 175af57ed9fSAtsushi Murai void 176dd7e2610SBrian Somers fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count) 177af57ed9fSAtsushi Murai { 178af57ed9fSAtsushi Murai int plen; 179af57ed9fSAtsushi Murai struct fsmheader lh; 180af57ed9fSAtsushi Murai struct mbuf *bp; 181af57ed9fSAtsushi Murai 182dd7e2610SBrian Somers if (log_IsKept(fp->LogLevel)) { 183dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 184d47dceb8SBrian Somers fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 1852267893fSBrian Somers switch (code) { 1862267893fSBrian Somers case CODE_CONFIGREQ: 1872267893fSBrian Somers case CODE_CONFIGACK: 1882267893fSBrian Somers case CODE_CONFIGREJ: 1892267893fSBrian Somers case CODE_CONFIGNAK: 1902267893fSBrian Somers (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL); 1912267893fSBrian Somers if (count < sizeof(struct fsmconfig)) 192dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 1932267893fSBrian Somers break; 1942267893fSBrian Somers } 1952267893fSBrian Somers } 1962267893fSBrian Somers 197af57ed9fSAtsushi Murai plen = sizeof(struct fsmheader) + count; 198af57ed9fSAtsushi Murai lh.code = code; 199af57ed9fSAtsushi Murai lh.id = id; 200af57ed9fSAtsushi Murai lh.length = htons(plen); 201dd7e2610SBrian Somers bp = mbuf_Alloc(plen, MB_FSM); 20275240ed1SBrian Somers memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 203af57ed9fSAtsushi Murai if (count) 20475240ed1SBrian Somers memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 205dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "fsm_Output", bp); 206dd7e2610SBrian Somers hdlc_Output(fp->link, PRI_LINK, fp->proto, bp); 207af57ed9fSAtsushi Murai } 208af57ed9fSAtsushi Murai 20949b239e0SBrian Somers static void 21049b239e0SBrian Somers FsmOpenNow(void *v) 21149b239e0SBrian Somers { 21249b239e0SBrian Somers struct fsm *fp = (struct fsm *)v; 21349b239e0SBrian Somers 214dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 21549b239e0SBrian Somers if (fp->state <= ST_STOPPED) { 21649b239e0SBrian Somers FsmInitRestartCounter(fp); 21749b239e0SBrian Somers FsmSendConfigReq(fp); 21849b239e0SBrian Somers NewState(fp, ST_REQSENT); 21949b239e0SBrian Somers } 22049b239e0SBrian Somers } 22149b239e0SBrian Somers 222af57ed9fSAtsushi Murai void 223dd7e2610SBrian Somers fsm_Open(struct fsm * fp) 224af57ed9fSAtsushi Murai { 225af57ed9fSAtsushi Murai switch (fp->state) { 226af57ed9fSAtsushi Murai case ST_INITIAL: 227af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 2286d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2296d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 230af57ed9fSAtsushi Murai break; 231af57ed9fSAtsushi Murai case ST_CLOSED: 232af57ed9fSAtsushi Murai if (fp->open_mode == OPEN_PASSIVE) { 233af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 23449b239e0SBrian Somers } else if (fp->open_mode > 0) { 23549b239e0SBrian Somers if (fp->open_mode > 1) 236dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 237d47dceb8SBrian Somers fp->link->name, fp->open_mode); 23849b239e0SBrian Somers NewState(fp, ST_STOPPED); 239dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 24049b239e0SBrian Somers fp->OpenTimer.load = fp->open_mode * SECTICKS; 24149b239e0SBrian Somers fp->OpenTimer.func = FsmOpenNow; 24249b239e0SBrian Somers fp->OpenTimer.arg = (void *)fp; 243dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 24449b239e0SBrian Somers } else 24549b239e0SBrian Somers FsmOpenNow(fp); 246af57ed9fSAtsushi Murai break; 247af57ed9fSAtsushi Murai case ST_STOPPED: /* XXX: restart option */ 248af57ed9fSAtsushi Murai case ST_REQSENT: 249af57ed9fSAtsushi Murai case ST_ACKRCVD: 250af57ed9fSAtsushi Murai case ST_ACKSENT: 251af57ed9fSAtsushi Murai case ST_OPENED: /* XXX: restart option */ 252af57ed9fSAtsushi Murai break; 253af57ed9fSAtsushi Murai case ST_CLOSING: /* XXX: restart option */ 254af57ed9fSAtsushi Murai case ST_STOPPING: /* XXX: restart option */ 255af57ed9fSAtsushi Murai NewState(fp, ST_STOPPING); 256af57ed9fSAtsushi Murai break; 257af57ed9fSAtsushi Murai } 258af57ed9fSAtsushi Murai } 259af57ed9fSAtsushi Murai 260af57ed9fSAtsushi Murai void 261dd7e2610SBrian Somers fsm_Up(struct fsm * fp) 262af57ed9fSAtsushi Murai { 263af57ed9fSAtsushi Murai switch (fp->state) { 264af57ed9fSAtsushi Murai case ST_INITIAL: 265dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 2661fa665f5SBrian Somers fp->link->name); 267af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 268af57ed9fSAtsushi Murai break; 269af57ed9fSAtsushi Murai case ST_STARTING: 270af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 271af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 272af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 273af57ed9fSAtsushi Murai break; 274af57ed9fSAtsushi Murai default: 275dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 276d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 277af57ed9fSAtsushi Murai break; 278af57ed9fSAtsushi Murai } 279af57ed9fSAtsushi Murai } 280af57ed9fSAtsushi Murai 281af57ed9fSAtsushi Murai void 282dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 283af57ed9fSAtsushi Murai { 284af57ed9fSAtsushi Murai switch (fp->state) { 285af57ed9fSAtsushi Murai case ST_CLOSED: 286af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 287af57ed9fSAtsushi Murai break; 288455aabc3SBrian Somers case ST_CLOSING: 2896d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 290455aabc3SBrian Somers NewState(fp, ST_INITIAL); 2916d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 292455aabc3SBrian Somers break; 293af57ed9fSAtsushi Murai case ST_STOPPED: 294455aabc3SBrian Somers NewState(fp, ST_STARTING); 2956d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2966d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 297455aabc3SBrian Somers break; 298af57ed9fSAtsushi Murai case ST_STOPPING: 299af57ed9fSAtsushi Murai case ST_REQSENT: 300af57ed9fSAtsushi Murai case ST_ACKRCVD: 301af57ed9fSAtsushi Murai case ST_ACKSENT: 302af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 303af57ed9fSAtsushi Murai break; 304af57ed9fSAtsushi Murai case ST_OPENED: 3056d666775SBrian Somers (*fp->fn->LayerDown)(fp); 306af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 3076d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 308af57ed9fSAtsushi Murai break; 309af57ed9fSAtsushi Murai } 310af57ed9fSAtsushi Murai } 311af57ed9fSAtsushi Murai 312af57ed9fSAtsushi Murai void 313dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 314af57ed9fSAtsushi Murai { 315af57ed9fSAtsushi Murai switch (fp->state) { 316af57ed9fSAtsushi Murai case ST_STARTING: 3176d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 318af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 3196d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 320af57ed9fSAtsushi Murai break; 321af57ed9fSAtsushi Murai case ST_STOPPED: 322af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 323af57ed9fSAtsushi Murai break; 324af57ed9fSAtsushi Murai case ST_STOPPING: 325af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 326af57ed9fSAtsushi Murai break; 327af57ed9fSAtsushi Murai case ST_OPENED: 3286d666775SBrian Somers (*fp->fn->LayerDown)(fp); 329455aabc3SBrian Somers FsmInitRestartCounter(fp); 330455aabc3SBrian Somers FsmSendTerminateReq(fp); 331455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3326d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 333455aabc3SBrian Somers break; 334af57ed9fSAtsushi Murai case ST_REQSENT: 335af57ed9fSAtsushi Murai case ST_ACKRCVD: 336af57ed9fSAtsushi Murai case ST_ACKSENT: 337af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 338af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 339af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 340af57ed9fSAtsushi Murai break; 341af57ed9fSAtsushi Murai } 342af57ed9fSAtsushi Murai } 343af57ed9fSAtsushi Murai 344af57ed9fSAtsushi Murai /* 345af57ed9fSAtsushi Murai * Send functions 346af57ed9fSAtsushi Murai */ 34775240ed1SBrian Somers static void 348944f7098SBrian Somers FsmSendConfigReq(struct fsm * fp) 349af57ed9fSAtsushi Murai { 350af57ed9fSAtsushi Murai if (--fp->maxconfig > 0) { 35183d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 352dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 353af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 354af57ed9fSAtsushi Murai } else { 355dd7e2610SBrian Somers fsm_Close(fp); 356af57ed9fSAtsushi Murai } 357af57ed9fSAtsushi Murai } 358af57ed9fSAtsushi Murai 35975240ed1SBrian Somers static void 360944f7098SBrian Somers FsmSendTerminateReq(struct fsm *fp) 361af57ed9fSAtsushi Murai { 362dd7e2610SBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0); 3632267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 364dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 365af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 366af57ed9fSAtsushi Murai } 367af57ed9fSAtsushi Murai 368af57ed9fSAtsushi Murai /* 369af57ed9fSAtsushi Murai * Timeout actions 370af57ed9fSAtsushi Murai */ 37175240ed1SBrian Somers static void 372b6e82f33SBrian Somers FsmTimeout(void *v) 373af57ed9fSAtsushi Murai { 374b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 375b6e82f33SBrian Somers 376af57ed9fSAtsushi Murai if (fp->restart) { 377af57ed9fSAtsushi Murai switch (fp->state) { 378af57ed9fSAtsushi Murai case ST_CLOSING: 379af57ed9fSAtsushi Murai case ST_STOPPING: 380af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 381af57ed9fSAtsushi Murai break; 382af57ed9fSAtsushi Murai case ST_REQSENT: 383af57ed9fSAtsushi Murai case ST_ACKSENT: 384af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 385af57ed9fSAtsushi Murai break; 386af57ed9fSAtsushi Murai case ST_ACKRCVD: 387af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 388af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 389af57ed9fSAtsushi Murai break; 390af57ed9fSAtsushi Murai } 391dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 392af57ed9fSAtsushi Murai } else { 393af57ed9fSAtsushi Murai switch (fp->state) { 394af57ed9fSAtsushi Murai case ST_CLOSING: 3956d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 396af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 3976d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 398af57ed9fSAtsushi Murai break; 399af57ed9fSAtsushi Murai case ST_STOPPING: 4006d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 401af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4026d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 403af57ed9fSAtsushi Murai break; 404af57ed9fSAtsushi Murai case ST_REQSENT: /* XXX: 3p */ 405af57ed9fSAtsushi Murai case ST_ACKSENT: 406af57ed9fSAtsushi Murai case ST_ACKRCVD: 4076d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 408af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4096d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 410af57ed9fSAtsushi Murai break; 411af57ed9fSAtsushi Murai } 412af57ed9fSAtsushi Murai } 413af57ed9fSAtsushi Murai } 414af57ed9fSAtsushi Murai 41575240ed1SBrian Somers static void 416944f7098SBrian Somers FsmInitRestartCounter(struct fsm * fp) 417af57ed9fSAtsushi Murai { 418dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 419af57ed9fSAtsushi Murai fp->FsmTimer.func = FsmTimeout; 420af57ed9fSAtsushi Murai fp->FsmTimer.arg = (void *) fp; 42183d1af55SBrian Somers (*fp->fn->InitRestartCounter)(fp); 422af57ed9fSAtsushi Murai } 423af57ed9fSAtsushi Murai 424af57ed9fSAtsushi Murai /* 425af57ed9fSAtsushi Murai * Actions when receive packets 426af57ed9fSAtsushi Murai */ 42775240ed1SBrian Somers static void 428944f7098SBrian Somers FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 429944f7098SBrian Somers /* RCR */ 430af57ed9fSAtsushi Murai { 43130c2f2ffSBrian Somers struct fsm_decode dec; 43253c9f6c0SAtsushi Murai int plen, flen; 433af57ed9fSAtsushi Murai int ackaction = 0; 434af57ed9fSAtsushi Murai 435dd7e2610SBrian Somers plen = mbuf_Length(bp); 43670ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 43753c9f6c0SAtsushi Murai if (plen < flen) { 438a33b2ef7SBrian Somers log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 439d47dceb8SBrian Somers fp->link->name, plen, flen); 440dd7e2610SBrian Somers mbuf_Free(bp); 441af57ed9fSAtsushi Murai return; 442af57ed9fSAtsushi Murai } 443af57ed9fSAtsushi Murai 444af57ed9fSAtsushi Murai /* 445af57ed9fSAtsushi Murai * Check and process easy case 446af57ed9fSAtsushi Murai */ 447af57ed9fSAtsushi Murai switch (fp->state) { 448af57ed9fSAtsushi Murai case ST_INITIAL: 449af57ed9fSAtsushi Murai case ST_STARTING: 450dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 451d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 452dd7e2610SBrian Somers mbuf_Free(bp); 453af57ed9fSAtsushi Murai return; 454af57ed9fSAtsushi Murai case ST_CLOSED: 4552267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 456dd7e2610SBrian Somers mbuf_Free(bp); 457af57ed9fSAtsushi Murai return; 458af57ed9fSAtsushi Murai case ST_CLOSING: 459dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 460d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 461a9c503afSBrian Somers case ST_STOPPING: 462dd7e2610SBrian Somers mbuf_Free(bp); 463af57ed9fSAtsushi Murai return; 464af57ed9fSAtsushi Murai } 465af57ed9fSAtsushi Murai 46630c2f2ffSBrian Somers dec.ackend = dec.ack; 46730c2f2ffSBrian Somers dec.nakend = dec.nak; 46830c2f2ffSBrian Somers dec.rejend = dec.rej; 46930c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec); 4702267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 471dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 472af57ed9fSAtsushi Murai 47330c2f2ffSBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 474af57ed9fSAtsushi Murai ackaction = 1; 475af57ed9fSAtsushi Murai 476af57ed9fSAtsushi Murai switch (fp->state) { 477af57ed9fSAtsushi Murai case ST_OPENED: 4786d666775SBrian Somers (*fp->fn->LayerDown)(fp); 479af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 4806d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 481af57ed9fSAtsushi Murai break; 482af57ed9fSAtsushi Murai case ST_STOPPED: 483af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 484af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 485af57ed9fSAtsushi Murai break; 486af57ed9fSAtsushi Murai } 487af57ed9fSAtsushi Murai 48830c2f2ffSBrian Somers if (dec.rejend != dec.rej) 489dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej); 49030c2f2ffSBrian Somers if (dec.nakend != dec.nak) 491dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak); 492af57ed9fSAtsushi Murai if (ackaction) 493dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack); 494af57ed9fSAtsushi Murai 495af57ed9fSAtsushi Murai switch (fp->state) { 496af57ed9fSAtsushi Murai case ST_OPENED: 497455aabc3SBrian Somers case ST_STOPPED: 498af57ed9fSAtsushi Murai if (ackaction) 499af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 500af57ed9fSAtsushi Murai else 501af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 502af57ed9fSAtsushi Murai break; 503af57ed9fSAtsushi Murai case ST_REQSENT: 504af57ed9fSAtsushi Murai if (ackaction) 505af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 506af57ed9fSAtsushi Murai break; 507af57ed9fSAtsushi Murai case ST_ACKRCVD: 508af57ed9fSAtsushi Murai if (ackaction) { 509af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5106f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5116d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5126f384573SBrian Somers else { 5136f384573SBrian Somers (*fp->fn->LayerDown)(fp); 5146f384573SBrian Somers FsmInitRestartCounter(fp); 5156f384573SBrian Somers FsmSendTerminateReq(fp); 5166f384573SBrian Somers NewState(fp, ST_CLOSING); 5176f384573SBrian Somers } 518af57ed9fSAtsushi Murai } 519af57ed9fSAtsushi Murai break; 520af57ed9fSAtsushi Murai case ST_ACKSENT: 521af57ed9fSAtsushi Murai if (!ackaction) 522af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 523af57ed9fSAtsushi Murai break; 524af57ed9fSAtsushi Murai } 525dd7e2610SBrian Somers mbuf_Free(bp); 526af57ed9fSAtsushi Murai } 527af57ed9fSAtsushi Murai 52875240ed1SBrian Somers static void 529944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 530944f7098SBrian Somers /* RCA */ 531af57ed9fSAtsushi Murai { 532af57ed9fSAtsushi Murai switch (fp->state) { 533af57ed9fSAtsushi Murai case ST_CLOSED: 534af57ed9fSAtsushi Murai case ST_STOPPED: 5352267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 536af57ed9fSAtsushi Murai break; 537af57ed9fSAtsushi Murai case ST_CLOSING: 538af57ed9fSAtsushi Murai case ST_STOPPING: 539af57ed9fSAtsushi Murai break; 540af57ed9fSAtsushi Murai case ST_REQSENT: 541af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 542af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 543af57ed9fSAtsushi Murai break; 544af57ed9fSAtsushi Murai case ST_ACKRCVD: 545af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 546af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 547af57ed9fSAtsushi Murai break; 548af57ed9fSAtsushi Murai case ST_ACKSENT: 549af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 550af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5516f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5526d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5536f384573SBrian Somers else { 5546f384573SBrian Somers (*fp->fn->LayerDown)(fp); 5556f384573SBrian Somers FsmInitRestartCounter(fp); 5566f384573SBrian Somers FsmSendTerminateReq(fp); 5576f384573SBrian Somers NewState(fp, ST_CLOSING); 5586f384573SBrian Somers } 559af57ed9fSAtsushi Murai break; 560af57ed9fSAtsushi Murai case ST_OPENED: 5616d666775SBrian Somers (*fp->fn->LayerDown)(fp); 562af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 563af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 5646d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 565af57ed9fSAtsushi Murai break; 566af57ed9fSAtsushi Murai } 567dd7e2610SBrian Somers mbuf_Free(bp); 568af57ed9fSAtsushi Murai } 569af57ed9fSAtsushi Murai 57075240ed1SBrian Somers static void 571944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 572944f7098SBrian Somers /* RCN */ 573af57ed9fSAtsushi Murai { 57430c2f2ffSBrian Somers struct fsm_decode dec; 57553c9f6c0SAtsushi Murai int plen, flen; 576af57ed9fSAtsushi Murai 577dd7e2610SBrian Somers plen = mbuf_Length(bp); 57870ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 57953c9f6c0SAtsushi Murai if (plen < flen) { 580dd7e2610SBrian Somers mbuf_Free(bp); 581af57ed9fSAtsushi Murai return; 582af57ed9fSAtsushi Murai } 583af57ed9fSAtsushi Murai 584af57ed9fSAtsushi Murai /* 585af57ed9fSAtsushi Murai * Check and process easy case 586af57ed9fSAtsushi Murai */ 587af57ed9fSAtsushi Murai switch (fp->state) { 588af57ed9fSAtsushi Murai case ST_INITIAL: 589af57ed9fSAtsushi Murai case ST_STARTING: 590dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 591d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 592dd7e2610SBrian Somers mbuf_Free(bp); 593af57ed9fSAtsushi Murai return; 594af57ed9fSAtsushi Murai case ST_CLOSED: 595af57ed9fSAtsushi Murai case ST_STOPPED: 5962267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 597dd7e2610SBrian Somers mbuf_Free(bp); 598af57ed9fSAtsushi Murai return; 599af57ed9fSAtsushi Murai case ST_CLOSING: 600af57ed9fSAtsushi Murai case ST_STOPPING: 601dd7e2610SBrian Somers mbuf_Free(bp); 602af57ed9fSAtsushi Murai return; 603af57ed9fSAtsushi Murai } 604af57ed9fSAtsushi Murai 60530c2f2ffSBrian Somers dec.ackend = dec.ack; 60630c2f2ffSBrian Somers dec.nakend = dec.nak; 60730c2f2ffSBrian Somers dec.rejend = dec.rej; 60830c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); 6092267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 610dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 611af57ed9fSAtsushi Murai 612af57ed9fSAtsushi Murai switch (fp->state) { 613af57ed9fSAtsushi Murai case ST_REQSENT: 614af57ed9fSAtsushi Murai case ST_ACKSENT: 615af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 616af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 617af57ed9fSAtsushi Murai break; 618af57ed9fSAtsushi Murai case ST_OPENED: 6196d666775SBrian Somers (*fp->fn->LayerDown)(fp); 620455aabc3SBrian Somers FsmSendConfigReq(fp); 621455aabc3SBrian Somers NewState(fp, ST_REQSENT); 6226d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 623455aabc3SBrian Somers break; 624af57ed9fSAtsushi Murai case ST_ACKRCVD: 625af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 626af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 627af57ed9fSAtsushi Murai break; 628af57ed9fSAtsushi Murai } 629af57ed9fSAtsushi Murai 630dd7e2610SBrian Somers mbuf_Free(bp); 631af57ed9fSAtsushi Murai } 632af57ed9fSAtsushi Murai 63375240ed1SBrian Somers static void 634944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 635944f7098SBrian Somers /* RTR */ 636af57ed9fSAtsushi Murai { 637af57ed9fSAtsushi Murai switch (fp->state) { 638af57ed9fSAtsushi Murai case ST_INITIAL: 639af57ed9fSAtsushi Murai case ST_STARTING: 640dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 641d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 642af57ed9fSAtsushi Murai break; 643af57ed9fSAtsushi Murai case ST_CLOSED: 644af57ed9fSAtsushi Murai case ST_STOPPED: 645af57ed9fSAtsushi Murai case ST_CLOSING: 646af57ed9fSAtsushi Murai case ST_STOPPING: 647af57ed9fSAtsushi Murai case ST_REQSENT: 6482267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 649af57ed9fSAtsushi Murai break; 650af57ed9fSAtsushi Murai case ST_ACKRCVD: 651af57ed9fSAtsushi Murai case ST_ACKSENT: 6522267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 653af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 654af57ed9fSAtsushi Murai break; 655af57ed9fSAtsushi Murai case ST_OPENED: 6566d666775SBrian Somers (*fp->fn->LayerDown)(fp); 6572267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 658dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 6598f2fa0eeSBrian Somers fp->restart = 0; 6608f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 6616d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 662af57ed9fSAtsushi Murai break; 663af57ed9fSAtsushi Murai } 664dd7e2610SBrian Somers mbuf_Free(bp); 665af57ed9fSAtsushi Murai } 666af57ed9fSAtsushi Murai 66775240ed1SBrian Somers static void 668944f7098SBrian Somers FsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 669944f7098SBrian Somers /* RTA */ 670af57ed9fSAtsushi Murai { 671af57ed9fSAtsushi Murai switch (fp->state) { 672af57ed9fSAtsushi Murai case ST_CLOSING: 6736d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 674af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 6756d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 676af57ed9fSAtsushi Murai break; 677af57ed9fSAtsushi Murai case ST_STOPPING: 6786d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 679af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 6806d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 681af57ed9fSAtsushi Murai break; 682af57ed9fSAtsushi Murai case ST_ACKRCVD: 683af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 684af57ed9fSAtsushi Murai break; 685af57ed9fSAtsushi Murai case ST_OPENED: 6866d666775SBrian Somers (*fp->fn->LayerDown)(fp); 687af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 688af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 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 FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 697944f7098SBrian Somers /* RCJ */ 698af57ed9fSAtsushi Murai { 69930c2f2ffSBrian Somers struct fsm_decode dec; 70053c9f6c0SAtsushi Murai int plen, flen; 701af57ed9fSAtsushi Murai 702dd7e2610SBrian Somers plen = mbuf_Length(bp); 70370ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 70453c9f6c0SAtsushi Murai if (plen < flen) { 705dd7e2610SBrian Somers mbuf_Free(bp); 706af57ed9fSAtsushi Murai return; 707af57ed9fSAtsushi Murai } 708af57ed9fSAtsushi Murai 709af57ed9fSAtsushi Murai /* 710af57ed9fSAtsushi Murai * Check and process easy case 711af57ed9fSAtsushi Murai */ 712af57ed9fSAtsushi Murai switch (fp->state) { 713af57ed9fSAtsushi Murai case ST_INITIAL: 714af57ed9fSAtsushi Murai case ST_STARTING: 715dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 716d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 717dd7e2610SBrian Somers mbuf_Free(bp); 718af57ed9fSAtsushi Murai return; 719af57ed9fSAtsushi Murai case ST_CLOSED: 720af57ed9fSAtsushi Murai case ST_STOPPED: 7212267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 722dd7e2610SBrian Somers mbuf_Free(bp); 723af57ed9fSAtsushi Murai return; 724af57ed9fSAtsushi Murai case ST_CLOSING: 725af57ed9fSAtsushi Murai case ST_STOPPING: 726dd7e2610SBrian Somers mbuf_Free(bp); 727af57ed9fSAtsushi Murai return; 728af57ed9fSAtsushi Murai } 729af57ed9fSAtsushi Murai 73030c2f2ffSBrian Somers dec.ackend = dec.ack; 73130c2f2ffSBrian Somers dec.nakend = dec.nak; 73230c2f2ffSBrian Somers dec.rejend = dec.rej; 73330c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); 7342267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 735dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 736af57ed9fSAtsushi Murai 737af57ed9fSAtsushi Murai switch (fp->state) { 738af57ed9fSAtsushi Murai case ST_REQSENT: 739af57ed9fSAtsushi Murai case ST_ACKSENT: 740af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 741af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 742af57ed9fSAtsushi Murai break; 743af57ed9fSAtsushi Murai case ST_OPENED: 7446d666775SBrian Somers (*fp->fn->LayerDown)(fp); 745455aabc3SBrian Somers FsmSendConfigReq(fp); 746455aabc3SBrian Somers NewState(fp, ST_REQSENT); 7476d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 748455aabc3SBrian Somers break; 749af57ed9fSAtsushi Murai case ST_ACKRCVD: 750af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 751af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 752af57ed9fSAtsushi Murai break; 753af57ed9fSAtsushi Murai } 754dd7e2610SBrian Somers mbuf_Free(bp); 755af57ed9fSAtsushi Murai } 756af57ed9fSAtsushi Murai 75775240ed1SBrian Somers static void 758944f7098SBrian Somers FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 759af57ed9fSAtsushi Murai { 760dd7e2610SBrian Somers mbuf_Free(bp); 761af57ed9fSAtsushi Murai } 762af57ed9fSAtsushi Murai 76375240ed1SBrian Somers static void 764944f7098SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 765af57ed9fSAtsushi Murai { 7668c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 767af57ed9fSAtsushi Murai u_short *sp, proto; 768af57ed9fSAtsushi Murai 769af57ed9fSAtsushi Murai sp = (u_short *) MBUF_CTOP(bp); 770af57ed9fSAtsushi Murai proto = ntohs(*sp); 771dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 772d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 773af57ed9fSAtsushi Murai 774af57ed9fSAtsushi Murai switch (proto) { 775af57ed9fSAtsushi Murai case PROTO_LQR: 7768c07a7b2SBrian Somers if (p) 777dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 7788c07a7b2SBrian Somers else 779dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 780d47dceb8SBrian Somers fp->link->name); 781af57ed9fSAtsushi Murai break; 782af57ed9fSAtsushi Murai case PROTO_CCP: 783dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 7843b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 7856d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 786af57ed9fSAtsushi Murai switch (fp->state) { 787af57ed9fSAtsushi Murai case ST_CLOSED: 788af57ed9fSAtsushi Murai case ST_CLOSING: 789af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 790af57ed9fSAtsushi Murai default: 791af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 792af57ed9fSAtsushi Murai break; 793af57ed9fSAtsushi Murai } 7946d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 795dc0fdb6bSBrian Somers } 7961ae349f5Scvs2svn break; 797673903ecSBrian Somers case PROTO_MP: 798673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 799673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 800673903ecSBrian Somers 801673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 802dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 803d47dceb8SBrian Somers fp->link->name); 804dd7e2610SBrian Somers fsm_Close(fp); 805673903ecSBrian Somers } 806673903ecSBrian Somers } 807af57ed9fSAtsushi Murai break; 808af57ed9fSAtsushi Murai } 809dd7e2610SBrian Somers mbuf_Free(bp); 810af57ed9fSAtsushi Murai } 811af57ed9fSAtsushi Murai 81275240ed1SBrian Somers static void 813944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 814af57ed9fSAtsushi Murai { 815dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 816af57ed9fSAtsushi Murai u_char *cp; 817fe3125a0SBrian Somers u_int32_t magic; 818af57ed9fSAtsushi Murai 819dc0fdb6bSBrian Somers if (lcp) { 820af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 821fe3125a0SBrian Somers magic = ntohl(*(u_int32_t *)cp); 822dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 823dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: Error: His magic is bad!!\n", 824d47dceb8SBrian Somers fp->link->name); 825af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 826af57ed9fSAtsushi Murai } 827af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 828fe3125a0SBrian Somers *(u_int32_t *)cp = htonl(lcp->want_magic); /* local magic */ 829dd7e2610SBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, mbuf_Length(bp)); 830af57ed9fSAtsushi Murai } 831dc0fdb6bSBrian Somers } 832dd7e2610SBrian Somers mbuf_Free(bp); 833af57ed9fSAtsushi Murai } 834af57ed9fSAtsushi Murai 83575240ed1SBrian Somers static void 836944f7098SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 837af57ed9fSAtsushi Murai { 838dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 839fe3125a0SBrian Somers u_int32_t magic; 840af57ed9fSAtsushi Murai 841dc0fdb6bSBrian Somers if (lcp) { 842fe3125a0SBrian Somers magic = ntohl(*(u_int32_t *)MBUF_CTOP(bp)); 843879ed6faSBrian Somers /* Tolerate echo replies with either magic number */ 844dc0fdb6bSBrian Somers if (magic != 0 && magic != lcp->his_magic && magic != lcp->want_magic) { 845dd7e2610SBrian Somers log_Printf(LogWARN, 846d47dceb8SBrian Somers "%s: RecvEchoRep: Bad magic: expected 0x%08x, got: 0x%08x\n", 847d47dceb8SBrian Somers fp->link->name, lcp->his_magic, magic); 84885c59f05SJoerg Wunsch /* 849fe3125a0SBrian Somers * XXX: We should send terminate request. But poor implementations may 850fe3125a0SBrian Somers * die as a result. 851af57ed9fSAtsushi Murai */ 852af57ed9fSAtsushi Murai } 853dd7e2610SBrian Somers lqr_RecvEcho(fp, bp); 854dc0fdb6bSBrian Somers } 855dd7e2610SBrian Somers mbuf_Free(bp); 856af57ed9fSAtsushi Murai } 857af57ed9fSAtsushi Murai 85875240ed1SBrian Somers static void 859944f7098SBrian Somers FsmRecvDiscReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 860af57ed9fSAtsushi Murai { 861dd7e2610SBrian Somers mbuf_Free(bp); 862af57ed9fSAtsushi Murai } 863af57ed9fSAtsushi Murai 86475240ed1SBrian Somers static void 865944f7098SBrian Somers FsmRecvIdent(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 866af57ed9fSAtsushi Murai { 867dd7e2610SBrian Somers mbuf_Free(bp); 868af57ed9fSAtsushi Murai } 869af57ed9fSAtsushi Murai 87075240ed1SBrian Somers static void 871944f7098SBrian Somers FsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 872af57ed9fSAtsushi Murai { 873dd7e2610SBrian Somers mbuf_Free(bp); 874af57ed9fSAtsushi Murai } 875af57ed9fSAtsushi Murai 87675240ed1SBrian Somers static void 877944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 878af57ed9fSAtsushi Murai { 879503a7782SBrian Somers (*fp->fn->RecvResetReq)(fp); 88098baf7c8SBrian Somers /* 88198baf7c8SBrian Somers * All sendable compressed packets are queued in the PRI_NORMAL modem 88298baf7c8SBrian Somers * output queue.... dump 'em to the priority queue so that they arrive 88398baf7c8SBrian Somers * at the peer before our ResetAck. 88498baf7c8SBrian Somers */ 8858c07a7b2SBrian Somers link_SequenceQueue(fp->link); 886dd7e2610SBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0); 887dd7e2610SBrian Somers mbuf_Free(bp); 888af57ed9fSAtsushi Murai } 889af57ed9fSAtsushi Murai 89075240ed1SBrian Somers static void 891944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 892af57ed9fSAtsushi Murai { 893503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 894dd7e2610SBrian Somers mbuf_Free(bp); 895af57ed9fSAtsushi Murai } 896af57ed9fSAtsushi Murai 897af57ed9fSAtsushi Murai void 898dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 899af57ed9fSAtsushi Murai { 900af57ed9fSAtsushi Murai int len; 901af57ed9fSAtsushi Murai struct fsmheader *lhp; 9020053cc58SBrian Somers const struct fsmcodedesc *codep; 903af57ed9fSAtsushi Murai 904dd7e2610SBrian Somers len = mbuf_Length(bp); 905af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 906dd7e2610SBrian Somers mbuf_Free(bp); 907af57ed9fSAtsushi Murai return; 908af57ed9fSAtsushi Murai } 909af57ed9fSAtsushi Murai lhp = (struct fsmheader *) MBUF_CTOP(bp); 9103b0f8d2eSBrian Somers if (lhp->code < fp->min_code || lhp->code > fp->max_code || 9117308ec68SBrian Somers lhp->code > sizeof FsmCodes / sizeof *FsmCodes) { 9123b0f8d2eSBrian Somers /* 9133b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 9143b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 9153b0f8d2eSBrian Somers */ 9163b0f8d2eSBrian Somers static u_char id; 917d93d3a9cSBrian Somers 918dd7e2610SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->cnt); 919dd7e2610SBrian Somers mbuf_Free(bp); 920af57ed9fSAtsushi Murai return; 921af57ed9fSAtsushi Murai } 922af57ed9fSAtsushi Murai bp->offset += sizeof(struct fsmheader); 923af57ed9fSAtsushi Murai bp->cnt -= sizeof(struct fsmheader); 924af57ed9fSAtsushi Murai 925af57ed9fSAtsushi Murai codep = FsmCodes + lhp->code - 1; 9261342caedSBrian Somers if (lhp->id != fp->reqid && codep->check_reqid && 9271342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 928dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 929d47dceb8SBrian Somers fp->link->name, codep->name, lhp->id, fp->reqid); 9302267893fSBrian Somers return; 9312267893fSBrian Somers } 9322267893fSBrian Somers 933dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 934d47dceb8SBrian Somers fp->link->name, codep->name, lhp->id, State2Nam(fp->state)); 9352267893fSBrian Somers 936dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 937dd7e2610SBrian Somers mbuf_Log(); 9382267893fSBrian Somers 9392267893fSBrian Somers if (codep->inc_reqid && (lhp->id == fp->reqid || 9401342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 9412267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 9422267893fSBrian Somers 9431342caedSBrian Somers (*codep->recv)(fp, lhp, bp); 9442267893fSBrian Somers 945dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 946dd7e2610SBrian Somers mbuf_Log(); 9471ae349f5Scvs2svn } 948503a7782SBrian Somers 949503a7782SBrian Somers void 950dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 951503a7782SBrian Somers { 952dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 953d47dceb8SBrian Somers fp->link->name); 954503a7782SBrian Somers } 955503a7782SBrian Somers 956503a7782SBrian Somers void 957dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 958503a7782SBrian Somers { 959dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 960d47dceb8SBrian Somers fp->link->name); 961af57ed9fSAtsushi Murai } 962