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 * 203377c28cSBrian Somers * $Id: fsm.c,v 1.42 1999/05/08 11:06:35 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 345d9e6103SBrian Somers #include "layer.h" 359e8ec64bSBrian Somers #include "ua.h" 3675240ed1SBrian Somers #include "mbuf.h" 3775240ed1SBrian Somers #include "log.h" 3875240ed1SBrian Somers #include "defs.h" 3975240ed1SBrian Somers #include "timer.h" 40af57ed9fSAtsushi Murai #include "fsm.h" 411342caedSBrian Somers #include "iplist.h" 42af57ed9fSAtsushi Murai #include "lqr.h" 43879ed6faSBrian Somers #include "hdlc.h" 441342caedSBrian Somers #include "throughput.h" 451342caedSBrian Somers #include "slcompress.h" 461342caedSBrian Somers #include "ipcp.h" 471342caedSBrian Somers #include "filter.h" 481342caedSBrian Somers #include "descriptor.h" 49af57ed9fSAtsushi Murai #include "lcp.h" 50ed6a16c1SPoul-Henning Kamp #include "ccp.h" 518c07a7b2SBrian Somers #include "link.h" 521342caedSBrian Somers #include "mp.h" 53972a1bcfSBrian Somers #ifndef NORADIUS 54972a1bcfSBrian Somers #include "radius.h" 55972a1bcfSBrian Somers #endif 561342caedSBrian Somers #include "bundle.h" 571342caedSBrian Somers #include "async.h" 5863b73463SBrian Somers #include "physical.h" 595d9e6103SBrian Somers #include "proto.h" 6075240ed1SBrian Somers 6175240ed1SBrian Somers static void FsmSendConfigReq(struct fsm *); 6275240ed1SBrian Somers static void FsmSendTerminateReq(struct fsm *); 63479508cfSBrian Somers static void FsmInitRestartCounter(struct fsm *, int); 64af57ed9fSAtsushi Murai 652267893fSBrian Somers typedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *); 662267893fSBrian Somers static recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak, 672267893fSBrian Somers FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck, 682267893fSBrian Somers FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq, 692267893fSBrian Somers FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent, 702267893fSBrian Somers FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck; 712267893fSBrian Somers 722267893fSBrian Somers static const struct fsmcodedesc { 732267893fSBrian Somers recvfn *recv; 742267893fSBrian Somers unsigned check_reqid : 1; 752267893fSBrian Somers unsigned inc_reqid : 1; 762267893fSBrian Somers const char *name; 772267893fSBrian Somers } FsmCodes[] = { 782267893fSBrian Somers { FsmRecvConfigReq, 0, 0, "ConfigReq" }, 792267893fSBrian Somers { FsmRecvConfigAck, 1, 1, "ConfigAck" }, 802267893fSBrian Somers { FsmRecvConfigNak, 1, 1, "ConfigNak" }, 812267893fSBrian Somers { FsmRecvConfigRej, 1, 1, "ConfigRej" }, 822267893fSBrian Somers { FsmRecvTermReq, 0, 0, "TerminateReq" }, 832267893fSBrian Somers { FsmRecvTermAck, 1, 1, "TerminateAck" }, 842267893fSBrian Somers { FsmRecvCodeRej, 0, 0, "CodeRej" }, 852267893fSBrian Somers { FsmRecvProtoRej, 0, 0, "ProtocolRej" }, 862267893fSBrian Somers { FsmRecvEchoReq, 0, 0, "EchoRequest" }, 872267893fSBrian Somers { FsmRecvEchoRep, 0, 0, "EchoReply" }, 882267893fSBrian Somers { FsmRecvDiscReq, 0, 0, "DiscardReq" }, 892267893fSBrian Somers { FsmRecvIdent, 0, 0, "Ident" }, 902267893fSBrian Somers { FsmRecvTimeRemain,0, 0, "TimeRemain" }, 915d9e6103SBrian Somers { FsmRecvResetReq, 0, 0, "ResetReq" }, 922267893fSBrian Somers { FsmRecvResetAck, 0, 1, "ResetAck" } 932267893fSBrian Somers }; 942267893fSBrian Somers 952267893fSBrian Somers static const char * 962267893fSBrian Somers Code2Nam(u_int code) 972267893fSBrian Somers { 982267893fSBrian Somers if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0]) 992267893fSBrian Somers return "Unknown"; 1002267893fSBrian Somers return FsmCodes[code-1].name; 1012267893fSBrian Somers } 1022267893fSBrian Somers 1031e991daaSBrian Somers const char * 1041e991daaSBrian Somers State2Nam(u_int state) 1051e991daaSBrian Somers { 1061e991daaSBrian Somers static const char *StateNames[] = { 107af57ed9fSAtsushi Murai "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", 108927145beSBrian Somers "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", 109af57ed9fSAtsushi Murai }; 110af57ed9fSAtsushi Murai 1111e991daaSBrian Somers if (state >= sizeof StateNames / sizeof StateNames[0]) 1121e991daaSBrian Somers return "unknown"; 1131e991daaSBrian Somers return StateNames[state]; 1141e991daaSBrian Somers } 1151e991daaSBrian Somers 11671144dc5SBrian Somers static void 117b6e82f33SBrian Somers StoppedTimeout(void *v) 11871144dc5SBrian Somers { 119b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 120b6e82f33SBrian Somers 121dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name); 12249b239e0SBrian Somers if (fp->OpenTimer.state == TIMER_RUNNING) { 123dd7e2610SBrian Somers log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n", 124d47dceb8SBrian Somers fp->link->name, fp->name); 125dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 12649b239e0SBrian Somers } 12709206a6fSBrian Somers if (fp->state == ST_STOPPED) 12809206a6fSBrian Somers fsm2initial(fp); 12971144dc5SBrian Somers } 13071144dc5SBrian Somers 131af57ed9fSAtsushi Murai void 1323b0f8d2eSBrian Somers fsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, 133479508cfSBrian Somers int maxcode, int LogLevel, struct bundle *bundle, 1343b0f8d2eSBrian Somers struct link *l, const struct fsm_parent *parent, 1353b0f8d2eSBrian Somers struct fsm_callbacks *fn, const char *timer_names[3]) 136af57ed9fSAtsushi Murai { 137503a7782SBrian Somers fp->name = name; 138503a7782SBrian Somers fp->proto = proto; 1393b0f8d2eSBrian Somers fp->min_code = mincode; 140503a7782SBrian Somers fp->max_code = maxcode; 1413b0f8d2eSBrian Somers fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; 142af57ed9fSAtsushi Murai fp->reqid = 1; 143af57ed9fSAtsushi Murai fp->restart = 1; 1445d9e6103SBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = 3; 145503a7782SBrian Somers memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); 146503a7782SBrian Somers memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); 147503a7782SBrian Somers memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); 148503a7782SBrian Somers fp->LogLevel = LogLevel; 1498c07a7b2SBrian Somers fp->link = l; 1507a6f8720SBrian Somers fp->bundle = bundle; 1516d666775SBrian Somers fp->parent = parent; 152503a7782SBrian Somers fp->fn = fn; 1533b0f8d2eSBrian Somers fp->FsmTimer.name = timer_names[0]; 1543b0f8d2eSBrian Somers fp->OpenTimer.name = timer_names[1]; 1553b0f8d2eSBrian Somers fp->StoppedTimer.name = timer_names[2]; 156af57ed9fSAtsushi Murai } 157af57ed9fSAtsushi Murai 15875240ed1SBrian Somers static void 159944f7098SBrian Somers NewState(struct fsm *fp, int new) 160af57ed9fSAtsushi Murai { 161dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", 162d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state), State2Nam(new)); 163cb611434SBrian Somers if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) 164dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 165af57ed9fSAtsushi Murai fp->state = new; 16671144dc5SBrian Somers if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { 167dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 168cb611434SBrian Somers if (new == ST_STOPPED && fp->StoppedTimer.load) { 169dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 170cb611434SBrian Somers fp->StoppedTimer.func = StoppedTimeout; 171cb611434SBrian Somers fp->StoppedTimer.arg = (void *) fp; 172dd7e2610SBrian Somers timer_Start(&fp->StoppedTimer); 17371144dc5SBrian Somers } 17471144dc5SBrian Somers } 175af57ed9fSAtsushi Murai } 176af57ed9fSAtsushi Murai 177af57ed9fSAtsushi Murai void 178dd7e2610SBrian Somers fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count) 179af57ed9fSAtsushi Murai { 180af57ed9fSAtsushi Murai int plen; 181af57ed9fSAtsushi Murai struct fsmheader lh; 182af57ed9fSAtsushi Murai struct mbuf *bp; 183af57ed9fSAtsushi Murai 184dd7e2610SBrian Somers if (log_IsKept(fp->LogLevel)) { 185dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 186d47dceb8SBrian Somers fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 1872267893fSBrian Somers switch (code) { 1882267893fSBrian Somers case CODE_CONFIGREQ: 1892267893fSBrian Somers case CODE_CONFIGACK: 1902267893fSBrian Somers case CODE_CONFIGREJ: 1912267893fSBrian Somers case CODE_CONFIGNAK: 1922267893fSBrian Somers (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL); 1932267893fSBrian Somers if (count < sizeof(struct fsmconfig)) 194dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 1952267893fSBrian Somers break; 1962267893fSBrian Somers } 1972267893fSBrian Somers } 1982267893fSBrian Somers 199af57ed9fSAtsushi Murai plen = sizeof(struct fsmheader) + count; 200af57ed9fSAtsushi Murai lh.code = code; 201af57ed9fSAtsushi Murai lh.id = id; 202af57ed9fSAtsushi Murai lh.length = htons(plen); 203dd7e2610SBrian Somers bp = mbuf_Alloc(plen, MB_FSM); 20475240ed1SBrian Somers memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 205af57ed9fSAtsushi Murai if (count) 20675240ed1SBrian Somers memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 207dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "fsm_Output", bp); 2085d9e6103SBrian Somers link_PushPacket(fp->link, bp, fp->bundle, PRI_LINK, fp->proto); 209af57ed9fSAtsushi Murai } 210af57ed9fSAtsushi Murai 21149b239e0SBrian Somers static void 21249b239e0SBrian Somers FsmOpenNow(void *v) 21349b239e0SBrian Somers { 21449b239e0SBrian Somers struct fsm *fp = (struct fsm *)v; 21549b239e0SBrian Somers 216dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 21749b239e0SBrian Somers if (fp->state <= ST_STOPPED) { 2183a2e4f62SBrian Somers if (fp->state != ST_STARTING) { 2193a2e4f62SBrian Somers /* 2203a2e4f62SBrian Somers * In practice, we're only here in ST_STOPPED (when delaying the 2213a2e4f62SBrian Somers * first config request) or ST_CLOSED (when openmode == 0). 2223a2e4f62SBrian Somers * 2233a2e4f62SBrian Somers * The ST_STOPPED bit is breaking the RFC already :-( 2243a2e4f62SBrian Somers * 2253a2e4f62SBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 2263a2e4f62SBrian Somers * required for an Open event when state == Closed, but the RFC 2273a2e4f62SBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 2283a2e4f62SBrian Somers * ie, Initial gets an `Up' event, Closing gets a RTA etc. 2293a2e4f62SBrian Somers */ 2303a2e4f62SBrian Somers (*fp->fn->LayerStart)(fp); 2313a2e4f62SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 2323a2e4f62SBrian Somers } 233479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 23449b239e0SBrian Somers FsmSendConfigReq(fp); 23549b239e0SBrian Somers NewState(fp, ST_REQSENT); 23649b239e0SBrian Somers } 23749b239e0SBrian Somers } 23849b239e0SBrian Somers 239af57ed9fSAtsushi Murai void 240dd7e2610SBrian Somers fsm_Open(struct fsm *fp) 241af57ed9fSAtsushi Murai { 242af57ed9fSAtsushi Murai switch (fp->state) { 243af57ed9fSAtsushi Murai case ST_INITIAL: 244af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 2456d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2466d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 247af57ed9fSAtsushi Murai break; 248af57ed9fSAtsushi Murai case ST_CLOSED: 249af57ed9fSAtsushi Murai if (fp->open_mode == OPEN_PASSIVE) { 2503a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 25149b239e0SBrian Somers } else if (fp->open_mode > 0) { 25249b239e0SBrian Somers if (fp->open_mode > 1) 253dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 254d47dceb8SBrian Somers fp->link->name, fp->open_mode); 2553a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 256dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 25749b239e0SBrian Somers fp->OpenTimer.load = fp->open_mode * SECTICKS; 25849b239e0SBrian Somers fp->OpenTimer.func = FsmOpenNow; 25949b239e0SBrian Somers fp->OpenTimer.arg = (void *)fp; 260dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 26149b239e0SBrian Somers } else 26249b239e0SBrian Somers FsmOpenNow(fp); 263af57ed9fSAtsushi Murai break; 264af57ed9fSAtsushi Murai case ST_STOPPED: /* XXX: restart option */ 265af57ed9fSAtsushi Murai case ST_REQSENT: 266af57ed9fSAtsushi Murai case ST_ACKRCVD: 267af57ed9fSAtsushi Murai case ST_ACKSENT: 268af57ed9fSAtsushi Murai case ST_OPENED: /* XXX: restart option */ 269af57ed9fSAtsushi Murai break; 270af57ed9fSAtsushi Murai case ST_CLOSING: /* XXX: restart option */ 271af57ed9fSAtsushi Murai case ST_STOPPING: /* XXX: restart option */ 272af57ed9fSAtsushi Murai NewState(fp, ST_STOPPING); 273af57ed9fSAtsushi Murai break; 274af57ed9fSAtsushi Murai } 275af57ed9fSAtsushi Murai } 276af57ed9fSAtsushi Murai 277af57ed9fSAtsushi Murai void 278dd7e2610SBrian Somers fsm_Up(struct fsm *fp) 279af57ed9fSAtsushi Murai { 280af57ed9fSAtsushi Murai switch (fp->state) { 281af57ed9fSAtsushi Murai case ST_INITIAL: 282dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 2831fa665f5SBrian Somers fp->link->name); 284af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 285af57ed9fSAtsushi Murai break; 286af57ed9fSAtsushi Murai case ST_STARTING: 287479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 288af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 289af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 290af57ed9fSAtsushi Murai break; 291af57ed9fSAtsushi Murai default: 292dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 293d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 294af57ed9fSAtsushi Murai break; 295af57ed9fSAtsushi Murai } 296af57ed9fSAtsushi Murai } 297af57ed9fSAtsushi Murai 298af57ed9fSAtsushi Murai void 299dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 300af57ed9fSAtsushi Murai { 301af57ed9fSAtsushi Murai switch (fp->state) { 302af57ed9fSAtsushi Murai case ST_CLOSED: 303af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 304af57ed9fSAtsushi Murai break; 305455aabc3SBrian Somers case ST_CLOSING: 3068a8d9927SBrian Somers /* This TLF contradicts the RFC (1661), which ``misses it out'' ! */ 3076d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 308455aabc3SBrian Somers NewState(fp, ST_INITIAL); 3096d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 310455aabc3SBrian Somers break; 311af57ed9fSAtsushi Murai case ST_STOPPED: 312455aabc3SBrian Somers NewState(fp, ST_STARTING); 3136d666775SBrian Somers (*fp->fn->LayerStart)(fp); 3146d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 315455aabc3SBrian Somers break; 316af57ed9fSAtsushi Murai case ST_STOPPING: 317af57ed9fSAtsushi Murai case ST_REQSENT: 318af57ed9fSAtsushi Murai case ST_ACKRCVD: 319af57ed9fSAtsushi Murai case ST_ACKSENT: 320af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 321af57ed9fSAtsushi Murai break; 322af57ed9fSAtsushi Murai case ST_OPENED: 3236d666775SBrian Somers (*fp->fn->LayerDown)(fp); 324af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 3256d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 326af57ed9fSAtsushi Murai break; 327af57ed9fSAtsushi Murai } 328af57ed9fSAtsushi Murai } 329af57ed9fSAtsushi Murai 330af57ed9fSAtsushi Murai void 331dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 332af57ed9fSAtsushi Murai { 333af57ed9fSAtsushi Murai switch (fp->state) { 334af57ed9fSAtsushi Murai case ST_STARTING: 3356d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 336af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 3376d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 338af57ed9fSAtsushi Murai break; 339af57ed9fSAtsushi Murai case ST_STOPPED: 340af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 341af57ed9fSAtsushi Murai break; 342af57ed9fSAtsushi Murai case ST_STOPPING: 343af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 344af57ed9fSAtsushi Murai break; 345af57ed9fSAtsushi Murai case ST_OPENED: 3466d666775SBrian Somers (*fp->fn->LayerDown)(fp); 347479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 348455aabc3SBrian Somers FsmSendTerminateReq(fp); 349455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3506d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 351455aabc3SBrian Somers break; 352af57ed9fSAtsushi Murai case ST_REQSENT: 353af57ed9fSAtsushi Murai case ST_ACKRCVD: 354af57ed9fSAtsushi Murai case ST_ACKSENT: 355479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 356af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 357af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 358af57ed9fSAtsushi Murai break; 359af57ed9fSAtsushi Murai } 360af57ed9fSAtsushi Murai } 361af57ed9fSAtsushi Murai 362af57ed9fSAtsushi Murai /* 363af57ed9fSAtsushi Murai * Send functions 364af57ed9fSAtsushi Murai */ 36575240ed1SBrian Somers static void 366944f7098SBrian Somers FsmSendConfigReq(struct fsm *fp) 367af57ed9fSAtsushi Murai { 368479508cfSBrian Somers if (fp->more.reqs-- > 0 && fp->restart-- > 0) { 36983d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 370dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 371af57ed9fSAtsushi Murai } else { 372479508cfSBrian Somers if (fp->more.reqs < 0) 373479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REQs sent - abandoning " 374479508cfSBrian Somers "negotiation\n", fp->link->name, fp->name); 375dd7e2610SBrian Somers fsm_Close(fp); 376af57ed9fSAtsushi Murai } 377af57ed9fSAtsushi Murai } 378af57ed9fSAtsushi Murai 37975240ed1SBrian Somers static void 380944f7098SBrian Somers FsmSendTerminateReq(struct fsm *fp) 381af57ed9fSAtsushi Murai { 382dd7e2610SBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0); 3832267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 384dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 385af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 386af57ed9fSAtsushi Murai } 387af57ed9fSAtsushi Murai 388af57ed9fSAtsushi Murai /* 389af57ed9fSAtsushi Murai * Timeout actions 390af57ed9fSAtsushi Murai */ 39175240ed1SBrian Somers static void 392b6e82f33SBrian Somers FsmTimeout(void *v) 393af57ed9fSAtsushi Murai { 394b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 395b6e82f33SBrian Somers 396af57ed9fSAtsushi Murai if (fp->restart) { 397af57ed9fSAtsushi Murai switch (fp->state) { 398af57ed9fSAtsushi Murai case ST_CLOSING: 399af57ed9fSAtsushi Murai case ST_STOPPING: 400af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 401af57ed9fSAtsushi Murai break; 402af57ed9fSAtsushi Murai case ST_REQSENT: 403af57ed9fSAtsushi Murai case ST_ACKSENT: 404af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 405af57ed9fSAtsushi Murai break; 406af57ed9fSAtsushi Murai case ST_ACKRCVD: 407af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 408af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 409af57ed9fSAtsushi Murai break; 410af57ed9fSAtsushi Murai } 411dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 412af57ed9fSAtsushi Murai } else { 413af57ed9fSAtsushi Murai switch (fp->state) { 414af57ed9fSAtsushi Murai case ST_CLOSING: 4156d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 416af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 4176d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 418af57ed9fSAtsushi Murai break; 419af57ed9fSAtsushi Murai case ST_STOPPING: 4206d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 421af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4226d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 423af57ed9fSAtsushi Murai break; 424af57ed9fSAtsushi Murai case ST_REQSENT: /* XXX: 3p */ 425af57ed9fSAtsushi Murai case ST_ACKSENT: 426af57ed9fSAtsushi Murai case ST_ACKRCVD: 4276d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 428af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4296d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 430af57ed9fSAtsushi Murai break; 431af57ed9fSAtsushi Murai } 432af57ed9fSAtsushi Murai } 433af57ed9fSAtsushi Murai } 434af57ed9fSAtsushi Murai 43575240ed1SBrian Somers static void 436479508cfSBrian Somers FsmInitRestartCounter(struct fsm *fp, int what) 437af57ed9fSAtsushi Murai { 438dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 439af57ed9fSAtsushi Murai fp->FsmTimer.func = FsmTimeout; 440af57ed9fSAtsushi Murai fp->FsmTimer.arg = (void *)fp; 441479508cfSBrian Somers (*fp->fn->InitRestartCounter)(fp, what); 442af57ed9fSAtsushi Murai } 443af57ed9fSAtsushi Murai 444af57ed9fSAtsushi Murai /* 445af57ed9fSAtsushi Murai * Actions when receive packets 446af57ed9fSAtsushi Murai */ 44775240ed1SBrian Somers static void 448944f7098SBrian Somers FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 449944f7098SBrian Somers /* RCR */ 450af57ed9fSAtsushi Murai { 45130c2f2ffSBrian Somers struct fsm_decode dec; 45253c9f6c0SAtsushi Murai int plen, flen; 453af57ed9fSAtsushi Murai int ackaction = 0; 454af57ed9fSAtsushi Murai 455dd7e2610SBrian Somers plen = mbuf_Length(bp); 45670ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 45753c9f6c0SAtsushi Murai if (plen < flen) { 458a33b2ef7SBrian Somers log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 459d47dceb8SBrian Somers fp->link->name, plen, flen); 460dd7e2610SBrian Somers mbuf_Free(bp); 461af57ed9fSAtsushi Murai return; 462af57ed9fSAtsushi Murai } 463af57ed9fSAtsushi Murai 4643377c28cSBrian Somers /* Check and process easy case */ 465af57ed9fSAtsushi Murai switch (fp->state) { 466af57ed9fSAtsushi Murai case ST_INITIAL: 46706337856SBrian Somers if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 46806337856SBrian Somers /* 46906337856SBrian Somers * ccp_SetOpenMode() leaves us in initial if we're disabling 4705d9e6103SBrian Somers * & denying everything. 47106337856SBrian Somers */ 4725d9e6103SBrian Somers bp = mbuf_Prepend(bp, lhp, sizeof *lhp, 2); 4735d9e6103SBrian Somers bp = proto_Prepend(bp, fp->proto, 0, 0); 4745d9e6103SBrian Somers bp = mbuf_Contiguous(bp); 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 5015d9e6103SBrian Somers bp = mbuf_Contiguous(bp); 50230c2f2ffSBrian Somers dec.ackend = dec.ack; 50330c2f2ffSBrian Somers dec.nakend = dec.nak; 50430c2f2ffSBrian Somers dec.rejend = dec.rej; 50530c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec); 5062267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 507dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 508af57ed9fSAtsushi Murai 50930c2f2ffSBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 510af57ed9fSAtsushi Murai ackaction = 1; 511af57ed9fSAtsushi Murai 512af57ed9fSAtsushi Murai switch (fp->state) { 513af57ed9fSAtsushi Murai case ST_STOPPED: 514479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 51568a0e171SBrian Somers /* Fall through */ 51668a0e171SBrian Somers 51768a0e171SBrian Somers case ST_OPENED: 518af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 519af57ed9fSAtsushi Murai break; 520af57ed9fSAtsushi Murai } 521af57ed9fSAtsushi Murai 52230c2f2ffSBrian Somers if (dec.rejend != dec.rej) 523dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej); 52430c2f2ffSBrian Somers if (dec.nakend != dec.nak) 525dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak); 526af57ed9fSAtsushi Murai if (ackaction) 527dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack); 528af57ed9fSAtsushi Murai 529af57ed9fSAtsushi Murai switch (fp->state) { 530455aabc3SBrian Somers case ST_STOPPED: 531479508cfSBrian Somers /* 532479508cfSBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 533479508cfSBrian Somers * required for a RCR when state == ST_STOPPED, but the RFC 534479508cfSBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 535479508cfSBrian Somers */ 536479508cfSBrian Somers (*fp->fn->LayerStart)(fp); 537479508cfSBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 538479508cfSBrian Somers /* Fall through */ 539479508cfSBrian Somers 540479508cfSBrian Somers case ST_OPENED: 541af57ed9fSAtsushi Murai if (ackaction) 542af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 543af57ed9fSAtsushi Murai else 544af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 545af57ed9fSAtsushi Murai break; 546af57ed9fSAtsushi Murai case ST_REQSENT: 547af57ed9fSAtsushi Murai if (ackaction) 548af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 549af57ed9fSAtsushi Murai break; 550af57ed9fSAtsushi Murai case ST_ACKRCVD: 551af57ed9fSAtsushi Murai if (ackaction) { 552af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5536f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5546d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5556f384573SBrian Somers else { 5566f384573SBrian Somers (*fp->fn->LayerDown)(fp); 557479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 5586f384573SBrian Somers FsmSendTerminateReq(fp); 5596f384573SBrian Somers NewState(fp, ST_CLOSING); 5606f384573SBrian Somers } 561af57ed9fSAtsushi Murai } 562af57ed9fSAtsushi Murai break; 563af57ed9fSAtsushi Murai case ST_ACKSENT: 564af57ed9fSAtsushi Murai if (!ackaction) 565af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 566af57ed9fSAtsushi Murai break; 567af57ed9fSAtsushi Murai } 568dd7e2610SBrian Somers mbuf_Free(bp); 569479508cfSBrian Somers 570479508cfSBrian Somers if (dec.rejend != dec.rej && --fp->more.rejs <= 0) { 571479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REJs sent - abandoning negotiation\n", 572479508cfSBrian Somers fp->link->name, fp->name); 573479508cfSBrian Somers fsm_Close(fp); 574479508cfSBrian Somers } 575479508cfSBrian Somers 576479508cfSBrian Somers if (dec.nakend != dec.nak && --fp->more.naks <= 0) { 577479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s NAKs sent - abandoning negotiation\n", 578479508cfSBrian Somers fp->link->name, fp->name); 579479508cfSBrian Somers fsm_Close(fp); 580479508cfSBrian Somers } 581af57ed9fSAtsushi Murai } 582af57ed9fSAtsushi Murai 58375240ed1SBrian Somers static void 584944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 585944f7098SBrian Somers /* RCA */ 586af57ed9fSAtsushi Murai { 587af57ed9fSAtsushi Murai switch (fp->state) { 588af57ed9fSAtsushi Murai case ST_CLOSED: 589af57ed9fSAtsushi Murai case ST_STOPPED: 5902267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 591af57ed9fSAtsushi Murai break; 592af57ed9fSAtsushi Murai case ST_CLOSING: 593af57ed9fSAtsushi Murai case ST_STOPPING: 594af57ed9fSAtsushi Murai break; 595af57ed9fSAtsushi Murai case ST_REQSENT: 596479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 597af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 598af57ed9fSAtsushi Murai break; 599af57ed9fSAtsushi Murai case ST_ACKRCVD: 600af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 601af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 602af57ed9fSAtsushi Murai break; 603af57ed9fSAtsushi Murai case ST_ACKSENT: 604479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 605af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 6066f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 6076d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 6086f384573SBrian Somers else { 6096f384573SBrian Somers (*fp->fn->LayerDown)(fp); 610479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 6116f384573SBrian Somers FsmSendTerminateReq(fp); 6126f384573SBrian Somers NewState(fp, ST_CLOSING); 6136f384573SBrian Somers } 614af57ed9fSAtsushi Murai break; 615af57ed9fSAtsushi Murai case ST_OPENED: 6166d666775SBrian Somers (*fp->fn->LayerDown)(fp); 617af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 618af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 6196d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 620af57ed9fSAtsushi Murai break; 621af57ed9fSAtsushi Murai } 622dd7e2610SBrian Somers mbuf_Free(bp); 623af57ed9fSAtsushi Murai } 624af57ed9fSAtsushi Murai 62575240ed1SBrian Somers static void 626944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 627944f7098SBrian Somers /* RCN */ 628af57ed9fSAtsushi Murai { 62930c2f2ffSBrian Somers struct fsm_decode dec; 63053c9f6c0SAtsushi Murai int plen, flen; 631af57ed9fSAtsushi Murai 632dd7e2610SBrian Somers plen = mbuf_Length(bp); 63370ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 63453c9f6c0SAtsushi Murai if (plen < flen) { 635dd7e2610SBrian Somers mbuf_Free(bp); 636af57ed9fSAtsushi Murai return; 637af57ed9fSAtsushi Murai } 638af57ed9fSAtsushi Murai 639af57ed9fSAtsushi Murai /* 640af57ed9fSAtsushi Murai * Check and process easy case 641af57ed9fSAtsushi Murai */ 642af57ed9fSAtsushi Murai switch (fp->state) { 643af57ed9fSAtsushi Murai case ST_INITIAL: 644af57ed9fSAtsushi Murai case ST_STARTING: 645dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 646d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 647dd7e2610SBrian Somers mbuf_Free(bp); 648af57ed9fSAtsushi Murai return; 649af57ed9fSAtsushi Murai case ST_CLOSED: 650af57ed9fSAtsushi Murai case ST_STOPPED: 6512267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 652dd7e2610SBrian Somers mbuf_Free(bp); 653af57ed9fSAtsushi Murai return; 654af57ed9fSAtsushi Murai case ST_CLOSING: 655af57ed9fSAtsushi Murai case ST_STOPPING: 656dd7e2610SBrian Somers mbuf_Free(bp); 657af57ed9fSAtsushi Murai return; 658af57ed9fSAtsushi Murai } 659af57ed9fSAtsushi Murai 6603377c28cSBrian Somers bp = mbuf_Contiguous(bp); 66130c2f2ffSBrian Somers dec.ackend = dec.ack; 66230c2f2ffSBrian Somers dec.nakend = dec.nak; 66330c2f2ffSBrian Somers dec.rejend = dec.rej; 66430c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); 6652267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 666dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 667af57ed9fSAtsushi Murai 668af57ed9fSAtsushi Murai switch (fp->state) { 669af57ed9fSAtsushi Murai case ST_REQSENT: 670af57ed9fSAtsushi Murai case ST_ACKSENT: 671479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 672af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 673af57ed9fSAtsushi Murai break; 674af57ed9fSAtsushi Murai case ST_OPENED: 6756d666775SBrian Somers (*fp->fn->LayerDown)(fp); 676455aabc3SBrian Somers FsmSendConfigReq(fp); 677455aabc3SBrian Somers NewState(fp, ST_REQSENT); 6786d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 679455aabc3SBrian Somers break; 680af57ed9fSAtsushi Murai case ST_ACKRCVD: 681af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 682af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 683af57ed9fSAtsushi Murai break; 684af57ed9fSAtsushi Murai } 685af57ed9fSAtsushi Murai 686dd7e2610SBrian Somers mbuf_Free(bp); 687af57ed9fSAtsushi Murai } 688af57ed9fSAtsushi Murai 68975240ed1SBrian Somers static void 690944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 691944f7098SBrian Somers /* RTR */ 692af57ed9fSAtsushi Murai { 693af57ed9fSAtsushi Murai switch (fp->state) { 694af57ed9fSAtsushi Murai case ST_INITIAL: 695af57ed9fSAtsushi Murai case ST_STARTING: 696dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 697d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 698af57ed9fSAtsushi Murai break; 699af57ed9fSAtsushi Murai case ST_CLOSED: 700af57ed9fSAtsushi Murai case ST_STOPPED: 701af57ed9fSAtsushi Murai case ST_CLOSING: 702af57ed9fSAtsushi Murai case ST_STOPPING: 703af57ed9fSAtsushi Murai case ST_REQSENT: 7042267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 705af57ed9fSAtsushi Murai break; 706af57ed9fSAtsushi Murai case ST_ACKRCVD: 707af57ed9fSAtsushi Murai case ST_ACKSENT: 7082267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 709af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 710af57ed9fSAtsushi Murai break; 711af57ed9fSAtsushi Murai case ST_OPENED: 7126d666775SBrian Somers (*fp->fn->LayerDown)(fp); 7132267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 714479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 715dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 7168f2fa0eeSBrian Somers fp->restart = 0; 7178f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 7186d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 719479508cfSBrian Somers /* A delayed ST_STOPPED is now scheduled */ 720af57ed9fSAtsushi Murai break; 721af57ed9fSAtsushi Murai } 722dd7e2610SBrian Somers mbuf_Free(bp); 723af57ed9fSAtsushi Murai } 724af57ed9fSAtsushi Murai 72575240ed1SBrian Somers static void 726944f7098SBrian Somers FsmRecvTermAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 727944f7098SBrian Somers /* RTA */ 728af57ed9fSAtsushi Murai { 729af57ed9fSAtsushi Murai switch (fp->state) { 730af57ed9fSAtsushi Murai case ST_CLOSING: 7316d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 732af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 7336d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 734af57ed9fSAtsushi Murai break; 735af57ed9fSAtsushi Murai case ST_STOPPING: 7366d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 737af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 7386d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 739af57ed9fSAtsushi Murai break; 740af57ed9fSAtsushi Murai case ST_ACKRCVD: 741af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 742af57ed9fSAtsushi Murai break; 743af57ed9fSAtsushi Murai case ST_OPENED: 7446d666775SBrian Somers (*fp->fn->LayerDown)(fp); 745af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 746af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 7476d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 748af57ed9fSAtsushi Murai break; 749af57ed9fSAtsushi Murai } 750dd7e2610SBrian Somers mbuf_Free(bp); 751af57ed9fSAtsushi Murai } 752af57ed9fSAtsushi Murai 75375240ed1SBrian Somers static void 754944f7098SBrian Somers FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 755944f7098SBrian Somers /* RCJ */ 756af57ed9fSAtsushi Murai { 75730c2f2ffSBrian Somers struct fsm_decode dec; 75853c9f6c0SAtsushi Murai int plen, flen; 759af57ed9fSAtsushi Murai 760dd7e2610SBrian Somers plen = mbuf_Length(bp); 76170ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 76253c9f6c0SAtsushi Murai if (plen < flen) { 763dd7e2610SBrian Somers mbuf_Free(bp); 764af57ed9fSAtsushi Murai return; 765af57ed9fSAtsushi Murai } 766af57ed9fSAtsushi Murai 767af57ed9fSAtsushi Murai /* 768af57ed9fSAtsushi Murai * Check and process easy case 769af57ed9fSAtsushi Murai */ 770af57ed9fSAtsushi Murai switch (fp->state) { 771af57ed9fSAtsushi Murai case ST_INITIAL: 772af57ed9fSAtsushi Murai case ST_STARTING: 773dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 774d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 775dd7e2610SBrian Somers mbuf_Free(bp); 776af57ed9fSAtsushi Murai return; 777af57ed9fSAtsushi Murai case ST_CLOSED: 778af57ed9fSAtsushi Murai case ST_STOPPED: 7792267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 780dd7e2610SBrian Somers mbuf_Free(bp); 781af57ed9fSAtsushi Murai return; 782af57ed9fSAtsushi Murai case ST_CLOSING: 783af57ed9fSAtsushi Murai case ST_STOPPING: 784dd7e2610SBrian Somers mbuf_Free(bp); 785af57ed9fSAtsushi Murai return; 786af57ed9fSAtsushi Murai } 787af57ed9fSAtsushi Murai 7883377c28cSBrian Somers bp = mbuf_Contiguous(bp); 78930c2f2ffSBrian Somers dec.ackend = dec.ack; 79030c2f2ffSBrian Somers dec.nakend = dec.nak; 79130c2f2ffSBrian Somers dec.rejend = dec.rej; 79230c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); 7932267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 794dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 795af57ed9fSAtsushi Murai 796af57ed9fSAtsushi Murai switch (fp->state) { 797af57ed9fSAtsushi Murai case ST_REQSENT: 798af57ed9fSAtsushi Murai case ST_ACKSENT: 799479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 800af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 801af57ed9fSAtsushi Murai break; 802af57ed9fSAtsushi Murai case ST_OPENED: 8036d666775SBrian Somers (*fp->fn->LayerDown)(fp); 804455aabc3SBrian Somers FsmSendConfigReq(fp); 805455aabc3SBrian Somers NewState(fp, ST_REQSENT); 8066d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 807455aabc3SBrian Somers break; 808af57ed9fSAtsushi Murai case ST_ACKRCVD: 809af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 810af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 811af57ed9fSAtsushi Murai break; 812af57ed9fSAtsushi Murai } 813dd7e2610SBrian Somers mbuf_Free(bp); 814af57ed9fSAtsushi Murai } 815af57ed9fSAtsushi Murai 81675240ed1SBrian Somers static void 817944f7098SBrian Somers FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 818af57ed9fSAtsushi Murai { 819dd7e2610SBrian Somers mbuf_Free(bp); 820af57ed9fSAtsushi Murai } 821af57ed9fSAtsushi Murai 82275240ed1SBrian Somers static void 823944f7098SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 824af57ed9fSAtsushi Murai { 8258c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 8263377c28cSBrian Somers u_short proto; 827af57ed9fSAtsushi Murai 8283377c28cSBrian Somers if (mbuf_Length(bp) < 2) { 8293377c28cSBrian Somers mbuf_Free(bp); 8303377c28cSBrian Somers return; 8313377c28cSBrian Somers } 8323377c28cSBrian Somers bp = mbuf_Read(bp, &proto, 2); 8333377c28cSBrian Somers proto = ntohs(proto); 834dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 835d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 836af57ed9fSAtsushi Murai 837af57ed9fSAtsushi Murai switch (proto) { 838af57ed9fSAtsushi Murai case PROTO_LQR: 8398c07a7b2SBrian Somers if (p) 840dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 8418c07a7b2SBrian Somers else 842dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 843d47dceb8SBrian Somers fp->link->name); 844af57ed9fSAtsushi Murai break; 845af57ed9fSAtsushi Murai case PROTO_CCP: 846dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 8473b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 8488a8d9927SBrian Somers /* Despite the RFC (1661), don't do an out-of-place TLF */ 8498a8d9927SBrian Somers /* (*fp->fn->LayerFinish)(fp); */ 850af57ed9fSAtsushi Murai switch (fp->state) { 851af57ed9fSAtsushi Murai case ST_CLOSED: 852af57ed9fSAtsushi Murai case ST_CLOSING: 853af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 854af57ed9fSAtsushi Murai default: 855af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 856af57ed9fSAtsushi Murai break; 857af57ed9fSAtsushi Murai } 8588a8d9927SBrian Somers /* See above */ 8598a8d9927SBrian Somers /* (*fp->parent->LayerFinish)(fp->parent->object, fp); */ 860dc0fdb6bSBrian Somers } 8611ae349f5Scvs2svn break; 862673903ecSBrian Somers case PROTO_MP: 863673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 864673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 865673903ecSBrian Somers 866673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 867dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 868d47dceb8SBrian Somers fp->link->name); 869dd7e2610SBrian Somers fsm_Close(fp); 870673903ecSBrian Somers } 871673903ecSBrian Somers } 872af57ed9fSAtsushi Murai break; 873af57ed9fSAtsushi Murai } 874dd7e2610SBrian Somers mbuf_Free(bp); 875af57ed9fSAtsushi Murai } 876af57ed9fSAtsushi Murai 87775240ed1SBrian Somers static void 878944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 879af57ed9fSAtsushi Murai { 880dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 881af57ed9fSAtsushi Murai u_char *cp; 882fe3125a0SBrian Somers u_int32_t magic; 883af57ed9fSAtsushi Murai 8843377c28cSBrian Somers if (lcp && mbuf_Length(bp) >= 4) { 885af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 8869e8ec64bSBrian Somers ua_ntohl(cp, &magic); 887dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 888dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: Error: His magic is bad!!\n", 889d47dceb8SBrian Somers fp->link->name); 890af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 891af57ed9fSAtsushi Murai } 892af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 8939e8ec64bSBrian Somers ua_htonl(&lcp->want_magic, cp); /* local magic */ 894dd7e2610SBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, mbuf_Length(bp)); 895af57ed9fSAtsushi Murai } 896dc0fdb6bSBrian Somers } 897dd7e2610SBrian Somers mbuf_Free(bp); 898af57ed9fSAtsushi Murai } 899af57ed9fSAtsushi Murai 90075240ed1SBrian Somers static void 901944f7098SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 902af57ed9fSAtsushi Murai { 903dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 904fe3125a0SBrian Somers u_int32_t magic; 905af57ed9fSAtsushi Murai 9063377c28cSBrian Somers if (lcp && mbuf_Length(bp) >= 4) { 9073377c28cSBrian Somers mbuf_Read(bp, &magic, 4); 9083377c28cSBrian Somers magic = ntohl(magic); 909879ed6faSBrian Somers /* Tolerate echo replies with either magic number */ 910dc0fdb6bSBrian Somers if (magic != 0 && magic != lcp->his_magic && magic != lcp->want_magic) { 9113377c28cSBrian Somers log_Printf(LogWARN, "%s: RecvEchoRep: Bad magic: expected 0x%08x," 9123377c28cSBrian Somers " got 0x%08x\n", fp->link->name, lcp->his_magic, magic); 91385c59f05SJoerg Wunsch /* 914fe3125a0SBrian Somers * XXX: We should send terminate request. But poor implementations may 915fe3125a0SBrian Somers * die as a result. 916af57ed9fSAtsushi Murai */ 917af57ed9fSAtsushi Murai } 9183377c28cSBrian Somers bp = lqr_RecvEcho(fp, bp); 919dc0fdb6bSBrian Somers } 920dd7e2610SBrian Somers mbuf_Free(bp); 921af57ed9fSAtsushi Murai } 922af57ed9fSAtsushi Murai 92375240ed1SBrian Somers static void 924944f7098SBrian Somers FsmRecvDiscReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 925af57ed9fSAtsushi Murai { 926dd7e2610SBrian Somers mbuf_Free(bp); 927af57ed9fSAtsushi Murai } 928af57ed9fSAtsushi Murai 92975240ed1SBrian Somers static void 930944f7098SBrian Somers FsmRecvIdent(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 931af57ed9fSAtsushi Murai { 932dd7e2610SBrian Somers mbuf_Free(bp); 933af57ed9fSAtsushi Murai } 934af57ed9fSAtsushi Murai 93575240ed1SBrian Somers static void 936944f7098SBrian Somers FsmRecvTimeRemain(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 937af57ed9fSAtsushi Murai { 938dd7e2610SBrian Somers mbuf_Free(bp); 939af57ed9fSAtsushi Murai } 940af57ed9fSAtsushi Murai 94175240ed1SBrian Somers static void 942944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 943af57ed9fSAtsushi Murai { 944503a7782SBrian Somers (*fp->fn->RecvResetReq)(fp); 94598baf7c8SBrian Somers /* 94698baf7c8SBrian Somers * All sendable compressed packets are queued in the PRI_NORMAL modem 94798baf7c8SBrian Somers * output queue.... dump 'em to the priority queue so that they arrive 94898baf7c8SBrian Somers * at the peer before our ResetAck. 94998baf7c8SBrian Somers */ 9508c07a7b2SBrian Somers link_SequenceQueue(fp->link); 951dd7e2610SBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0); 952dd7e2610SBrian Somers mbuf_Free(bp); 953af57ed9fSAtsushi Murai } 954af57ed9fSAtsushi Murai 95575240ed1SBrian Somers static void 956944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 957af57ed9fSAtsushi Murai { 958503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 959dd7e2610SBrian Somers mbuf_Free(bp); 960af57ed9fSAtsushi Murai } 961af57ed9fSAtsushi Murai 962af57ed9fSAtsushi Murai void 963dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 964af57ed9fSAtsushi Murai { 965af57ed9fSAtsushi Murai int len; 9665d9e6103SBrian Somers struct fsmheader lh; 9670053cc58SBrian Somers const struct fsmcodedesc *codep; 968af57ed9fSAtsushi Murai 969dd7e2610SBrian Somers len = mbuf_Length(bp); 970af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 971dd7e2610SBrian Somers mbuf_Free(bp); 972af57ed9fSAtsushi Murai return; 973af57ed9fSAtsushi Murai } 9745d9e6103SBrian Somers bp = mbuf_Read(bp, &lh, sizeof lh); 9755d9e6103SBrian Somers if (lh.code < fp->min_code || lh.code > fp->max_code || 9765d9e6103SBrian Somers lh.code > sizeof FsmCodes / sizeof *FsmCodes) { 9773b0f8d2eSBrian Somers /* 9783b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 9793b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 9803b0f8d2eSBrian Somers */ 9813b0f8d2eSBrian Somers static u_char id; 982d93d3a9cSBrian Somers 9835d9e6103SBrian Somers bp = mbuf_Prepend(bp, &lh, sizeof lh, 0); 9845d9e6103SBrian Somers bp = mbuf_Contiguous(bp); 985dd7e2610SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->cnt); 986dd7e2610SBrian Somers mbuf_Free(bp); 987af57ed9fSAtsushi Murai return; 988af57ed9fSAtsushi Murai } 989af57ed9fSAtsushi Murai 9905d9e6103SBrian Somers codep = FsmCodes + lh.code - 1; 9915d9e6103SBrian Somers if (lh.id != fp->reqid && codep->check_reqid && 9921342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 993dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 9945d9e6103SBrian Somers fp->link->name, codep->name, lh.id, fp->reqid); 9952267893fSBrian Somers return; 9962267893fSBrian Somers } 9972267893fSBrian Somers 998dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 9995d9e6103SBrian Somers fp->link->name, codep->name, lh.id, State2Nam(fp->state)); 10002267893fSBrian Somers 1001dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 1002dd7e2610SBrian Somers mbuf_Log(); 10032267893fSBrian Somers 10045d9e6103SBrian Somers if (codep->inc_reqid && (lh.id == fp->reqid || 10051342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 10062267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 10072267893fSBrian Somers 10085d9e6103SBrian Somers (*codep->recv)(fp, &lh, bp); 10092267893fSBrian Somers 1010dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 1011dd7e2610SBrian Somers mbuf_Log(); 10121ae349f5Scvs2svn } 1013503a7782SBrian Somers 1014503a7782SBrian Somers void 1015dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 1016503a7782SBrian Somers { 1017dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 1018d47dceb8SBrian Somers fp->link->name); 1019503a7782SBrian Somers } 1020503a7782SBrian Somers 1021503a7782SBrian Somers void 1022dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 1023503a7782SBrian Somers { 1024dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 1025d47dceb8SBrian Somers fp->link->name); 1026af57ed9fSAtsushi Murai } 102709206a6fSBrian Somers 102809206a6fSBrian Somers void 1029897f9429SBrian Somers fsm_Reopen(struct fsm *fp) 1030897f9429SBrian Somers { 1031897f9429SBrian Somers if (fp->state == ST_OPENED) { 1032897f9429SBrian Somers (*fp->fn->LayerDown)(fp); 1033479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 1034897f9429SBrian Somers FsmSendConfigReq(fp); 1035897f9429SBrian Somers NewState(fp, ST_REQSENT); 1036897f9429SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 1037897f9429SBrian Somers } 1038897f9429SBrian Somers } 1039897f9429SBrian Somers 1040897f9429SBrian Somers void 104109206a6fSBrian Somers fsm2initial(struct fsm *fp) 104209206a6fSBrian Somers { 1043479508cfSBrian Somers timer_Stop(&fp->FsmTimer); 1044479508cfSBrian Somers timer_Stop(&fp->OpenTimer); 1045479508cfSBrian Somers timer_Stop(&fp->StoppedTimer); 104609206a6fSBrian Somers if (fp->state == ST_STOPPED) 104709206a6fSBrian Somers fsm_Close(fp); 104809206a6fSBrian Somers if (fp->state > ST_INITIAL) 104909206a6fSBrian Somers fsm_Down(fp); 105009206a6fSBrian Somers if (fp->state > ST_INITIAL) 105109206a6fSBrian Somers fsm_Close(fp); 105209206a6fSBrian Somers } 1053