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 * 208a59beb7SBrian Somers * $Id: fsm.c,v 1.45 1999/06/02 15:58:57 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 178411675baSBrian Somers fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count, 179411675baSBrian Somers int mtype) 180af57ed9fSAtsushi Murai { 181af57ed9fSAtsushi Murai int plen; 182af57ed9fSAtsushi Murai struct fsmheader lh; 183af57ed9fSAtsushi Murai struct mbuf *bp; 184af57ed9fSAtsushi Murai 185dd7e2610SBrian Somers if (log_IsKept(fp->LogLevel)) { 186dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 187d47dceb8SBrian Somers fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 1882267893fSBrian Somers switch (code) { 1892267893fSBrian Somers case CODE_CONFIGREQ: 1902267893fSBrian Somers case CODE_CONFIGACK: 1912267893fSBrian Somers case CODE_CONFIGREJ: 1922267893fSBrian Somers case CODE_CONFIGNAK: 1932267893fSBrian Somers (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL); 1942267893fSBrian Somers if (count < sizeof(struct fsmconfig)) 195dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 1962267893fSBrian Somers break; 1972267893fSBrian Somers } 1982267893fSBrian Somers } 1992267893fSBrian Somers 200af57ed9fSAtsushi Murai plen = sizeof(struct fsmheader) + count; 201af57ed9fSAtsushi Murai lh.code = code; 202af57ed9fSAtsushi Murai lh.id = id; 203af57ed9fSAtsushi Murai lh.length = htons(plen); 204411675baSBrian Somers bp = mbuf_Alloc(plen, mtype); 20575240ed1SBrian Somers memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 206af57ed9fSAtsushi Murai if (count) 20775240ed1SBrian Somers memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 208dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "fsm_Output", bp); 2095d9e6103SBrian Somers link_PushPacket(fp->link, bp, fp->bundle, PRI_LINK, fp->proto); 210af57ed9fSAtsushi Murai } 211af57ed9fSAtsushi Murai 21249b239e0SBrian Somers static void 21349b239e0SBrian Somers FsmOpenNow(void *v) 21449b239e0SBrian Somers { 21549b239e0SBrian Somers struct fsm *fp = (struct fsm *)v; 21649b239e0SBrian Somers 217dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 21849b239e0SBrian Somers if (fp->state <= ST_STOPPED) { 2193a2e4f62SBrian Somers if (fp->state != ST_STARTING) { 2203a2e4f62SBrian Somers /* 2213a2e4f62SBrian Somers * In practice, we're only here in ST_STOPPED (when delaying the 2223a2e4f62SBrian Somers * first config request) or ST_CLOSED (when openmode == 0). 2233a2e4f62SBrian Somers * 2243a2e4f62SBrian Somers * The ST_STOPPED bit is breaking the RFC already :-( 2253a2e4f62SBrian Somers * 2263a2e4f62SBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 2273a2e4f62SBrian Somers * required for an Open event when state == Closed, but the RFC 2283a2e4f62SBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 2293a2e4f62SBrian Somers * ie, Initial gets an `Up' event, Closing gets a RTA etc. 2303a2e4f62SBrian Somers */ 2313a2e4f62SBrian Somers (*fp->fn->LayerStart)(fp); 2323a2e4f62SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 2333a2e4f62SBrian Somers } 234479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 23549b239e0SBrian Somers FsmSendConfigReq(fp); 23649b239e0SBrian Somers NewState(fp, ST_REQSENT); 23749b239e0SBrian Somers } 23849b239e0SBrian Somers } 23949b239e0SBrian Somers 240af57ed9fSAtsushi Murai void 241dd7e2610SBrian Somers fsm_Open(struct fsm *fp) 242af57ed9fSAtsushi Murai { 243af57ed9fSAtsushi Murai switch (fp->state) { 244af57ed9fSAtsushi Murai case ST_INITIAL: 245af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 2466d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2476d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 248af57ed9fSAtsushi Murai break; 249af57ed9fSAtsushi Murai case ST_CLOSED: 250af57ed9fSAtsushi Murai if (fp->open_mode == OPEN_PASSIVE) { 2513a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 25249b239e0SBrian Somers } else if (fp->open_mode > 0) { 25349b239e0SBrian Somers if (fp->open_mode > 1) 254dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 255d47dceb8SBrian Somers fp->link->name, fp->open_mode); 2563a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 257dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 25849b239e0SBrian Somers fp->OpenTimer.load = fp->open_mode * SECTICKS; 25949b239e0SBrian Somers fp->OpenTimer.func = FsmOpenNow; 26049b239e0SBrian Somers fp->OpenTimer.arg = (void *)fp; 261dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 26249b239e0SBrian Somers } else 26349b239e0SBrian Somers FsmOpenNow(fp); 264af57ed9fSAtsushi Murai break; 265af57ed9fSAtsushi Murai case ST_STOPPED: /* XXX: restart option */ 266af57ed9fSAtsushi Murai case ST_REQSENT: 267af57ed9fSAtsushi Murai case ST_ACKRCVD: 268af57ed9fSAtsushi Murai case ST_ACKSENT: 269af57ed9fSAtsushi Murai case ST_OPENED: /* XXX: restart option */ 270af57ed9fSAtsushi Murai break; 271af57ed9fSAtsushi Murai case ST_CLOSING: /* XXX: restart option */ 272af57ed9fSAtsushi Murai case ST_STOPPING: /* XXX: restart option */ 273af57ed9fSAtsushi Murai NewState(fp, ST_STOPPING); 274af57ed9fSAtsushi Murai break; 275af57ed9fSAtsushi Murai } 276af57ed9fSAtsushi Murai } 277af57ed9fSAtsushi Murai 278af57ed9fSAtsushi Murai void 279dd7e2610SBrian Somers fsm_Up(struct fsm *fp) 280af57ed9fSAtsushi Murai { 281af57ed9fSAtsushi Murai switch (fp->state) { 282af57ed9fSAtsushi Murai case ST_INITIAL: 283dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 2841fa665f5SBrian Somers fp->link->name); 285af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 286af57ed9fSAtsushi Murai break; 287af57ed9fSAtsushi Murai case ST_STARTING: 288479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 289af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 290af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 291af57ed9fSAtsushi Murai break; 292af57ed9fSAtsushi Murai default: 293dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 294d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 295af57ed9fSAtsushi Murai break; 296af57ed9fSAtsushi Murai } 297af57ed9fSAtsushi Murai } 298af57ed9fSAtsushi Murai 299af57ed9fSAtsushi Murai void 300dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 301af57ed9fSAtsushi Murai { 302af57ed9fSAtsushi Murai switch (fp->state) { 303af57ed9fSAtsushi Murai case ST_CLOSED: 304af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 305af57ed9fSAtsushi Murai break; 306455aabc3SBrian Somers case ST_CLOSING: 3078a8d9927SBrian Somers /* This TLF contradicts the RFC (1661), which ``misses it out'' ! */ 3086d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 309455aabc3SBrian Somers NewState(fp, ST_INITIAL); 3106d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 311455aabc3SBrian Somers break; 312af57ed9fSAtsushi Murai case ST_STOPPED: 313455aabc3SBrian Somers NewState(fp, ST_STARTING); 3146d666775SBrian Somers (*fp->fn->LayerStart)(fp); 3156d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 316455aabc3SBrian Somers break; 317af57ed9fSAtsushi Murai case ST_STOPPING: 318af57ed9fSAtsushi Murai case ST_REQSENT: 319af57ed9fSAtsushi Murai case ST_ACKRCVD: 320af57ed9fSAtsushi Murai case ST_ACKSENT: 321af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 322af57ed9fSAtsushi Murai break; 323af57ed9fSAtsushi Murai case ST_OPENED: 3246d666775SBrian Somers (*fp->fn->LayerDown)(fp); 325af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 3266d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 327af57ed9fSAtsushi Murai break; 328af57ed9fSAtsushi Murai } 329af57ed9fSAtsushi Murai } 330af57ed9fSAtsushi Murai 331af57ed9fSAtsushi Murai void 332dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 333af57ed9fSAtsushi Murai { 334af57ed9fSAtsushi Murai switch (fp->state) { 335af57ed9fSAtsushi Murai case ST_STARTING: 3366d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 337af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 3386d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 339af57ed9fSAtsushi Murai break; 340af57ed9fSAtsushi Murai case ST_STOPPED: 341af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 342af57ed9fSAtsushi Murai break; 343af57ed9fSAtsushi Murai case ST_STOPPING: 344af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 345af57ed9fSAtsushi Murai break; 346af57ed9fSAtsushi Murai case ST_OPENED: 3476d666775SBrian Somers (*fp->fn->LayerDown)(fp); 348479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 349455aabc3SBrian Somers FsmSendTerminateReq(fp); 350455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3516d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 352455aabc3SBrian Somers break; 353af57ed9fSAtsushi Murai case ST_REQSENT: 354af57ed9fSAtsushi Murai case ST_ACKRCVD: 355af57ed9fSAtsushi Murai case ST_ACKSENT: 356479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 357af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 358af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 359af57ed9fSAtsushi Murai break; 360af57ed9fSAtsushi Murai } 361af57ed9fSAtsushi Murai } 362af57ed9fSAtsushi Murai 363af57ed9fSAtsushi Murai /* 364af57ed9fSAtsushi Murai * Send functions 365af57ed9fSAtsushi Murai */ 36675240ed1SBrian Somers static void 367944f7098SBrian Somers FsmSendConfigReq(struct fsm *fp) 368af57ed9fSAtsushi Murai { 369479508cfSBrian Somers if (fp->more.reqs-- > 0 && fp->restart-- > 0) { 37083d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 371dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 372af57ed9fSAtsushi Murai } else { 373479508cfSBrian Somers if (fp->more.reqs < 0) 374479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REQs sent - abandoning " 375479508cfSBrian Somers "negotiation\n", fp->link->name, fp->name); 376dd7e2610SBrian Somers fsm_Close(fp); 377af57ed9fSAtsushi Murai } 378af57ed9fSAtsushi Murai } 379af57ed9fSAtsushi Murai 38075240ed1SBrian Somers static void 381944f7098SBrian Somers FsmSendTerminateReq(struct fsm *fp) 382af57ed9fSAtsushi Murai { 383411675baSBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0, MB_UNKNOWN); 3842267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 385dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 386af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 387af57ed9fSAtsushi Murai } 388af57ed9fSAtsushi Murai 389af57ed9fSAtsushi Murai /* 390af57ed9fSAtsushi Murai * Timeout actions 391af57ed9fSAtsushi Murai */ 39275240ed1SBrian Somers static void 393b6e82f33SBrian Somers FsmTimeout(void *v) 394af57ed9fSAtsushi Murai { 395b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 396b6e82f33SBrian Somers 397af57ed9fSAtsushi Murai if (fp->restart) { 398af57ed9fSAtsushi Murai switch (fp->state) { 399af57ed9fSAtsushi Murai case ST_CLOSING: 400af57ed9fSAtsushi Murai case ST_STOPPING: 401af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 402af57ed9fSAtsushi Murai break; 403af57ed9fSAtsushi Murai case ST_REQSENT: 404af57ed9fSAtsushi Murai case ST_ACKSENT: 405af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 406af57ed9fSAtsushi Murai break; 407af57ed9fSAtsushi Murai case ST_ACKRCVD: 408af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 409af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 410af57ed9fSAtsushi Murai break; 411af57ed9fSAtsushi Murai } 412dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 413af57ed9fSAtsushi Murai } else { 414af57ed9fSAtsushi Murai switch (fp->state) { 415af57ed9fSAtsushi Murai case ST_CLOSING: 4166d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 417af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 4186d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 419af57ed9fSAtsushi Murai break; 420af57ed9fSAtsushi Murai case ST_STOPPING: 4216d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 422af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4236d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 424af57ed9fSAtsushi Murai break; 425af57ed9fSAtsushi Murai case ST_REQSENT: /* XXX: 3p */ 426af57ed9fSAtsushi Murai case ST_ACKSENT: 427af57ed9fSAtsushi Murai case ST_ACKRCVD: 4286d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 429af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4306d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 431af57ed9fSAtsushi Murai break; 432af57ed9fSAtsushi Murai } 433af57ed9fSAtsushi Murai } 434af57ed9fSAtsushi Murai } 435af57ed9fSAtsushi Murai 43675240ed1SBrian Somers static void 437479508cfSBrian Somers FsmInitRestartCounter(struct fsm *fp, int what) 438af57ed9fSAtsushi Murai { 439dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 440af57ed9fSAtsushi Murai fp->FsmTimer.func = FsmTimeout; 441af57ed9fSAtsushi Murai fp->FsmTimer.arg = (void *)fp; 442479508cfSBrian Somers (*fp->fn->InitRestartCounter)(fp, what); 443af57ed9fSAtsushi Murai } 444af57ed9fSAtsushi Murai 445af57ed9fSAtsushi Murai /* 446af57ed9fSAtsushi Murai * Actions when receive packets 447af57ed9fSAtsushi Murai */ 44875240ed1SBrian Somers static void 449944f7098SBrian Somers FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 450944f7098SBrian Somers /* RCR */ 451af57ed9fSAtsushi Murai { 45230c2f2ffSBrian Somers struct fsm_decode dec; 45353c9f6c0SAtsushi Murai int plen, flen; 454af57ed9fSAtsushi Murai int ackaction = 0; 455af57ed9fSAtsushi Murai 456dd7e2610SBrian Somers plen = mbuf_Length(bp); 45770ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 45853c9f6c0SAtsushi Murai if (plen < flen) { 459a33b2ef7SBrian Somers log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 460d47dceb8SBrian Somers fp->link->name, plen, flen); 461dd7e2610SBrian Somers mbuf_Free(bp); 462af57ed9fSAtsushi Murai return; 463af57ed9fSAtsushi Murai } 464af57ed9fSAtsushi Murai 4653377c28cSBrian Somers /* Check and process easy case */ 466af57ed9fSAtsushi Murai switch (fp->state) { 467af57ed9fSAtsushi Murai case ST_INITIAL: 46806337856SBrian Somers if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 46906337856SBrian Somers /* 47006337856SBrian Somers * ccp_SetOpenMode() leaves us in initial if we're disabling 4715d9e6103SBrian Somers * & denying everything. 47206337856SBrian Somers */ 4735d9e6103SBrian Somers bp = mbuf_Prepend(bp, lhp, sizeof *lhp, 2); 4745d9e6103SBrian Somers bp = proto_Prepend(bp, fp->proto, 0, 0); 4755d9e6103SBrian Somers bp = mbuf_Contiguous(bp); 47606337856SBrian Somers lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->cnt); 47706337856SBrian Somers mbuf_Free(bp); 47806337856SBrian Somers return; 47906337856SBrian Somers } 48006337856SBrian Somers /* Drop through */ 481af57ed9fSAtsushi Murai case ST_STARTING: 482dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 483d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 484dd7e2610SBrian Somers mbuf_Free(bp); 485af57ed9fSAtsushi Murai return; 486af57ed9fSAtsushi Murai case ST_CLOSED: 4872267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 488dd7e2610SBrian Somers mbuf_Free(bp); 489af57ed9fSAtsushi Murai return; 490af57ed9fSAtsushi Murai case ST_CLOSING: 491dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 492d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 493a9c503afSBrian Somers case ST_STOPPING: 494dd7e2610SBrian Somers mbuf_Free(bp); 495af57ed9fSAtsushi Murai return; 49668a0e171SBrian Somers case ST_OPENED: 49768a0e171SBrian Somers (*fp->fn->LayerDown)(fp); 49868a0e171SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 49968a0e171SBrian Somers break; 500af57ed9fSAtsushi Murai } 501af57ed9fSAtsushi Murai 5025d9e6103SBrian Somers bp = mbuf_Contiguous(bp); 50330c2f2ffSBrian Somers dec.ackend = dec.ack; 50430c2f2ffSBrian Somers dec.nakend = dec.nak; 50530c2f2ffSBrian Somers dec.rejend = dec.rej; 50630c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec); 5072267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 508dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 509af57ed9fSAtsushi Murai 51030c2f2ffSBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 511af57ed9fSAtsushi Murai ackaction = 1; 512af57ed9fSAtsushi Murai 513af57ed9fSAtsushi Murai switch (fp->state) { 514af57ed9fSAtsushi Murai case ST_STOPPED: 515479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 51668a0e171SBrian Somers /* Fall through */ 51768a0e171SBrian Somers 51868a0e171SBrian Somers case ST_OPENED: 519af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 520af57ed9fSAtsushi Murai break; 521af57ed9fSAtsushi Murai } 522af57ed9fSAtsushi Murai 52330c2f2ffSBrian Somers if (dec.rejend != dec.rej) 524411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej, 525411675baSBrian Somers MB_UNKNOWN); 52630c2f2ffSBrian Somers if (dec.nakend != dec.nak) 527411675baSBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak, 528411675baSBrian Somers MB_UNKNOWN); 529af57ed9fSAtsushi Murai if (ackaction) 530411675baSBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack, 531411675baSBrian Somers MB_UNKNOWN); 532af57ed9fSAtsushi Murai 533af57ed9fSAtsushi Murai switch (fp->state) { 534455aabc3SBrian Somers case ST_STOPPED: 535479508cfSBrian Somers /* 536479508cfSBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 537479508cfSBrian Somers * required for a RCR when state == ST_STOPPED, but the RFC 538479508cfSBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 539479508cfSBrian Somers */ 540479508cfSBrian Somers (*fp->fn->LayerStart)(fp); 541479508cfSBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 542479508cfSBrian Somers /* Fall through */ 543479508cfSBrian Somers 544479508cfSBrian Somers case ST_OPENED: 545af57ed9fSAtsushi Murai if (ackaction) 546af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 547af57ed9fSAtsushi Murai else 548af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 549af57ed9fSAtsushi Murai break; 550af57ed9fSAtsushi Murai case ST_REQSENT: 551af57ed9fSAtsushi Murai if (ackaction) 552af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 553af57ed9fSAtsushi Murai break; 554af57ed9fSAtsushi Murai case ST_ACKRCVD: 555af57ed9fSAtsushi Murai if (ackaction) { 556af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5576f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5586d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5596f384573SBrian Somers else { 5606f384573SBrian Somers (*fp->fn->LayerDown)(fp); 561479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 5626f384573SBrian Somers FsmSendTerminateReq(fp); 5636f384573SBrian Somers NewState(fp, ST_CLOSING); 5646f384573SBrian Somers } 565af57ed9fSAtsushi Murai } 566af57ed9fSAtsushi Murai break; 567af57ed9fSAtsushi Murai case ST_ACKSENT: 568af57ed9fSAtsushi Murai if (!ackaction) 569af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 570af57ed9fSAtsushi Murai break; 571af57ed9fSAtsushi Murai } 572dd7e2610SBrian Somers mbuf_Free(bp); 573479508cfSBrian Somers 574479508cfSBrian Somers if (dec.rejend != dec.rej && --fp->more.rejs <= 0) { 575479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REJs sent - abandoning negotiation\n", 576479508cfSBrian Somers fp->link->name, fp->name); 577479508cfSBrian Somers fsm_Close(fp); 578479508cfSBrian Somers } 579479508cfSBrian Somers 580479508cfSBrian Somers if (dec.nakend != dec.nak && --fp->more.naks <= 0) { 581479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s NAKs sent - abandoning negotiation\n", 582479508cfSBrian Somers fp->link->name, fp->name); 583479508cfSBrian Somers fsm_Close(fp); 584479508cfSBrian Somers } 585af57ed9fSAtsushi Murai } 586af57ed9fSAtsushi Murai 58775240ed1SBrian Somers static void 588944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 589944f7098SBrian Somers /* RCA */ 590af57ed9fSAtsushi Murai { 591af57ed9fSAtsushi Murai switch (fp->state) { 592af57ed9fSAtsushi Murai case ST_CLOSED: 593af57ed9fSAtsushi Murai case ST_STOPPED: 5942267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 595af57ed9fSAtsushi Murai break; 596af57ed9fSAtsushi Murai case ST_CLOSING: 597af57ed9fSAtsushi Murai case ST_STOPPING: 598af57ed9fSAtsushi Murai break; 599af57ed9fSAtsushi Murai case ST_REQSENT: 600479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 601af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 602af57ed9fSAtsushi Murai break; 603af57ed9fSAtsushi Murai case ST_ACKRCVD: 604af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 605af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 606af57ed9fSAtsushi Murai break; 607af57ed9fSAtsushi Murai case ST_ACKSENT: 608479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 609af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 6106f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 6116d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 6126f384573SBrian Somers else { 6136f384573SBrian Somers (*fp->fn->LayerDown)(fp); 614479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 6156f384573SBrian Somers FsmSendTerminateReq(fp); 6166f384573SBrian Somers NewState(fp, ST_CLOSING); 6176f384573SBrian Somers } 618af57ed9fSAtsushi Murai break; 619af57ed9fSAtsushi Murai case ST_OPENED: 6206d666775SBrian Somers (*fp->fn->LayerDown)(fp); 621af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 622af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 6236d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 624af57ed9fSAtsushi Murai break; 625af57ed9fSAtsushi Murai } 626dd7e2610SBrian Somers mbuf_Free(bp); 627af57ed9fSAtsushi Murai } 628af57ed9fSAtsushi Murai 62975240ed1SBrian Somers static void 630944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 631944f7098SBrian Somers /* RCN */ 632af57ed9fSAtsushi Murai { 63330c2f2ffSBrian Somers struct fsm_decode dec; 63453c9f6c0SAtsushi Murai int plen, flen; 635af57ed9fSAtsushi Murai 636dd7e2610SBrian Somers plen = mbuf_Length(bp); 63770ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 63853c9f6c0SAtsushi Murai if (plen < flen) { 639dd7e2610SBrian Somers mbuf_Free(bp); 640af57ed9fSAtsushi Murai return; 641af57ed9fSAtsushi Murai } 642af57ed9fSAtsushi Murai 643af57ed9fSAtsushi Murai /* 644af57ed9fSAtsushi Murai * Check and process easy case 645af57ed9fSAtsushi Murai */ 646af57ed9fSAtsushi Murai switch (fp->state) { 647af57ed9fSAtsushi Murai case ST_INITIAL: 648af57ed9fSAtsushi Murai case ST_STARTING: 649dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 650d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 651dd7e2610SBrian Somers mbuf_Free(bp); 652af57ed9fSAtsushi Murai return; 653af57ed9fSAtsushi Murai case ST_CLOSED: 654af57ed9fSAtsushi Murai case ST_STOPPED: 6552267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 656dd7e2610SBrian Somers mbuf_Free(bp); 657af57ed9fSAtsushi Murai return; 658af57ed9fSAtsushi Murai case ST_CLOSING: 659af57ed9fSAtsushi Murai case ST_STOPPING: 660dd7e2610SBrian Somers mbuf_Free(bp); 661af57ed9fSAtsushi Murai return; 662af57ed9fSAtsushi Murai } 663af57ed9fSAtsushi Murai 6643377c28cSBrian Somers bp = mbuf_Contiguous(bp); 66530c2f2ffSBrian Somers dec.ackend = dec.ack; 66630c2f2ffSBrian Somers dec.nakend = dec.nak; 66730c2f2ffSBrian Somers dec.rejend = dec.rej; 66830c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); 6692267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 670dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 671af57ed9fSAtsushi Murai 672af57ed9fSAtsushi Murai switch (fp->state) { 673af57ed9fSAtsushi Murai case ST_REQSENT: 674af57ed9fSAtsushi Murai case ST_ACKSENT: 675479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 676af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 677af57ed9fSAtsushi Murai break; 678af57ed9fSAtsushi Murai case ST_OPENED: 6796d666775SBrian Somers (*fp->fn->LayerDown)(fp); 680455aabc3SBrian Somers FsmSendConfigReq(fp); 681455aabc3SBrian Somers NewState(fp, ST_REQSENT); 6826d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 683455aabc3SBrian Somers break; 684af57ed9fSAtsushi Murai case ST_ACKRCVD: 685af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 686af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 687af57ed9fSAtsushi Murai break; 688af57ed9fSAtsushi Murai } 689af57ed9fSAtsushi Murai 690dd7e2610SBrian Somers mbuf_Free(bp); 691af57ed9fSAtsushi Murai } 692af57ed9fSAtsushi Murai 69375240ed1SBrian Somers static void 694944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 695944f7098SBrian Somers /* RTR */ 696af57ed9fSAtsushi Murai { 697af57ed9fSAtsushi Murai switch (fp->state) { 698af57ed9fSAtsushi Murai case ST_INITIAL: 699af57ed9fSAtsushi Murai case ST_STARTING: 700dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 701d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 702af57ed9fSAtsushi Murai break; 703af57ed9fSAtsushi Murai case ST_CLOSED: 704af57ed9fSAtsushi Murai case ST_STOPPED: 705af57ed9fSAtsushi Murai case ST_CLOSING: 706af57ed9fSAtsushi Murai case ST_STOPPING: 707af57ed9fSAtsushi Murai case ST_REQSENT: 7082267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 709af57ed9fSAtsushi Murai break; 710af57ed9fSAtsushi Murai case ST_ACKRCVD: 711af57ed9fSAtsushi Murai case ST_ACKSENT: 7122267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 713af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 714af57ed9fSAtsushi Murai break; 715af57ed9fSAtsushi Murai case ST_OPENED: 7166d666775SBrian Somers (*fp->fn->LayerDown)(fp); 7172267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 718479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 719dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 7208f2fa0eeSBrian Somers fp->restart = 0; 7218f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 7226d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 723479508cfSBrian Somers /* A delayed ST_STOPPED is now scheduled */ 724af57ed9fSAtsushi Murai break; 725af57ed9fSAtsushi Murai } 726dd7e2610SBrian Somers mbuf_Free(bp); 727af57ed9fSAtsushi Murai } 728af57ed9fSAtsushi Murai 72975240ed1SBrian Somers static void 730944f7098SBrian Somers FsmRecvTermAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 731944f7098SBrian Somers /* RTA */ 732af57ed9fSAtsushi Murai { 733af57ed9fSAtsushi Murai switch (fp->state) { 734af57ed9fSAtsushi Murai case ST_CLOSING: 7356d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 736af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 7376d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 738af57ed9fSAtsushi Murai break; 739af57ed9fSAtsushi Murai case ST_STOPPING: 7406d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 741af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 7426d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 743af57ed9fSAtsushi Murai break; 744af57ed9fSAtsushi Murai case ST_ACKRCVD: 745af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 746af57ed9fSAtsushi Murai break; 747af57ed9fSAtsushi Murai case ST_OPENED: 7486d666775SBrian Somers (*fp->fn->LayerDown)(fp); 749af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 750af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 7516d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 752af57ed9fSAtsushi Murai break; 753af57ed9fSAtsushi Murai } 754dd7e2610SBrian Somers mbuf_Free(bp); 755af57ed9fSAtsushi Murai } 756af57ed9fSAtsushi Murai 75775240ed1SBrian Somers static void 758944f7098SBrian Somers FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 759944f7098SBrian Somers /* RCJ */ 760af57ed9fSAtsushi Murai { 76130c2f2ffSBrian Somers struct fsm_decode dec; 76253c9f6c0SAtsushi Murai int plen, flen; 763af57ed9fSAtsushi Murai 764dd7e2610SBrian Somers plen = mbuf_Length(bp); 76570ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 76653c9f6c0SAtsushi Murai if (plen < flen) { 767dd7e2610SBrian Somers mbuf_Free(bp); 768af57ed9fSAtsushi Murai return; 769af57ed9fSAtsushi Murai } 770af57ed9fSAtsushi Murai 771af57ed9fSAtsushi Murai /* 772af57ed9fSAtsushi Murai * Check and process easy case 773af57ed9fSAtsushi Murai */ 774af57ed9fSAtsushi Murai switch (fp->state) { 775af57ed9fSAtsushi Murai case ST_INITIAL: 776af57ed9fSAtsushi Murai case ST_STARTING: 777dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 778d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 779dd7e2610SBrian Somers mbuf_Free(bp); 780af57ed9fSAtsushi Murai return; 781af57ed9fSAtsushi Murai case ST_CLOSED: 782af57ed9fSAtsushi Murai case ST_STOPPED: 7832267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 784dd7e2610SBrian Somers mbuf_Free(bp); 785af57ed9fSAtsushi Murai return; 786af57ed9fSAtsushi Murai case ST_CLOSING: 787af57ed9fSAtsushi Murai case ST_STOPPING: 788dd7e2610SBrian Somers mbuf_Free(bp); 789af57ed9fSAtsushi Murai return; 790af57ed9fSAtsushi Murai } 791af57ed9fSAtsushi Murai 7923377c28cSBrian Somers bp = mbuf_Contiguous(bp); 79330c2f2ffSBrian Somers dec.ackend = dec.ack; 79430c2f2ffSBrian Somers dec.nakend = dec.nak; 79530c2f2ffSBrian Somers dec.rejend = dec.rej; 79630c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); 7972267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 798dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 799af57ed9fSAtsushi Murai 800af57ed9fSAtsushi Murai switch (fp->state) { 801af57ed9fSAtsushi Murai case ST_REQSENT: 802af57ed9fSAtsushi Murai case ST_ACKSENT: 803479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 804af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 805af57ed9fSAtsushi Murai break; 806af57ed9fSAtsushi Murai case ST_OPENED: 8076d666775SBrian Somers (*fp->fn->LayerDown)(fp); 808455aabc3SBrian Somers FsmSendConfigReq(fp); 809455aabc3SBrian Somers NewState(fp, ST_REQSENT); 8106d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 811455aabc3SBrian Somers break; 812af57ed9fSAtsushi Murai case ST_ACKRCVD: 813af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 814af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 815af57ed9fSAtsushi Murai break; 816af57ed9fSAtsushi Murai } 817dd7e2610SBrian Somers mbuf_Free(bp); 818af57ed9fSAtsushi Murai } 819af57ed9fSAtsushi Murai 82075240ed1SBrian Somers static void 821944f7098SBrian Somers FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 822af57ed9fSAtsushi Murai { 823dd7e2610SBrian Somers mbuf_Free(bp); 824af57ed9fSAtsushi Murai } 825af57ed9fSAtsushi Murai 82675240ed1SBrian Somers static void 827944f7098SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 828af57ed9fSAtsushi Murai { 8298c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 8303377c28cSBrian Somers u_short proto; 831af57ed9fSAtsushi Murai 8323377c28cSBrian Somers if (mbuf_Length(bp) < 2) { 8333377c28cSBrian Somers mbuf_Free(bp); 8343377c28cSBrian Somers return; 8353377c28cSBrian Somers } 8363377c28cSBrian Somers bp = mbuf_Read(bp, &proto, 2); 8373377c28cSBrian Somers proto = ntohs(proto); 838dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 839d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 840af57ed9fSAtsushi Murai 841af57ed9fSAtsushi Murai switch (proto) { 842af57ed9fSAtsushi Murai case PROTO_LQR: 8438c07a7b2SBrian Somers if (p) 844dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 8458c07a7b2SBrian Somers else 846dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 847d47dceb8SBrian Somers fp->link->name); 848af57ed9fSAtsushi Murai break; 849af57ed9fSAtsushi Murai case PROTO_CCP: 850dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 8513b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 8528a8d9927SBrian Somers /* Despite the RFC (1661), don't do an out-of-place TLF */ 8538a8d9927SBrian Somers /* (*fp->fn->LayerFinish)(fp); */ 854af57ed9fSAtsushi Murai switch (fp->state) { 855af57ed9fSAtsushi Murai case ST_CLOSED: 856af57ed9fSAtsushi Murai case ST_CLOSING: 857af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 858af57ed9fSAtsushi Murai default: 859af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 860af57ed9fSAtsushi Murai break; 861af57ed9fSAtsushi Murai } 8628a8d9927SBrian Somers /* See above */ 8638a8d9927SBrian Somers /* (*fp->parent->LayerFinish)(fp->parent->object, fp); */ 864dc0fdb6bSBrian Somers } 8651ae349f5Scvs2svn break; 8668a59beb7SBrian Somers case PROTO_IPCP: 8678a59beb7SBrian Somers if (fp->proto == PROTO_LCP) { 8688a59beb7SBrian Somers log_Printf(LogPHASE, "%s: IPCP protocol reject closes IPCP !\n", 8698a59beb7SBrian Somers fp->link->name); 8708a59beb7SBrian Somers fsm_Close(&fp->bundle->ncp.ipcp.fsm); 8718a59beb7SBrian Somers } 8728a59beb7SBrian Somers break; 873673903ecSBrian Somers case PROTO_MP: 874673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 875673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 876673903ecSBrian Somers 877673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 878dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 879d47dceb8SBrian Somers fp->link->name); 880dd7e2610SBrian Somers fsm_Close(fp); 881673903ecSBrian Somers } 882673903ecSBrian Somers } 883af57ed9fSAtsushi Murai break; 884af57ed9fSAtsushi Murai } 885dd7e2610SBrian Somers mbuf_Free(bp); 886af57ed9fSAtsushi Murai } 887af57ed9fSAtsushi Murai 88875240ed1SBrian Somers static void 889944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 890af57ed9fSAtsushi Murai { 891dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 892af57ed9fSAtsushi Murai u_char *cp; 893fe3125a0SBrian Somers u_int32_t magic; 894af57ed9fSAtsushi Murai 895411675baSBrian Somers mbuf_SetType(bp, MB_ECHOIN); 8963377c28cSBrian Somers if (lcp && mbuf_Length(bp) >= 4) { 897af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 8989e8ec64bSBrian Somers ua_ntohl(cp, &magic); 899dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 900dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: Error: His magic is bad!!\n", 901d47dceb8SBrian Somers fp->link->name); 902af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 903af57ed9fSAtsushi Murai } 904af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 9059e8ec64bSBrian Somers ua_htonl(&lcp->want_magic, cp); /* local magic */ 906411675baSBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, mbuf_Length(bp), MB_ECHOOUT); 907af57ed9fSAtsushi Murai } 908dc0fdb6bSBrian Somers } 909dd7e2610SBrian Somers mbuf_Free(bp); 910af57ed9fSAtsushi Murai } 911af57ed9fSAtsushi Murai 91275240ed1SBrian Somers static void 913944f7098SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 914af57ed9fSAtsushi Murai { 9156471628dSBrian Somers if (fsm2lcp(fp)) 9163377c28cSBrian Somers bp = lqr_RecvEcho(fp, bp); 9176471628dSBrian Somers 918dd7e2610SBrian Somers mbuf_Free(bp); 919af57ed9fSAtsushi Murai } 920af57ed9fSAtsushi Murai 92175240ed1SBrian Somers static void 922944f7098SBrian Somers FsmRecvDiscReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 923af57ed9fSAtsushi Murai { 924dd7e2610SBrian Somers mbuf_Free(bp); 925af57ed9fSAtsushi Murai } 926af57ed9fSAtsushi Murai 92775240ed1SBrian Somers static void 928944f7098SBrian Somers FsmRecvIdent(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 929af57ed9fSAtsushi Murai { 930dd7e2610SBrian Somers mbuf_Free(bp); 931af57ed9fSAtsushi Murai } 932af57ed9fSAtsushi Murai 93375240ed1SBrian Somers static void 934944f7098SBrian Somers FsmRecvTimeRemain(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 935af57ed9fSAtsushi Murai { 936dd7e2610SBrian Somers mbuf_Free(bp); 937af57ed9fSAtsushi Murai } 938af57ed9fSAtsushi Murai 93975240ed1SBrian Somers static void 940944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 941af57ed9fSAtsushi Murai { 942503a7782SBrian Somers (*fp->fn->RecvResetReq)(fp); 94398baf7c8SBrian Somers /* 94498baf7c8SBrian Somers * All sendable compressed packets are queued in the PRI_NORMAL modem 94598baf7c8SBrian Somers * output queue.... dump 'em to the priority queue so that they arrive 94698baf7c8SBrian Somers * at the peer before our ResetAck. 94798baf7c8SBrian Somers */ 9488c07a7b2SBrian Somers link_SequenceQueue(fp->link); 949411675baSBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0, MB_CCPOUT); 950dd7e2610SBrian Somers mbuf_Free(bp); 951af57ed9fSAtsushi Murai } 952af57ed9fSAtsushi Murai 95375240ed1SBrian Somers static void 954944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 955af57ed9fSAtsushi Murai { 956503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 957dd7e2610SBrian Somers mbuf_Free(bp); 958af57ed9fSAtsushi Murai } 959af57ed9fSAtsushi Murai 960af57ed9fSAtsushi Murai void 961dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 962af57ed9fSAtsushi Murai { 963af57ed9fSAtsushi Murai int len; 9645d9e6103SBrian Somers struct fsmheader lh; 9650053cc58SBrian Somers const struct fsmcodedesc *codep; 966af57ed9fSAtsushi Murai 967dd7e2610SBrian Somers len = mbuf_Length(bp); 968af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 969dd7e2610SBrian Somers mbuf_Free(bp); 970af57ed9fSAtsushi Murai return; 971af57ed9fSAtsushi Murai } 9725d9e6103SBrian Somers bp = mbuf_Read(bp, &lh, sizeof lh); 9735d9e6103SBrian Somers if (lh.code < fp->min_code || lh.code > fp->max_code || 9745d9e6103SBrian Somers lh.code > sizeof FsmCodes / sizeof *FsmCodes) { 9753b0f8d2eSBrian Somers /* 9763b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 9773b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 9783b0f8d2eSBrian Somers */ 9793b0f8d2eSBrian Somers static u_char id; 980d93d3a9cSBrian Somers 9815d9e6103SBrian Somers bp = mbuf_Prepend(bp, &lh, sizeof lh, 0); 9825d9e6103SBrian Somers bp = mbuf_Contiguous(bp); 983411675baSBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->cnt, MB_UNKNOWN); 984dd7e2610SBrian Somers mbuf_Free(bp); 985af57ed9fSAtsushi Murai return; 986af57ed9fSAtsushi Murai } 987af57ed9fSAtsushi Murai 9885d9e6103SBrian Somers codep = FsmCodes + lh.code - 1; 9895d9e6103SBrian Somers if (lh.id != fp->reqid && codep->check_reqid && 9901342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 991dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 9925d9e6103SBrian Somers fp->link->name, codep->name, lh.id, fp->reqid); 9932267893fSBrian Somers return; 9942267893fSBrian Somers } 9952267893fSBrian Somers 996dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 9975d9e6103SBrian Somers fp->link->name, codep->name, lh.id, State2Nam(fp->state)); 9982267893fSBrian Somers 9995d9e6103SBrian Somers if (codep->inc_reqid && (lh.id == fp->reqid || 10001342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 10012267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 10022267893fSBrian Somers 10035d9e6103SBrian Somers (*codep->recv)(fp, &lh, bp); 10041ae349f5Scvs2svn } 1005503a7782SBrian Somers 1006503a7782SBrian Somers void 1007dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 1008503a7782SBrian Somers { 1009dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 1010d47dceb8SBrian Somers fp->link->name); 1011503a7782SBrian Somers } 1012503a7782SBrian Somers 1013503a7782SBrian Somers void 1014dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 1015503a7782SBrian Somers { 1016dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 1017d47dceb8SBrian Somers fp->link->name); 1018af57ed9fSAtsushi Murai } 101909206a6fSBrian Somers 102009206a6fSBrian Somers void 1021897f9429SBrian Somers fsm_Reopen(struct fsm *fp) 1022897f9429SBrian Somers { 1023897f9429SBrian Somers if (fp->state == ST_OPENED) { 1024897f9429SBrian Somers (*fp->fn->LayerDown)(fp); 1025479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 1026897f9429SBrian Somers FsmSendConfigReq(fp); 1027897f9429SBrian Somers NewState(fp, ST_REQSENT); 1028897f9429SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 1029897f9429SBrian Somers } 1030897f9429SBrian Somers } 1031897f9429SBrian Somers 1032897f9429SBrian Somers void 103309206a6fSBrian Somers fsm2initial(struct fsm *fp) 103409206a6fSBrian Somers { 1035479508cfSBrian Somers timer_Stop(&fp->FsmTimer); 1036479508cfSBrian Somers timer_Stop(&fp->OpenTimer); 1037479508cfSBrian Somers timer_Stop(&fp->StoppedTimer); 103809206a6fSBrian Somers if (fp->state == ST_STOPPED) 103909206a6fSBrian Somers fsm_Close(fp); 104009206a6fSBrian Somers if (fp->state > ST_INITIAL) 104109206a6fSBrian Somers fsm_Down(fp); 104209206a6fSBrian Somers if (fp->state > ST_INITIAL) 104309206a6fSBrian Somers fsm_Close(fp); 104409206a6fSBrian Somers } 1045