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 * 20972a1bcfSBrian Somers * $Id: fsm.c,v 1.37 1998/09/04 18:25:59 brian Exp $ 21af57ed9fSAtsushi Murai * 22af57ed9fSAtsushi Murai * TODO: 23af57ed9fSAtsushi Murai */ 2475240ed1SBrian Somers 25972a1bcfSBrian Somers #include <sys/param.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 349e8ec64bSBrian Somers #include "ua.h" 3575240ed1SBrian Somers #include "mbuf.h" 3675240ed1SBrian Somers #include "log.h" 3775240ed1SBrian Somers #include "defs.h" 3875240ed1SBrian Somers #include "timer.h" 39af57ed9fSAtsushi Murai #include "fsm.h" 401342caedSBrian Somers #include "iplist.h" 41af57ed9fSAtsushi Murai #include "lqr.h" 42879ed6faSBrian Somers #include "hdlc.h" 431342caedSBrian Somers #include "throughput.h" 441342caedSBrian Somers #include "slcompress.h" 451342caedSBrian Somers #include "ipcp.h" 461342caedSBrian Somers #include "filter.h" 471342caedSBrian Somers #include "descriptor.h" 48af57ed9fSAtsushi Murai #include "lcp.h" 49ed6a16c1SPoul-Henning Kamp #include "ccp.h" 508c07a7b2SBrian Somers #include "link.h" 511342caedSBrian Somers #include "mp.h" 52972a1bcfSBrian Somers #ifndef NORADIUS 53972a1bcfSBrian Somers #include "radius.h" 54972a1bcfSBrian Somers #endif 551342caedSBrian Somers #include "bundle.h" 561342caedSBrian Somers #include "async.h" 5763b73463SBrian Somers #include "physical.h" 581342caedSBrian Somers #include "lcpproto.h" 5975240ed1SBrian Somers 6075240ed1SBrian Somers static void FsmSendConfigReq(struct fsm *); 6175240ed1SBrian Somers static void FsmSendTerminateReq(struct fsm *); 6275240ed1SBrian Somers static void FsmInitRestartCounter(struct fsm *); 63af57ed9fSAtsushi Murai 642267893fSBrian Somers typedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *); 652267893fSBrian Somers static recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak, 662267893fSBrian Somers FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck, 672267893fSBrian Somers FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq, 682267893fSBrian Somers FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent, 692267893fSBrian Somers FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck; 702267893fSBrian Somers 712267893fSBrian Somers static const struct fsmcodedesc { 722267893fSBrian Somers recvfn *recv; 732267893fSBrian Somers unsigned check_reqid : 1; 742267893fSBrian Somers unsigned inc_reqid : 1; 752267893fSBrian Somers const char *name; 762267893fSBrian Somers } FsmCodes[] = { 772267893fSBrian Somers { FsmRecvConfigReq, 0, 0, "ConfigReq" }, 782267893fSBrian Somers { FsmRecvConfigAck, 1, 1, "ConfigAck" }, 792267893fSBrian Somers { FsmRecvConfigNak, 1, 1, "ConfigNak" }, 802267893fSBrian Somers { FsmRecvConfigRej, 1, 1, "ConfigRej" }, 812267893fSBrian Somers { FsmRecvTermReq, 0, 0, "TerminateReq" }, 822267893fSBrian Somers { FsmRecvTermAck, 1, 1, "TerminateAck" }, 832267893fSBrian Somers { FsmRecvCodeRej, 0, 0, "CodeRej" }, 842267893fSBrian Somers { FsmRecvProtoRej, 0, 0, "ProtocolRej" }, 852267893fSBrian Somers { FsmRecvEchoReq, 0, 0, "EchoRequest" }, 862267893fSBrian Somers { FsmRecvEchoRep, 0, 0, "EchoReply" }, 872267893fSBrian Somers { FsmRecvDiscReq, 0, 0, "DiscardReq" }, 882267893fSBrian Somers { FsmRecvIdent, 0, 0, "Ident" }, 892267893fSBrian Somers { FsmRecvTimeRemain,0, 0, "TimeRemain" }, 902267893fSBrian Somers { FsmRecvResetReq, 0, 0, "ResetReqt" }, 912267893fSBrian Somers { FsmRecvResetAck, 0, 1, "ResetAck" } 922267893fSBrian Somers }; 932267893fSBrian Somers 942267893fSBrian Somers static const char * 952267893fSBrian Somers Code2Nam(u_int code) 962267893fSBrian Somers { 972267893fSBrian Somers if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0]) 982267893fSBrian Somers return "Unknown"; 992267893fSBrian Somers return FsmCodes[code-1].name; 1002267893fSBrian Somers } 1012267893fSBrian Somers 1021e991daaSBrian Somers const char * 1031e991daaSBrian Somers State2Nam(u_int state) 1041e991daaSBrian Somers { 1051e991daaSBrian Somers static const char *StateNames[] = { 106af57ed9fSAtsushi Murai "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", 107927145beSBrian Somers "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", 108af57ed9fSAtsushi Murai }; 109af57ed9fSAtsushi Murai 1101e991daaSBrian Somers if (state >= sizeof StateNames / sizeof StateNames[0]) 1111e991daaSBrian Somers return "unknown"; 1121e991daaSBrian Somers return StateNames[state]; 1131e991daaSBrian Somers } 1141e991daaSBrian Somers 11571144dc5SBrian Somers static void 116b6e82f33SBrian Somers StoppedTimeout(void *v) 11771144dc5SBrian Somers { 118b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 119b6e82f33SBrian Somers 120dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name); 12149b239e0SBrian Somers if (fp->OpenTimer.state == TIMER_RUNNING) { 122dd7e2610SBrian Somers log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n", 123d47dceb8SBrian Somers fp->link->name, fp->name); 124dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 12549b239e0SBrian Somers } 12609206a6fSBrian Somers if (fp->state == ST_STOPPED) 12709206a6fSBrian Somers fsm2initial(fp); 12871144dc5SBrian Somers } 12971144dc5SBrian Somers 130af57ed9fSAtsushi Murai void 1313b0f8d2eSBrian Somers fsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, 1323b0f8d2eSBrian Somers int maxcode, int maxcfg, int LogLevel, struct bundle *bundle, 1333b0f8d2eSBrian Somers struct link *l, const struct fsm_parent *parent, 1343b0f8d2eSBrian Somers struct fsm_callbacks *fn, const char *timer_names[3]) 135af57ed9fSAtsushi Murai { 136503a7782SBrian Somers fp->name = name; 137503a7782SBrian Somers fp->proto = proto; 1383b0f8d2eSBrian Somers fp->min_code = mincode; 139503a7782SBrian Somers fp->max_code = maxcode; 1403b0f8d2eSBrian Somers fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; 141af57ed9fSAtsushi Murai fp->reqid = 1; 142af57ed9fSAtsushi Murai fp->restart = 1; 143503a7782SBrian Somers fp->maxconfig = maxcfg; 144503a7782SBrian Somers memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); 145503a7782SBrian Somers memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); 146503a7782SBrian Somers memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); 147503a7782SBrian Somers fp->LogLevel = LogLevel; 1488c07a7b2SBrian Somers fp->link = l; 1497a6f8720SBrian Somers fp->bundle = bundle; 1506d666775SBrian Somers fp->parent = parent; 151503a7782SBrian Somers fp->fn = fn; 1523b0f8d2eSBrian Somers fp->FsmTimer.name = timer_names[0]; 1533b0f8d2eSBrian Somers fp->OpenTimer.name = timer_names[1]; 1543b0f8d2eSBrian Somers fp->StoppedTimer.name = timer_names[2]; 155af57ed9fSAtsushi Murai } 156af57ed9fSAtsushi Murai 15775240ed1SBrian Somers static void 158944f7098SBrian Somers NewState(struct fsm * fp, int new) 159af57ed9fSAtsushi Murai { 160dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", 161d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state), State2Nam(new)); 162cb611434SBrian Somers if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) 163dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 164af57ed9fSAtsushi Murai fp->state = new; 16571144dc5SBrian Somers if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { 166dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 167cb611434SBrian Somers if (new == ST_STOPPED && fp->StoppedTimer.load) { 168dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 169cb611434SBrian Somers fp->StoppedTimer.func = StoppedTimeout; 170cb611434SBrian Somers fp->StoppedTimer.arg = (void *) fp; 171dd7e2610SBrian Somers timer_Start(&fp->StoppedTimer); 17271144dc5SBrian Somers } 17371144dc5SBrian Somers } 174af57ed9fSAtsushi Murai } 175af57ed9fSAtsushi Murai 176af57ed9fSAtsushi Murai void 177dd7e2610SBrian Somers fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count) 178af57ed9fSAtsushi Murai { 179af57ed9fSAtsushi Murai int plen; 180af57ed9fSAtsushi Murai struct fsmheader lh; 181af57ed9fSAtsushi Murai struct mbuf *bp; 182af57ed9fSAtsushi Murai 183dd7e2610SBrian Somers if (log_IsKept(fp->LogLevel)) { 184dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 185d47dceb8SBrian Somers fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 1862267893fSBrian Somers switch (code) { 1872267893fSBrian Somers case CODE_CONFIGREQ: 1882267893fSBrian Somers case CODE_CONFIGACK: 1892267893fSBrian Somers case CODE_CONFIGREJ: 1902267893fSBrian Somers case CODE_CONFIGNAK: 1912267893fSBrian Somers (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL); 1922267893fSBrian Somers if (count < sizeof(struct fsmconfig)) 193dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 1942267893fSBrian Somers break; 1952267893fSBrian Somers } 1962267893fSBrian Somers } 1972267893fSBrian Somers 198af57ed9fSAtsushi Murai plen = sizeof(struct fsmheader) + count; 199af57ed9fSAtsushi Murai lh.code = code; 200af57ed9fSAtsushi Murai lh.id = id; 201af57ed9fSAtsushi Murai lh.length = htons(plen); 202dd7e2610SBrian Somers bp = mbuf_Alloc(plen, MB_FSM); 20375240ed1SBrian Somers memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 204af57ed9fSAtsushi Murai if (count) 20575240ed1SBrian Somers memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 206dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "fsm_Output", bp); 207dd7e2610SBrian Somers hdlc_Output(fp->link, PRI_LINK, fp->proto, bp); 208af57ed9fSAtsushi Murai } 209af57ed9fSAtsushi Murai 21049b239e0SBrian Somers static void 21149b239e0SBrian Somers FsmOpenNow(void *v) 21249b239e0SBrian Somers { 21349b239e0SBrian Somers struct fsm *fp = (struct fsm *)v; 21449b239e0SBrian Somers 215dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 21649b239e0SBrian Somers if (fp->state <= ST_STOPPED) { 2173a2e4f62SBrian Somers if (fp->state != ST_STARTING) { 2183a2e4f62SBrian Somers /* 2193a2e4f62SBrian Somers * In practice, we're only here in ST_STOPPED (when delaying the 2203a2e4f62SBrian Somers * first config request) or ST_CLOSED (when openmode == 0). 2213a2e4f62SBrian Somers * 2223a2e4f62SBrian Somers * The ST_STOPPED bit is breaking the RFC already :-( 2233a2e4f62SBrian Somers * 2243a2e4f62SBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 2253a2e4f62SBrian Somers * required for an Open event when state == Closed, but the RFC 2263a2e4f62SBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 2273a2e4f62SBrian Somers * ie, Initial gets an `Up' event, Closing gets a RTA etc. 2283a2e4f62SBrian Somers */ 2293a2e4f62SBrian Somers (*fp->fn->LayerStart)(fp); 2303a2e4f62SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 2313a2e4f62SBrian Somers } 23249b239e0SBrian Somers FsmInitRestartCounter(fp); 23349b239e0SBrian Somers FsmSendConfigReq(fp); 23449b239e0SBrian Somers NewState(fp, ST_REQSENT); 23549b239e0SBrian Somers } 23649b239e0SBrian Somers } 23749b239e0SBrian Somers 238af57ed9fSAtsushi Murai void 239dd7e2610SBrian Somers fsm_Open(struct fsm * fp) 240af57ed9fSAtsushi Murai { 241af57ed9fSAtsushi Murai switch (fp->state) { 242af57ed9fSAtsushi Murai case ST_INITIAL: 243af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 2446d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2456d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 246af57ed9fSAtsushi Murai break; 247af57ed9fSAtsushi Murai case ST_CLOSED: 248af57ed9fSAtsushi Murai if (fp->open_mode == OPEN_PASSIVE) { 2493a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 25049b239e0SBrian Somers } else if (fp->open_mode > 0) { 25149b239e0SBrian Somers if (fp->open_mode > 1) 252dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 253d47dceb8SBrian Somers fp->link->name, fp->open_mode); 2543a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 255dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 25649b239e0SBrian Somers fp->OpenTimer.load = fp->open_mode * SECTICKS; 25749b239e0SBrian Somers fp->OpenTimer.func = FsmOpenNow; 25849b239e0SBrian Somers fp->OpenTimer.arg = (void *)fp; 259dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 26049b239e0SBrian Somers } else 26149b239e0SBrian Somers FsmOpenNow(fp); 262af57ed9fSAtsushi Murai break; 263af57ed9fSAtsushi Murai case ST_STOPPED: /* XXX: restart option */ 264af57ed9fSAtsushi Murai case ST_REQSENT: 265af57ed9fSAtsushi Murai case ST_ACKRCVD: 266af57ed9fSAtsushi Murai case ST_ACKSENT: 267af57ed9fSAtsushi Murai case ST_OPENED: /* XXX: restart option */ 268af57ed9fSAtsushi Murai break; 269af57ed9fSAtsushi Murai case ST_CLOSING: /* XXX: restart option */ 270af57ed9fSAtsushi Murai case ST_STOPPING: /* XXX: restart option */ 271af57ed9fSAtsushi Murai NewState(fp, ST_STOPPING); 272af57ed9fSAtsushi Murai break; 273af57ed9fSAtsushi Murai } 274af57ed9fSAtsushi Murai } 275af57ed9fSAtsushi Murai 276af57ed9fSAtsushi Murai void 277dd7e2610SBrian Somers fsm_Up(struct fsm * fp) 278af57ed9fSAtsushi Murai { 279af57ed9fSAtsushi Murai switch (fp->state) { 280af57ed9fSAtsushi Murai case ST_INITIAL: 281dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 2821fa665f5SBrian Somers fp->link->name); 283af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 284af57ed9fSAtsushi Murai break; 285af57ed9fSAtsushi Murai case ST_STARTING: 286af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 287af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 288af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 289af57ed9fSAtsushi Murai break; 290af57ed9fSAtsushi Murai default: 291dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 292d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 293af57ed9fSAtsushi Murai break; 294af57ed9fSAtsushi Murai } 295af57ed9fSAtsushi Murai } 296af57ed9fSAtsushi Murai 297af57ed9fSAtsushi Murai void 298dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 299af57ed9fSAtsushi Murai { 300af57ed9fSAtsushi Murai switch (fp->state) { 301af57ed9fSAtsushi Murai case ST_CLOSED: 302af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 303af57ed9fSAtsushi Murai break; 304455aabc3SBrian Somers case ST_CLOSING: 3056d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 306455aabc3SBrian Somers NewState(fp, ST_INITIAL); 3076d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 308455aabc3SBrian Somers break; 309af57ed9fSAtsushi Murai case ST_STOPPED: 310455aabc3SBrian Somers NewState(fp, ST_STARTING); 3116d666775SBrian Somers (*fp->fn->LayerStart)(fp); 3126d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 313455aabc3SBrian Somers break; 314af57ed9fSAtsushi Murai case ST_STOPPING: 315af57ed9fSAtsushi Murai case ST_REQSENT: 316af57ed9fSAtsushi Murai case ST_ACKRCVD: 317af57ed9fSAtsushi Murai case ST_ACKSENT: 318af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 319af57ed9fSAtsushi Murai break; 320af57ed9fSAtsushi Murai case ST_OPENED: 3216d666775SBrian Somers (*fp->fn->LayerDown)(fp); 322af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 3236d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 324af57ed9fSAtsushi Murai break; 325af57ed9fSAtsushi Murai } 326af57ed9fSAtsushi Murai } 327af57ed9fSAtsushi Murai 328af57ed9fSAtsushi Murai void 329dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 330af57ed9fSAtsushi Murai { 331af57ed9fSAtsushi Murai switch (fp->state) { 332af57ed9fSAtsushi Murai case ST_STARTING: 3336d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 334af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 3356d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 336af57ed9fSAtsushi Murai break; 337af57ed9fSAtsushi Murai case ST_STOPPED: 338af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 339af57ed9fSAtsushi Murai break; 340af57ed9fSAtsushi Murai case ST_STOPPING: 341af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 342af57ed9fSAtsushi Murai break; 343af57ed9fSAtsushi Murai case ST_OPENED: 3446d666775SBrian Somers (*fp->fn->LayerDown)(fp); 345455aabc3SBrian Somers FsmInitRestartCounter(fp); 346455aabc3SBrian Somers FsmSendTerminateReq(fp); 347455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3486d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 349455aabc3SBrian Somers break; 350af57ed9fSAtsushi Murai case ST_REQSENT: 351af57ed9fSAtsushi Murai case ST_ACKRCVD: 352af57ed9fSAtsushi Murai case ST_ACKSENT: 353af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 354af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 355af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 356af57ed9fSAtsushi Murai break; 357af57ed9fSAtsushi Murai } 358af57ed9fSAtsushi Murai } 359af57ed9fSAtsushi Murai 360af57ed9fSAtsushi Murai /* 361af57ed9fSAtsushi Murai * Send functions 362af57ed9fSAtsushi Murai */ 36375240ed1SBrian Somers static void 364944f7098SBrian Somers FsmSendConfigReq(struct fsm * fp) 365af57ed9fSAtsushi Murai { 366af57ed9fSAtsushi Murai if (--fp->maxconfig > 0) { 36783d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 368dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 369af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 370af57ed9fSAtsushi Murai } else { 371dd7e2610SBrian Somers fsm_Close(fp); 372af57ed9fSAtsushi Murai } 373af57ed9fSAtsushi Murai } 374af57ed9fSAtsushi Murai 37575240ed1SBrian Somers static void 376944f7098SBrian Somers FsmSendTerminateReq(struct fsm *fp) 377af57ed9fSAtsushi Murai { 378dd7e2610SBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0); 3792267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 380dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 381af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 382af57ed9fSAtsushi Murai } 383af57ed9fSAtsushi Murai 384af57ed9fSAtsushi Murai /* 385af57ed9fSAtsushi Murai * Timeout actions 386af57ed9fSAtsushi Murai */ 38775240ed1SBrian Somers static void 388b6e82f33SBrian Somers FsmTimeout(void *v) 389af57ed9fSAtsushi Murai { 390b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 391b6e82f33SBrian Somers 392af57ed9fSAtsushi Murai if (fp->restart) { 393af57ed9fSAtsushi Murai switch (fp->state) { 394af57ed9fSAtsushi Murai case ST_CLOSING: 395af57ed9fSAtsushi Murai case ST_STOPPING: 396af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 397af57ed9fSAtsushi Murai break; 398af57ed9fSAtsushi Murai case ST_REQSENT: 399af57ed9fSAtsushi Murai case ST_ACKSENT: 400af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 401af57ed9fSAtsushi Murai break; 402af57ed9fSAtsushi Murai case ST_ACKRCVD: 403af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 404af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 405af57ed9fSAtsushi Murai break; 406af57ed9fSAtsushi Murai } 407dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 408af57ed9fSAtsushi Murai } else { 409af57ed9fSAtsushi Murai switch (fp->state) { 410af57ed9fSAtsushi Murai case ST_CLOSING: 4116d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 412af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 4136d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 414af57ed9fSAtsushi Murai break; 415af57ed9fSAtsushi Murai case ST_STOPPING: 4166d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 417af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4186d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 419af57ed9fSAtsushi Murai break; 420af57ed9fSAtsushi Murai case ST_REQSENT: /* XXX: 3p */ 421af57ed9fSAtsushi Murai case ST_ACKSENT: 422af57ed9fSAtsushi Murai case ST_ACKRCVD: 4236d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 424af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4256d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 426af57ed9fSAtsushi Murai break; 427af57ed9fSAtsushi Murai } 428af57ed9fSAtsushi Murai } 429af57ed9fSAtsushi Murai } 430af57ed9fSAtsushi Murai 43175240ed1SBrian Somers static void 432944f7098SBrian Somers FsmInitRestartCounter(struct fsm * fp) 433af57ed9fSAtsushi Murai { 434dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 435af57ed9fSAtsushi Murai fp->FsmTimer.func = FsmTimeout; 436af57ed9fSAtsushi Murai fp->FsmTimer.arg = (void *) fp; 43783d1af55SBrian Somers (*fp->fn->InitRestartCounter)(fp); 438af57ed9fSAtsushi Murai } 439af57ed9fSAtsushi Murai 440af57ed9fSAtsushi Murai /* 441af57ed9fSAtsushi Murai * Actions when receive packets 442af57ed9fSAtsushi Murai */ 44375240ed1SBrian Somers static void 444944f7098SBrian Somers FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 445944f7098SBrian Somers /* RCR */ 446af57ed9fSAtsushi Murai { 44730c2f2ffSBrian Somers struct fsm_decode dec; 44853c9f6c0SAtsushi Murai int plen, flen; 449af57ed9fSAtsushi Murai int ackaction = 0; 450af57ed9fSAtsushi Murai 451dd7e2610SBrian Somers plen = mbuf_Length(bp); 45270ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 45353c9f6c0SAtsushi Murai if (plen < flen) { 454a33b2ef7SBrian Somers log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 455d47dceb8SBrian Somers fp->link->name, plen, flen); 456dd7e2610SBrian Somers mbuf_Free(bp); 457af57ed9fSAtsushi Murai return; 458af57ed9fSAtsushi Murai } 459af57ed9fSAtsushi Murai 460af57ed9fSAtsushi Murai /* 461af57ed9fSAtsushi Murai * Check and process easy case 462af57ed9fSAtsushi Murai */ 463af57ed9fSAtsushi Murai switch (fp->state) { 464af57ed9fSAtsushi Murai case ST_INITIAL: 46506337856SBrian Somers if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 46606337856SBrian Somers /* 46706337856SBrian Somers * ccp_SetOpenMode() leaves us in initial if we're disabling 46806337856SBrian Somers * & denying everything. This is a bit smelly, we know that 46906337856SBrian Somers * ``bp'' really has ``fsmheader'' in front of it, and CCP_PROTO 47006337856SBrian Somers * in front of that. CCP_PROTO isn't compressed either 'cos it 47106337856SBrian Somers * doesn't begin with 0x00.... 47206337856SBrian Somers */ 47306337856SBrian Somers bp->offset -= sizeof(struct fsmheader) + 2; 47406337856SBrian Somers bp->cnt += sizeof(struct fsmheader) + 2; 47506337856SBrian Somers lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->cnt); 47606337856SBrian Somers mbuf_Free(bp); 47706337856SBrian Somers return; 47806337856SBrian Somers } 47906337856SBrian Somers /* Drop through */ 480af57ed9fSAtsushi Murai case ST_STARTING: 481dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 482d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 483dd7e2610SBrian Somers mbuf_Free(bp); 484af57ed9fSAtsushi Murai return; 485af57ed9fSAtsushi Murai case ST_CLOSED: 4862267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 487dd7e2610SBrian Somers mbuf_Free(bp); 488af57ed9fSAtsushi Murai return; 489af57ed9fSAtsushi Murai case ST_CLOSING: 490dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 491d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 492a9c503afSBrian Somers case ST_STOPPING: 493dd7e2610SBrian Somers mbuf_Free(bp); 494af57ed9fSAtsushi Murai return; 49568a0e171SBrian Somers case ST_OPENED: 49668a0e171SBrian Somers (*fp->fn->LayerDown)(fp); 49768a0e171SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 49868a0e171SBrian Somers break; 499af57ed9fSAtsushi Murai } 500af57ed9fSAtsushi Murai 50130c2f2ffSBrian Somers dec.ackend = dec.ack; 50230c2f2ffSBrian Somers dec.nakend = dec.nak; 50330c2f2ffSBrian Somers dec.rejend = dec.rej; 50430c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec); 5052267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 506dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 507af57ed9fSAtsushi Murai 50830c2f2ffSBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 509af57ed9fSAtsushi Murai ackaction = 1; 510af57ed9fSAtsushi Murai 511af57ed9fSAtsushi Murai switch (fp->state) { 512af57ed9fSAtsushi Murai case ST_STOPPED: 513af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 51468a0e171SBrian Somers /* Fall through */ 51568a0e171SBrian Somers 51668a0e171SBrian Somers case ST_OPENED: 517af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 518af57ed9fSAtsushi Murai break; 519af57ed9fSAtsushi Murai } 520af57ed9fSAtsushi Murai 52130c2f2ffSBrian Somers if (dec.rejend != dec.rej) 522dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej); 52330c2f2ffSBrian Somers if (dec.nakend != dec.nak) 524dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak); 525af57ed9fSAtsushi Murai if (ackaction) 526dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack); 527af57ed9fSAtsushi Murai 528af57ed9fSAtsushi Murai switch (fp->state) { 529af57ed9fSAtsushi Murai case ST_OPENED: 530455aabc3SBrian Somers case ST_STOPPED: 531af57ed9fSAtsushi Murai if (ackaction) 532af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 533af57ed9fSAtsushi Murai else 534af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 535af57ed9fSAtsushi Murai break; 536af57ed9fSAtsushi Murai case ST_REQSENT: 537af57ed9fSAtsushi Murai if (ackaction) 538af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 539af57ed9fSAtsushi Murai break; 540af57ed9fSAtsushi Murai case ST_ACKRCVD: 541af57ed9fSAtsushi Murai if (ackaction) { 542af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5436f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5446d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5456f384573SBrian Somers else { 5466f384573SBrian Somers (*fp->fn->LayerDown)(fp); 5476f384573SBrian Somers FsmInitRestartCounter(fp); 5486f384573SBrian Somers FsmSendTerminateReq(fp); 5496f384573SBrian Somers NewState(fp, ST_CLOSING); 5506f384573SBrian Somers } 551af57ed9fSAtsushi Murai } 552af57ed9fSAtsushi Murai break; 553af57ed9fSAtsushi Murai case ST_ACKSENT: 554af57ed9fSAtsushi Murai if (!ackaction) 555af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 556af57ed9fSAtsushi Murai break; 557af57ed9fSAtsushi Murai } 558dd7e2610SBrian Somers mbuf_Free(bp); 559af57ed9fSAtsushi Murai } 560af57ed9fSAtsushi Murai 56175240ed1SBrian Somers static void 562944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 563944f7098SBrian Somers /* RCA */ 564af57ed9fSAtsushi Murai { 565af57ed9fSAtsushi Murai switch (fp->state) { 566af57ed9fSAtsushi Murai case ST_CLOSED: 567af57ed9fSAtsushi Murai case ST_STOPPED: 5682267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 569af57ed9fSAtsushi Murai break; 570af57ed9fSAtsushi Murai case ST_CLOSING: 571af57ed9fSAtsushi Murai case ST_STOPPING: 572af57ed9fSAtsushi Murai break; 573af57ed9fSAtsushi Murai case ST_REQSENT: 574af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 575af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 576af57ed9fSAtsushi Murai break; 577af57ed9fSAtsushi Murai case ST_ACKRCVD: 578af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 579af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 580af57ed9fSAtsushi Murai break; 581af57ed9fSAtsushi Murai case ST_ACKSENT: 582af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 583af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5846f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5856d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5866f384573SBrian Somers else { 5876f384573SBrian Somers (*fp->fn->LayerDown)(fp); 5886f384573SBrian Somers FsmInitRestartCounter(fp); 5896f384573SBrian Somers FsmSendTerminateReq(fp); 5906f384573SBrian Somers NewState(fp, ST_CLOSING); 5916f384573SBrian Somers } 592af57ed9fSAtsushi Murai break; 593af57ed9fSAtsushi Murai case ST_OPENED: 5946d666775SBrian Somers (*fp->fn->LayerDown)(fp); 595af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 596af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 5976d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 598af57ed9fSAtsushi Murai break; 599af57ed9fSAtsushi Murai } 600dd7e2610SBrian Somers mbuf_Free(bp); 601af57ed9fSAtsushi Murai } 602af57ed9fSAtsushi Murai 60375240ed1SBrian Somers static void 604944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 605944f7098SBrian Somers /* RCN */ 606af57ed9fSAtsushi Murai { 60730c2f2ffSBrian Somers struct fsm_decode dec; 60853c9f6c0SAtsushi Murai int plen, flen; 609af57ed9fSAtsushi Murai 610dd7e2610SBrian Somers plen = mbuf_Length(bp); 61170ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 61253c9f6c0SAtsushi Murai if (plen < flen) { 613dd7e2610SBrian Somers mbuf_Free(bp); 614af57ed9fSAtsushi Murai return; 615af57ed9fSAtsushi Murai } 616af57ed9fSAtsushi Murai 617af57ed9fSAtsushi Murai /* 618af57ed9fSAtsushi Murai * Check and process easy case 619af57ed9fSAtsushi Murai */ 620af57ed9fSAtsushi Murai switch (fp->state) { 621af57ed9fSAtsushi Murai case ST_INITIAL: 622af57ed9fSAtsushi Murai case ST_STARTING: 623dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 624d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 625dd7e2610SBrian Somers mbuf_Free(bp); 626af57ed9fSAtsushi Murai return; 627af57ed9fSAtsushi Murai case ST_CLOSED: 628af57ed9fSAtsushi Murai case ST_STOPPED: 6292267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 630dd7e2610SBrian Somers mbuf_Free(bp); 631af57ed9fSAtsushi Murai return; 632af57ed9fSAtsushi Murai case ST_CLOSING: 633af57ed9fSAtsushi Murai case ST_STOPPING: 634dd7e2610SBrian Somers mbuf_Free(bp); 635af57ed9fSAtsushi Murai return; 636af57ed9fSAtsushi Murai } 637af57ed9fSAtsushi Murai 63830c2f2ffSBrian Somers dec.ackend = dec.ack; 63930c2f2ffSBrian Somers dec.nakend = dec.nak; 64030c2f2ffSBrian Somers dec.rejend = dec.rej; 64130c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); 6422267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 643dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 644af57ed9fSAtsushi Murai 645af57ed9fSAtsushi Murai switch (fp->state) { 646af57ed9fSAtsushi Murai case ST_REQSENT: 647af57ed9fSAtsushi Murai case ST_ACKSENT: 648af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 649af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 650af57ed9fSAtsushi Murai break; 651af57ed9fSAtsushi Murai case ST_OPENED: 6526d666775SBrian Somers (*fp->fn->LayerDown)(fp); 653455aabc3SBrian Somers FsmSendConfigReq(fp); 654455aabc3SBrian Somers NewState(fp, ST_REQSENT); 6556d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 656455aabc3SBrian Somers break; 657af57ed9fSAtsushi Murai case ST_ACKRCVD: 658af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 659af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 660af57ed9fSAtsushi Murai break; 661af57ed9fSAtsushi Murai } 662af57ed9fSAtsushi Murai 663dd7e2610SBrian Somers mbuf_Free(bp); 664af57ed9fSAtsushi Murai } 665af57ed9fSAtsushi Murai 66675240ed1SBrian Somers static void 667944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 668944f7098SBrian Somers /* RTR */ 669af57ed9fSAtsushi Murai { 670af57ed9fSAtsushi Murai switch (fp->state) { 671af57ed9fSAtsushi Murai case ST_INITIAL: 672af57ed9fSAtsushi Murai case ST_STARTING: 673dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 674d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 675af57ed9fSAtsushi Murai break; 676af57ed9fSAtsushi Murai case ST_CLOSED: 677af57ed9fSAtsushi Murai case ST_STOPPED: 678af57ed9fSAtsushi Murai case ST_CLOSING: 679af57ed9fSAtsushi Murai case ST_STOPPING: 680af57ed9fSAtsushi Murai case ST_REQSENT: 6812267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 682af57ed9fSAtsushi Murai break; 683af57ed9fSAtsushi Murai case ST_ACKRCVD: 684af57ed9fSAtsushi Murai case ST_ACKSENT: 6852267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 686af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 687af57ed9fSAtsushi Murai break; 688af57ed9fSAtsushi Murai case ST_OPENED: 6896d666775SBrian Somers (*fp->fn->LayerDown)(fp); 6902267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 69174d14b4cSBrian Somers FsmInitRestartCounter(fp); 692dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 6938f2fa0eeSBrian Somers fp->restart = 0; 6948f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 6956d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 696af57ed9fSAtsushi Murai break; 697af57ed9fSAtsushi Murai } 698dd7e2610SBrian Somers mbuf_Free(bp); 699af57ed9fSAtsushi Murai } 700af57ed9fSAtsushi Murai 70175240ed1SBrian Somers static void 702944f7098SBrian Somers FsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 703944f7098SBrian Somers /* RTA */ 704af57ed9fSAtsushi Murai { 705af57ed9fSAtsushi Murai switch (fp->state) { 706af57ed9fSAtsushi Murai case ST_CLOSING: 7076d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 708af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 7096d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 710af57ed9fSAtsushi Murai break; 711af57ed9fSAtsushi Murai case ST_STOPPING: 7126d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 713af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 7146d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 715af57ed9fSAtsushi Murai break; 716af57ed9fSAtsushi Murai case ST_ACKRCVD: 717af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 718af57ed9fSAtsushi Murai break; 719af57ed9fSAtsushi Murai case ST_OPENED: 7206d666775SBrian Somers (*fp->fn->LayerDown)(fp); 721af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 722af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 7236d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 724af57ed9fSAtsushi Murai break; 725af57ed9fSAtsushi Murai } 726dd7e2610SBrian Somers mbuf_Free(bp); 727af57ed9fSAtsushi Murai } 728af57ed9fSAtsushi Murai 72975240ed1SBrian Somers static void 730944f7098SBrian Somers FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 731944f7098SBrian Somers /* RCJ */ 732af57ed9fSAtsushi Murai { 73330c2f2ffSBrian Somers struct fsm_decode dec; 73453c9f6c0SAtsushi Murai int plen, flen; 735af57ed9fSAtsushi Murai 736dd7e2610SBrian Somers plen = mbuf_Length(bp); 73770ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 73853c9f6c0SAtsushi Murai if (plen < flen) { 739dd7e2610SBrian Somers mbuf_Free(bp); 740af57ed9fSAtsushi Murai return; 741af57ed9fSAtsushi Murai } 742af57ed9fSAtsushi Murai 743af57ed9fSAtsushi Murai /* 744af57ed9fSAtsushi Murai * Check and process easy case 745af57ed9fSAtsushi Murai */ 746af57ed9fSAtsushi Murai switch (fp->state) { 747af57ed9fSAtsushi Murai case ST_INITIAL: 748af57ed9fSAtsushi Murai case ST_STARTING: 749dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 750d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 751dd7e2610SBrian Somers mbuf_Free(bp); 752af57ed9fSAtsushi Murai return; 753af57ed9fSAtsushi Murai case ST_CLOSED: 754af57ed9fSAtsushi Murai case ST_STOPPED: 7552267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 756dd7e2610SBrian Somers mbuf_Free(bp); 757af57ed9fSAtsushi Murai return; 758af57ed9fSAtsushi Murai case ST_CLOSING: 759af57ed9fSAtsushi Murai case ST_STOPPING: 760dd7e2610SBrian Somers mbuf_Free(bp); 761af57ed9fSAtsushi Murai return; 762af57ed9fSAtsushi Murai } 763af57ed9fSAtsushi Murai 76430c2f2ffSBrian Somers dec.ackend = dec.ack; 76530c2f2ffSBrian Somers dec.nakend = dec.nak; 76630c2f2ffSBrian Somers dec.rejend = dec.rej; 76730c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); 7682267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 769dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 770af57ed9fSAtsushi Murai 771af57ed9fSAtsushi Murai switch (fp->state) { 772af57ed9fSAtsushi Murai case ST_REQSENT: 773af57ed9fSAtsushi Murai case ST_ACKSENT: 774af57ed9fSAtsushi Murai FsmInitRestartCounter(fp); 775af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 776af57ed9fSAtsushi Murai break; 777af57ed9fSAtsushi Murai case ST_OPENED: 7786d666775SBrian Somers (*fp->fn->LayerDown)(fp); 779455aabc3SBrian Somers FsmSendConfigReq(fp); 780455aabc3SBrian Somers NewState(fp, ST_REQSENT); 7816d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 782455aabc3SBrian Somers break; 783af57ed9fSAtsushi Murai case ST_ACKRCVD: 784af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 785af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 786af57ed9fSAtsushi Murai break; 787af57ed9fSAtsushi Murai } 788dd7e2610SBrian Somers mbuf_Free(bp); 789af57ed9fSAtsushi Murai } 790af57ed9fSAtsushi Murai 79175240ed1SBrian Somers static void 792944f7098SBrian Somers FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 793af57ed9fSAtsushi Murai { 794dd7e2610SBrian Somers mbuf_Free(bp); 795af57ed9fSAtsushi Murai } 796af57ed9fSAtsushi Murai 79775240ed1SBrian Somers static void 798944f7098SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 799af57ed9fSAtsushi Murai { 8008c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 801af57ed9fSAtsushi Murai u_short *sp, proto; 802af57ed9fSAtsushi Murai 803af57ed9fSAtsushi Murai sp = (u_short *)MBUF_CTOP(bp); 804af57ed9fSAtsushi Murai proto = ntohs(*sp); 805dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 806d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 807af57ed9fSAtsushi Murai 808af57ed9fSAtsushi Murai switch (proto) { 809af57ed9fSAtsushi Murai case PROTO_LQR: 8108c07a7b2SBrian Somers if (p) 811dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 8128c07a7b2SBrian Somers else 813dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 814d47dceb8SBrian Somers fp->link->name); 815af57ed9fSAtsushi Murai break; 816af57ed9fSAtsushi Murai case PROTO_CCP: 817dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 8183b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 8196d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 820af57ed9fSAtsushi Murai switch (fp->state) { 821af57ed9fSAtsushi Murai case ST_CLOSED: 822af57ed9fSAtsushi Murai case ST_CLOSING: 823af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 824af57ed9fSAtsushi Murai default: 825af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 826af57ed9fSAtsushi Murai break; 827af57ed9fSAtsushi Murai } 8286d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 829dc0fdb6bSBrian Somers } 8301ae349f5Scvs2svn break; 831673903ecSBrian Somers case PROTO_MP: 832673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 833673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 834673903ecSBrian Somers 835673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 836dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 837d47dceb8SBrian Somers fp->link->name); 838dd7e2610SBrian Somers fsm_Close(fp); 839673903ecSBrian Somers } 840673903ecSBrian Somers } 841af57ed9fSAtsushi Murai break; 842af57ed9fSAtsushi Murai } 843dd7e2610SBrian Somers mbuf_Free(bp); 844af57ed9fSAtsushi Murai } 845af57ed9fSAtsushi Murai 84675240ed1SBrian Somers static void 847944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 848af57ed9fSAtsushi Murai { 849dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 850af57ed9fSAtsushi Murai u_char *cp; 851fe3125a0SBrian Somers u_int32_t magic; 852af57ed9fSAtsushi Murai 853dc0fdb6bSBrian Somers if (lcp) { 854af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 8559e8ec64bSBrian Somers ua_ntohl(cp, &magic); 856dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 857dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: Error: His magic is bad!!\n", 858d47dceb8SBrian Somers fp->link->name); 859af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 860af57ed9fSAtsushi Murai } 861af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 8629e8ec64bSBrian Somers ua_htonl(&lcp->want_magic, cp); /* local magic */ 863dd7e2610SBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, mbuf_Length(bp)); 864af57ed9fSAtsushi Murai } 865dc0fdb6bSBrian Somers } 866dd7e2610SBrian Somers mbuf_Free(bp); 867af57ed9fSAtsushi Murai } 868af57ed9fSAtsushi Murai 86975240ed1SBrian Somers static void 870944f7098SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 871af57ed9fSAtsushi Murai { 872dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 873fe3125a0SBrian Somers u_int32_t magic; 874af57ed9fSAtsushi Murai 875dc0fdb6bSBrian Somers if (lcp) { 8769e8ec64bSBrian Somers ua_ntohl(MBUF_CTOP(bp), &magic); 877879ed6faSBrian Somers /* Tolerate echo replies with either magic number */ 878dc0fdb6bSBrian Somers if (magic != 0 && magic != lcp->his_magic && magic != lcp->want_magic) { 879dd7e2610SBrian Somers log_Printf(LogWARN, 880d47dceb8SBrian Somers "%s: RecvEchoRep: Bad magic: expected 0x%08x, got: 0x%08x\n", 881d47dceb8SBrian Somers fp->link->name, lcp->his_magic, magic); 88285c59f05SJoerg Wunsch /* 883fe3125a0SBrian Somers * XXX: We should send terminate request. But poor implementations may 884fe3125a0SBrian Somers * die as a result. 885af57ed9fSAtsushi Murai */ 886af57ed9fSAtsushi Murai } 887dd7e2610SBrian Somers lqr_RecvEcho(fp, bp); 888dc0fdb6bSBrian Somers } 889dd7e2610SBrian Somers mbuf_Free(bp); 890af57ed9fSAtsushi Murai } 891af57ed9fSAtsushi Murai 89275240ed1SBrian Somers static void 893944f7098SBrian Somers FsmRecvDiscReq(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 FsmRecvIdent(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 FsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 906af57ed9fSAtsushi Murai { 907dd7e2610SBrian Somers mbuf_Free(bp); 908af57ed9fSAtsushi Murai } 909af57ed9fSAtsushi Murai 91075240ed1SBrian Somers static void 911944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 912af57ed9fSAtsushi Murai { 913503a7782SBrian Somers (*fp->fn->RecvResetReq)(fp); 91498baf7c8SBrian Somers /* 91598baf7c8SBrian Somers * All sendable compressed packets are queued in the PRI_NORMAL modem 91698baf7c8SBrian Somers * output queue.... dump 'em to the priority queue so that they arrive 91798baf7c8SBrian Somers * at the peer before our ResetAck. 91898baf7c8SBrian Somers */ 9198c07a7b2SBrian Somers link_SequenceQueue(fp->link); 920dd7e2610SBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0); 921dd7e2610SBrian Somers mbuf_Free(bp); 922af57ed9fSAtsushi Murai } 923af57ed9fSAtsushi Murai 92475240ed1SBrian Somers static void 925944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 926af57ed9fSAtsushi Murai { 927503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 928dd7e2610SBrian Somers mbuf_Free(bp); 929af57ed9fSAtsushi Murai } 930af57ed9fSAtsushi Murai 931af57ed9fSAtsushi Murai void 932dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 933af57ed9fSAtsushi Murai { 934af57ed9fSAtsushi Murai int len; 935af57ed9fSAtsushi Murai struct fsmheader *lhp; 9360053cc58SBrian Somers const struct fsmcodedesc *codep; 937af57ed9fSAtsushi Murai 938dd7e2610SBrian Somers len = mbuf_Length(bp); 939af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 940dd7e2610SBrian Somers mbuf_Free(bp); 941af57ed9fSAtsushi Murai return; 942af57ed9fSAtsushi Murai } 943af57ed9fSAtsushi Murai lhp = (struct fsmheader *) MBUF_CTOP(bp); 9443b0f8d2eSBrian Somers if (lhp->code < fp->min_code || lhp->code > fp->max_code || 9457308ec68SBrian Somers lhp->code > sizeof FsmCodes / sizeof *FsmCodes) { 9463b0f8d2eSBrian Somers /* 9473b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 9483b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 9493b0f8d2eSBrian Somers */ 9503b0f8d2eSBrian Somers static u_char id; 951d93d3a9cSBrian Somers 952dd7e2610SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->cnt); 953dd7e2610SBrian Somers mbuf_Free(bp); 954af57ed9fSAtsushi Murai return; 955af57ed9fSAtsushi Murai } 956af57ed9fSAtsushi Murai bp->offset += sizeof(struct fsmheader); 957af57ed9fSAtsushi Murai bp->cnt -= sizeof(struct fsmheader); 958af57ed9fSAtsushi Murai 959af57ed9fSAtsushi Murai codep = FsmCodes + lhp->code - 1; 9601342caedSBrian Somers if (lhp->id != fp->reqid && codep->check_reqid && 9611342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 962dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 963d47dceb8SBrian Somers fp->link->name, codep->name, lhp->id, fp->reqid); 9642267893fSBrian Somers return; 9652267893fSBrian Somers } 9662267893fSBrian Somers 967dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 968d47dceb8SBrian Somers fp->link->name, codep->name, lhp->id, State2Nam(fp->state)); 9692267893fSBrian Somers 970dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 971dd7e2610SBrian Somers mbuf_Log(); 9722267893fSBrian Somers 9732267893fSBrian Somers if (codep->inc_reqid && (lhp->id == fp->reqid || 9741342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 9752267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 9762267893fSBrian Somers 9771342caedSBrian Somers (*codep->recv)(fp, lhp, bp); 9782267893fSBrian Somers 979dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 980dd7e2610SBrian Somers mbuf_Log(); 9811ae349f5Scvs2svn } 982503a7782SBrian Somers 983503a7782SBrian Somers void 984dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 985503a7782SBrian Somers { 986dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 987d47dceb8SBrian Somers fp->link->name); 988503a7782SBrian Somers } 989503a7782SBrian Somers 990503a7782SBrian Somers void 991dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 992503a7782SBrian Somers { 993dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 994d47dceb8SBrian Somers fp->link->name); 995af57ed9fSAtsushi Murai } 99609206a6fSBrian Somers 99709206a6fSBrian Somers void 998897f9429SBrian Somers fsm_Reopen(struct fsm *fp) 999897f9429SBrian Somers { 1000897f9429SBrian Somers if (fp->state == ST_OPENED) { 1001897f9429SBrian Somers (*fp->fn->LayerDown)(fp); 1002897f9429SBrian Somers FsmInitRestartCounter(fp); 1003897f9429SBrian Somers FsmSendConfigReq(fp); 1004897f9429SBrian Somers NewState(fp, ST_REQSENT); 1005897f9429SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 1006897f9429SBrian Somers } 1007897f9429SBrian Somers } 1008897f9429SBrian Somers 1009897f9429SBrian Somers void 101009206a6fSBrian Somers fsm2initial(struct fsm *fp) 101109206a6fSBrian Somers { 101209206a6fSBrian Somers if (fp->state == ST_STOPPED) 101309206a6fSBrian Somers fsm_Close(fp); 101409206a6fSBrian Somers if (fp->state > ST_INITIAL) 101509206a6fSBrian Somers fsm_Down(fp); 101609206a6fSBrian Somers if (fp->state > ST_INITIAL) 101709206a6fSBrian Somers fsm_Close(fp); 101809206a6fSBrian Somers } 1019