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 * 2097d92980SPeter Wemm * $FreeBSD$ 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); 20426af0ae9SBrian Somers bp = m_get(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); 209442f8495SBrian Somers link_PushPacket(fp->link, bp, fp->bundle, LINK_QUEUES(fp->link) - 1, 210442f8495SBrian Somers fp->proto); 211af57ed9fSAtsushi Murai } 212af57ed9fSAtsushi Murai 21349b239e0SBrian Somers static void 21449b239e0SBrian Somers FsmOpenNow(void *v) 21549b239e0SBrian Somers { 21649b239e0SBrian Somers struct fsm *fp = (struct fsm *)v; 21749b239e0SBrian Somers 218dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 21949b239e0SBrian Somers if (fp->state <= ST_STOPPED) { 2203a2e4f62SBrian Somers if (fp->state != ST_STARTING) { 2213a2e4f62SBrian Somers /* 2223a2e4f62SBrian Somers * In practice, we're only here in ST_STOPPED (when delaying the 2233a2e4f62SBrian Somers * first config request) or ST_CLOSED (when openmode == 0). 2243a2e4f62SBrian Somers * 2253a2e4f62SBrian Somers * The ST_STOPPED bit is breaking the RFC already :-( 2263a2e4f62SBrian Somers * 2273a2e4f62SBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 2283a2e4f62SBrian Somers * required for an Open event when state == Closed, but the RFC 2293a2e4f62SBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 2303a2e4f62SBrian Somers * ie, Initial gets an `Up' event, Closing gets a RTA etc. 2313a2e4f62SBrian Somers */ 2323a2e4f62SBrian Somers (*fp->fn->LayerStart)(fp); 2333a2e4f62SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 2343a2e4f62SBrian Somers } 235479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 23649b239e0SBrian Somers FsmSendConfigReq(fp); 23749b239e0SBrian Somers NewState(fp, ST_REQSENT); 23849b239e0SBrian Somers } 23949b239e0SBrian Somers } 24049b239e0SBrian Somers 241af57ed9fSAtsushi Murai void 242dd7e2610SBrian Somers fsm_Open(struct fsm *fp) 243af57ed9fSAtsushi Murai { 244af57ed9fSAtsushi Murai switch (fp->state) { 245af57ed9fSAtsushi Murai case ST_INITIAL: 246af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 2476d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2486d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 249af57ed9fSAtsushi Murai break; 250af57ed9fSAtsushi Murai case ST_CLOSED: 251af57ed9fSAtsushi Murai if (fp->open_mode == OPEN_PASSIVE) { 2523a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 25349b239e0SBrian Somers } else if (fp->open_mode > 0) { 25449b239e0SBrian Somers if (fp->open_mode > 1) 255dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 256d47dceb8SBrian Somers fp->link->name, fp->open_mode); 2573a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 258dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 25949b239e0SBrian Somers fp->OpenTimer.load = fp->open_mode * SECTICKS; 26049b239e0SBrian Somers fp->OpenTimer.func = FsmOpenNow; 26149b239e0SBrian Somers fp->OpenTimer.arg = (void *)fp; 262dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 26349b239e0SBrian Somers } else 26449b239e0SBrian Somers FsmOpenNow(fp); 265af57ed9fSAtsushi Murai break; 266af57ed9fSAtsushi Murai case ST_STOPPED: /* XXX: restart option */ 267af57ed9fSAtsushi Murai case ST_REQSENT: 268af57ed9fSAtsushi Murai case ST_ACKRCVD: 269af57ed9fSAtsushi Murai case ST_ACKSENT: 270af57ed9fSAtsushi Murai case ST_OPENED: /* XXX: restart option */ 271af57ed9fSAtsushi Murai break; 272af57ed9fSAtsushi Murai case ST_CLOSING: /* XXX: restart option */ 273af57ed9fSAtsushi Murai case ST_STOPPING: /* XXX: restart option */ 274af57ed9fSAtsushi Murai NewState(fp, ST_STOPPING); 275af57ed9fSAtsushi Murai break; 276af57ed9fSAtsushi Murai } 277af57ed9fSAtsushi Murai } 278af57ed9fSAtsushi Murai 279af57ed9fSAtsushi Murai void 280dd7e2610SBrian Somers fsm_Up(struct fsm *fp) 281af57ed9fSAtsushi Murai { 282af57ed9fSAtsushi Murai switch (fp->state) { 283af57ed9fSAtsushi Murai case ST_INITIAL: 284dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 2851fa665f5SBrian Somers fp->link->name); 286af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 287af57ed9fSAtsushi Murai break; 288af57ed9fSAtsushi Murai case ST_STARTING: 289479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 290af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 291af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 292af57ed9fSAtsushi Murai break; 293af57ed9fSAtsushi Murai default: 294dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 295d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 296af57ed9fSAtsushi Murai break; 297af57ed9fSAtsushi Murai } 298af57ed9fSAtsushi Murai } 299af57ed9fSAtsushi Murai 300af57ed9fSAtsushi Murai void 301dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 302af57ed9fSAtsushi Murai { 303af57ed9fSAtsushi Murai switch (fp->state) { 304af57ed9fSAtsushi Murai case ST_CLOSED: 305af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 306af57ed9fSAtsushi Murai break; 307455aabc3SBrian Somers case ST_CLOSING: 3088a8d9927SBrian Somers /* This TLF contradicts the RFC (1661), which ``misses it out'' ! */ 3096d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 310455aabc3SBrian Somers NewState(fp, ST_INITIAL); 3116d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 312455aabc3SBrian Somers break; 313af57ed9fSAtsushi Murai case ST_STOPPED: 314455aabc3SBrian Somers NewState(fp, ST_STARTING); 3156d666775SBrian Somers (*fp->fn->LayerStart)(fp); 3166d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 317455aabc3SBrian Somers break; 318af57ed9fSAtsushi Murai case ST_STOPPING: 319af57ed9fSAtsushi Murai case ST_REQSENT: 320af57ed9fSAtsushi Murai case ST_ACKRCVD: 321af57ed9fSAtsushi Murai case ST_ACKSENT: 322af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 323af57ed9fSAtsushi Murai break; 324af57ed9fSAtsushi Murai case ST_OPENED: 3256d666775SBrian Somers (*fp->fn->LayerDown)(fp); 326af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 3276d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 328af57ed9fSAtsushi Murai break; 329af57ed9fSAtsushi Murai } 330af57ed9fSAtsushi Murai } 331af57ed9fSAtsushi Murai 332af57ed9fSAtsushi Murai void 333dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 334af57ed9fSAtsushi Murai { 335af57ed9fSAtsushi Murai switch (fp->state) { 336af57ed9fSAtsushi Murai case ST_STARTING: 3376d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 338af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 3396d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 340af57ed9fSAtsushi Murai break; 341af57ed9fSAtsushi Murai case ST_STOPPED: 342af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 343af57ed9fSAtsushi Murai break; 344af57ed9fSAtsushi Murai case ST_STOPPING: 345af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 346af57ed9fSAtsushi Murai break; 347af57ed9fSAtsushi Murai case ST_OPENED: 3486d666775SBrian Somers (*fp->fn->LayerDown)(fp); 349479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 350455aabc3SBrian Somers FsmSendTerminateReq(fp); 351455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3526d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 353455aabc3SBrian Somers break; 354af57ed9fSAtsushi Murai case ST_REQSENT: 355af57ed9fSAtsushi Murai case ST_ACKRCVD: 356af57ed9fSAtsushi Murai case ST_ACKSENT: 357479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 358af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 359af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 360af57ed9fSAtsushi Murai break; 361af57ed9fSAtsushi Murai } 362af57ed9fSAtsushi Murai } 363af57ed9fSAtsushi Murai 364af57ed9fSAtsushi Murai /* 365af57ed9fSAtsushi Murai * Send functions 366af57ed9fSAtsushi Murai */ 36775240ed1SBrian Somers static void 368944f7098SBrian Somers FsmSendConfigReq(struct fsm *fp) 369af57ed9fSAtsushi Murai { 370479508cfSBrian Somers if (fp->more.reqs-- > 0 && fp->restart-- > 0) { 37183d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 372dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 373af57ed9fSAtsushi Murai } else { 374479508cfSBrian Somers if (fp->more.reqs < 0) 375479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REQs sent - abandoning " 376479508cfSBrian Somers "negotiation\n", fp->link->name, fp->name); 377dd7e2610SBrian Somers fsm_Close(fp); 378af57ed9fSAtsushi Murai } 379af57ed9fSAtsushi Murai } 380af57ed9fSAtsushi Murai 38175240ed1SBrian Somers static void 382944f7098SBrian Somers FsmSendTerminateReq(struct fsm *fp) 383af57ed9fSAtsushi Murai { 384411675baSBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0, MB_UNKNOWN); 3852267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 386dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 387af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 388af57ed9fSAtsushi Murai } 389af57ed9fSAtsushi Murai 390af57ed9fSAtsushi Murai /* 391af57ed9fSAtsushi Murai * Timeout actions 392af57ed9fSAtsushi Murai */ 39375240ed1SBrian Somers static void 394b6e82f33SBrian Somers FsmTimeout(void *v) 395af57ed9fSAtsushi Murai { 396b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 397b6e82f33SBrian Somers 398af57ed9fSAtsushi Murai if (fp->restart) { 399af57ed9fSAtsushi Murai switch (fp->state) { 400af57ed9fSAtsushi Murai case ST_CLOSING: 401af57ed9fSAtsushi Murai case ST_STOPPING: 402af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 403af57ed9fSAtsushi Murai break; 404af57ed9fSAtsushi Murai case ST_REQSENT: 405af57ed9fSAtsushi Murai case ST_ACKSENT: 406af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 407af57ed9fSAtsushi Murai break; 408af57ed9fSAtsushi Murai case ST_ACKRCVD: 409af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 410af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 411af57ed9fSAtsushi Murai break; 412af57ed9fSAtsushi Murai } 413dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 414af57ed9fSAtsushi Murai } else { 415af57ed9fSAtsushi Murai switch (fp->state) { 416af57ed9fSAtsushi Murai case ST_CLOSING: 4176d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 418af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 4196d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 420af57ed9fSAtsushi Murai break; 421af57ed9fSAtsushi Murai case ST_STOPPING: 4226d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 423af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4246d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 425af57ed9fSAtsushi Murai break; 426af57ed9fSAtsushi Murai case ST_REQSENT: /* XXX: 3p */ 427af57ed9fSAtsushi Murai case ST_ACKSENT: 428af57ed9fSAtsushi Murai case ST_ACKRCVD: 4296d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 430af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4316d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 432af57ed9fSAtsushi Murai break; 433af57ed9fSAtsushi Murai } 434af57ed9fSAtsushi Murai } 435af57ed9fSAtsushi Murai } 436af57ed9fSAtsushi Murai 43775240ed1SBrian Somers static void 438479508cfSBrian Somers FsmInitRestartCounter(struct fsm *fp, int what) 439af57ed9fSAtsushi Murai { 440dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 441af57ed9fSAtsushi Murai fp->FsmTimer.func = FsmTimeout; 442af57ed9fSAtsushi Murai fp->FsmTimer.arg = (void *)fp; 443479508cfSBrian Somers (*fp->fn->InitRestartCounter)(fp, what); 444af57ed9fSAtsushi Murai } 445af57ed9fSAtsushi Murai 446af57ed9fSAtsushi Murai /* 447af57ed9fSAtsushi Murai * Actions when receive packets 448af57ed9fSAtsushi Murai */ 44975240ed1SBrian Somers static void 450944f7098SBrian Somers FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 451944f7098SBrian Somers /* RCR */ 452af57ed9fSAtsushi Murai { 45330c2f2ffSBrian Somers struct fsm_decode dec; 45453c9f6c0SAtsushi Murai int plen, flen; 455af57ed9fSAtsushi Murai int ackaction = 0; 456af57ed9fSAtsushi Murai 45726af0ae9SBrian Somers plen = m_length(bp); 45870ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 45953c9f6c0SAtsushi Murai if (plen < flen) { 460a33b2ef7SBrian Somers log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 461d47dceb8SBrian Somers fp->link->name, plen, flen); 46226af0ae9SBrian Somers m_freem(bp); 463af57ed9fSAtsushi Murai return; 464af57ed9fSAtsushi Murai } 465af57ed9fSAtsushi Murai 4663377c28cSBrian Somers /* Check and process easy case */ 467af57ed9fSAtsushi Murai switch (fp->state) { 468af57ed9fSAtsushi Murai case ST_INITIAL: 46906337856SBrian Somers if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 47006337856SBrian Somers /* 47106337856SBrian Somers * ccp_SetOpenMode() leaves us in initial if we're disabling 4725d9e6103SBrian Somers * & denying everything. 47306337856SBrian Somers */ 47426af0ae9SBrian Somers bp = m_prepend(bp, lhp, sizeof *lhp, 2); 4755d9e6103SBrian Somers bp = proto_Prepend(bp, fp->proto, 0, 0); 47626af0ae9SBrian Somers bp = m_pullup(bp); 47726af0ae9SBrian Somers lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->m_len); 47826af0ae9SBrian Somers m_freem(bp); 47906337856SBrian Somers return; 48006337856SBrian Somers } 48106337856SBrian Somers /* Drop through */ 482af57ed9fSAtsushi Murai case ST_STARTING: 483dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 484d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 48526af0ae9SBrian Somers m_freem(bp); 486af57ed9fSAtsushi Murai return; 487af57ed9fSAtsushi Murai case ST_CLOSED: 4882267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 48926af0ae9SBrian Somers m_freem(bp); 490af57ed9fSAtsushi Murai return; 491af57ed9fSAtsushi Murai case ST_CLOSING: 492dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 493d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 494a9c503afSBrian Somers case ST_STOPPING: 49526af0ae9SBrian Somers m_freem(bp); 496af57ed9fSAtsushi Murai return; 49768a0e171SBrian Somers case ST_OPENED: 49868a0e171SBrian Somers (*fp->fn->LayerDown)(fp); 49968a0e171SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 50068a0e171SBrian Somers break; 501af57ed9fSAtsushi Murai } 502af57ed9fSAtsushi Murai 50326af0ae9SBrian Somers bp = m_pullup(bp); 50430c2f2ffSBrian Somers dec.ackend = dec.ack; 50530c2f2ffSBrian Somers dec.nakend = dec.nak; 50630c2f2ffSBrian Somers dec.rejend = dec.rej; 50730c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec); 5082267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 509dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 510af57ed9fSAtsushi Murai 51130c2f2ffSBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 512af57ed9fSAtsushi Murai ackaction = 1; 513af57ed9fSAtsushi Murai 514af57ed9fSAtsushi Murai switch (fp->state) { 515af57ed9fSAtsushi Murai case ST_STOPPED: 516479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 51768a0e171SBrian Somers /* Fall through */ 51868a0e171SBrian Somers 51968a0e171SBrian Somers case ST_OPENED: 520af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 521af57ed9fSAtsushi Murai break; 522af57ed9fSAtsushi Murai } 523af57ed9fSAtsushi Murai 52430c2f2ffSBrian Somers if (dec.rejend != dec.rej) 525411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej, 526411675baSBrian Somers MB_UNKNOWN); 52730c2f2ffSBrian Somers if (dec.nakend != dec.nak) 528411675baSBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak, 529411675baSBrian Somers MB_UNKNOWN); 530af57ed9fSAtsushi Murai if (ackaction) 531411675baSBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack, 532411675baSBrian Somers MB_UNKNOWN); 533af57ed9fSAtsushi Murai 534af57ed9fSAtsushi Murai switch (fp->state) { 535455aabc3SBrian Somers case ST_STOPPED: 536479508cfSBrian Somers /* 537479508cfSBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 538479508cfSBrian Somers * required for a RCR when state == ST_STOPPED, but the RFC 539479508cfSBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 540479508cfSBrian Somers */ 541479508cfSBrian Somers (*fp->fn->LayerStart)(fp); 542479508cfSBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 543479508cfSBrian Somers /* Fall through */ 544479508cfSBrian Somers 545479508cfSBrian Somers case ST_OPENED: 546af57ed9fSAtsushi Murai if (ackaction) 547af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 548af57ed9fSAtsushi Murai else 549af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 550af57ed9fSAtsushi Murai break; 551af57ed9fSAtsushi Murai case ST_REQSENT: 552af57ed9fSAtsushi Murai if (ackaction) 553af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 554af57ed9fSAtsushi Murai break; 555af57ed9fSAtsushi Murai case ST_ACKRCVD: 556af57ed9fSAtsushi Murai if (ackaction) { 557af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5586f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5596d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5606f384573SBrian Somers else { 5616f384573SBrian Somers (*fp->fn->LayerDown)(fp); 562479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 5636f384573SBrian Somers FsmSendTerminateReq(fp); 5646f384573SBrian Somers NewState(fp, ST_CLOSING); 5656f384573SBrian Somers } 566af57ed9fSAtsushi Murai } 567af57ed9fSAtsushi Murai break; 568af57ed9fSAtsushi Murai case ST_ACKSENT: 569af57ed9fSAtsushi Murai if (!ackaction) 570af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 571af57ed9fSAtsushi Murai break; 572af57ed9fSAtsushi Murai } 57326af0ae9SBrian Somers m_freem(bp); 574479508cfSBrian Somers 575479508cfSBrian Somers if (dec.rejend != dec.rej && --fp->more.rejs <= 0) { 576479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REJs sent - abandoning negotiation\n", 577479508cfSBrian Somers fp->link->name, fp->name); 578479508cfSBrian Somers fsm_Close(fp); 579479508cfSBrian Somers } 580479508cfSBrian Somers 581479508cfSBrian Somers if (dec.nakend != dec.nak && --fp->more.naks <= 0) { 582479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s NAKs sent - abandoning negotiation\n", 583479508cfSBrian Somers fp->link->name, fp->name); 584479508cfSBrian Somers fsm_Close(fp); 585479508cfSBrian Somers } 586af57ed9fSAtsushi Murai } 587af57ed9fSAtsushi Murai 58875240ed1SBrian Somers static void 589944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 590944f7098SBrian Somers /* RCA */ 591af57ed9fSAtsushi Murai { 592af57ed9fSAtsushi Murai switch (fp->state) { 593af57ed9fSAtsushi Murai case ST_CLOSED: 594af57ed9fSAtsushi Murai case ST_STOPPED: 5952267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 596af57ed9fSAtsushi Murai break; 597af57ed9fSAtsushi Murai case ST_CLOSING: 598af57ed9fSAtsushi Murai case ST_STOPPING: 599af57ed9fSAtsushi Murai break; 600af57ed9fSAtsushi Murai case ST_REQSENT: 601479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 602af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 603af57ed9fSAtsushi Murai break; 604af57ed9fSAtsushi Murai case ST_ACKRCVD: 605af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 606af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 607af57ed9fSAtsushi Murai break; 608af57ed9fSAtsushi Murai case ST_ACKSENT: 609479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 610af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 6116f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 6126d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 6136f384573SBrian Somers else { 6146f384573SBrian Somers (*fp->fn->LayerDown)(fp); 615479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 6166f384573SBrian Somers FsmSendTerminateReq(fp); 6176f384573SBrian Somers NewState(fp, ST_CLOSING); 6186f384573SBrian Somers } 619af57ed9fSAtsushi Murai break; 620af57ed9fSAtsushi Murai case ST_OPENED: 6216d666775SBrian Somers (*fp->fn->LayerDown)(fp); 622af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 623af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 6246d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 625af57ed9fSAtsushi Murai break; 626af57ed9fSAtsushi Murai } 62726af0ae9SBrian Somers m_freem(bp); 628af57ed9fSAtsushi Murai } 629af57ed9fSAtsushi Murai 63075240ed1SBrian Somers static void 631944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 632944f7098SBrian Somers /* RCN */ 633af57ed9fSAtsushi Murai { 63430c2f2ffSBrian Somers struct fsm_decode dec; 63553c9f6c0SAtsushi Murai int plen, flen; 636af57ed9fSAtsushi Murai 63726af0ae9SBrian Somers plen = m_length(bp); 63870ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 63953c9f6c0SAtsushi Murai if (plen < flen) { 64026af0ae9SBrian Somers m_freem(bp); 641af57ed9fSAtsushi Murai return; 642af57ed9fSAtsushi Murai } 643af57ed9fSAtsushi Murai 644af57ed9fSAtsushi Murai /* 645af57ed9fSAtsushi Murai * Check and process easy case 646af57ed9fSAtsushi Murai */ 647af57ed9fSAtsushi Murai switch (fp->state) { 648af57ed9fSAtsushi Murai case ST_INITIAL: 649af57ed9fSAtsushi Murai case ST_STARTING: 650dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 651d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 65226af0ae9SBrian Somers m_freem(bp); 653af57ed9fSAtsushi Murai return; 654af57ed9fSAtsushi Murai case ST_CLOSED: 655af57ed9fSAtsushi Murai case ST_STOPPED: 6562267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 65726af0ae9SBrian Somers m_freem(bp); 658af57ed9fSAtsushi Murai return; 659af57ed9fSAtsushi Murai case ST_CLOSING: 660af57ed9fSAtsushi Murai case ST_STOPPING: 66126af0ae9SBrian Somers m_freem(bp); 662af57ed9fSAtsushi Murai return; 663af57ed9fSAtsushi Murai } 664af57ed9fSAtsushi Murai 66526af0ae9SBrian Somers bp = m_pullup(bp); 66630c2f2ffSBrian Somers dec.ackend = dec.ack; 66730c2f2ffSBrian Somers dec.nakend = dec.nak; 66830c2f2ffSBrian Somers dec.rejend = dec.rej; 66930c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); 6702267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 671dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 672af57ed9fSAtsushi Murai 673af57ed9fSAtsushi Murai switch (fp->state) { 674af57ed9fSAtsushi Murai case ST_REQSENT: 675af57ed9fSAtsushi Murai case ST_ACKSENT: 676479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 677af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 678af57ed9fSAtsushi Murai break; 679af57ed9fSAtsushi Murai case ST_OPENED: 6806d666775SBrian Somers (*fp->fn->LayerDown)(fp); 681455aabc3SBrian Somers FsmSendConfigReq(fp); 682455aabc3SBrian Somers NewState(fp, ST_REQSENT); 6836d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 684455aabc3SBrian Somers break; 685af57ed9fSAtsushi Murai case ST_ACKRCVD: 686af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 687af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 688af57ed9fSAtsushi Murai break; 689af57ed9fSAtsushi Murai } 690af57ed9fSAtsushi Murai 69126af0ae9SBrian Somers m_freem(bp); 692af57ed9fSAtsushi Murai } 693af57ed9fSAtsushi Murai 69475240ed1SBrian Somers static void 695944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 696944f7098SBrian Somers /* RTR */ 697af57ed9fSAtsushi Murai { 698af57ed9fSAtsushi Murai switch (fp->state) { 699af57ed9fSAtsushi Murai case ST_INITIAL: 700af57ed9fSAtsushi Murai case ST_STARTING: 701dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 702d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 703af57ed9fSAtsushi Murai break; 704af57ed9fSAtsushi Murai case ST_CLOSED: 705af57ed9fSAtsushi Murai case ST_STOPPED: 706af57ed9fSAtsushi Murai case ST_CLOSING: 707af57ed9fSAtsushi Murai case ST_STOPPING: 708af57ed9fSAtsushi Murai case ST_REQSENT: 7092267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 710af57ed9fSAtsushi Murai break; 711af57ed9fSAtsushi Murai case ST_ACKRCVD: 712af57ed9fSAtsushi Murai case ST_ACKSENT: 7132267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 714af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 715af57ed9fSAtsushi Murai break; 716af57ed9fSAtsushi Murai case ST_OPENED: 7176d666775SBrian Somers (*fp->fn->LayerDown)(fp); 7182267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 719479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 720dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 7218f2fa0eeSBrian Somers fp->restart = 0; 7228f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 7236d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 724479508cfSBrian Somers /* A delayed ST_STOPPED is now scheduled */ 725af57ed9fSAtsushi Murai break; 726af57ed9fSAtsushi Murai } 72726af0ae9SBrian Somers m_freem(bp); 728af57ed9fSAtsushi Murai } 729af57ed9fSAtsushi Murai 73075240ed1SBrian Somers static void 731944f7098SBrian Somers FsmRecvTermAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 732944f7098SBrian Somers /* RTA */ 733af57ed9fSAtsushi Murai { 734af57ed9fSAtsushi Murai switch (fp->state) { 735af57ed9fSAtsushi Murai case ST_CLOSING: 7366d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 737af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 7386d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 739af57ed9fSAtsushi Murai break; 740af57ed9fSAtsushi Murai case ST_STOPPING: 7416d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 742af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 7436d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 744af57ed9fSAtsushi Murai break; 745af57ed9fSAtsushi Murai case ST_ACKRCVD: 746af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 747af57ed9fSAtsushi Murai break; 748af57ed9fSAtsushi Murai case ST_OPENED: 7496d666775SBrian Somers (*fp->fn->LayerDown)(fp); 750af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 751af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 7526d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 753af57ed9fSAtsushi Murai break; 754af57ed9fSAtsushi Murai } 75526af0ae9SBrian Somers m_freem(bp); 756af57ed9fSAtsushi Murai } 757af57ed9fSAtsushi Murai 75875240ed1SBrian Somers static void 759944f7098SBrian Somers FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 760944f7098SBrian Somers /* RCJ */ 761af57ed9fSAtsushi Murai { 76230c2f2ffSBrian Somers struct fsm_decode dec; 76353c9f6c0SAtsushi Murai int plen, flen; 764af57ed9fSAtsushi Murai 76526af0ae9SBrian Somers plen = m_length(bp); 76670ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 76753c9f6c0SAtsushi Murai if (plen < flen) { 76826af0ae9SBrian Somers m_freem(bp); 769af57ed9fSAtsushi Murai return; 770af57ed9fSAtsushi Murai } 771af57ed9fSAtsushi Murai 772af57ed9fSAtsushi Murai /* 773af57ed9fSAtsushi Murai * Check and process easy case 774af57ed9fSAtsushi Murai */ 775af57ed9fSAtsushi Murai switch (fp->state) { 776af57ed9fSAtsushi Murai case ST_INITIAL: 777af57ed9fSAtsushi Murai case ST_STARTING: 778dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 779d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 78026af0ae9SBrian Somers m_freem(bp); 781af57ed9fSAtsushi Murai return; 782af57ed9fSAtsushi Murai case ST_CLOSED: 783af57ed9fSAtsushi Murai case ST_STOPPED: 7842267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 78526af0ae9SBrian Somers m_freem(bp); 786af57ed9fSAtsushi Murai return; 787af57ed9fSAtsushi Murai case ST_CLOSING: 788af57ed9fSAtsushi Murai case ST_STOPPING: 78926af0ae9SBrian Somers m_freem(bp); 790af57ed9fSAtsushi Murai return; 791af57ed9fSAtsushi Murai } 792af57ed9fSAtsushi Murai 79326af0ae9SBrian Somers bp = m_pullup(bp); 79430c2f2ffSBrian Somers dec.ackend = dec.ack; 79530c2f2ffSBrian Somers dec.nakend = dec.nak; 79630c2f2ffSBrian Somers dec.rejend = dec.rej; 79730c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); 7982267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 799dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 800af57ed9fSAtsushi Murai 801af57ed9fSAtsushi Murai switch (fp->state) { 802af57ed9fSAtsushi Murai case ST_REQSENT: 803af57ed9fSAtsushi Murai case ST_ACKSENT: 804479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 805af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 806af57ed9fSAtsushi Murai break; 807af57ed9fSAtsushi Murai case ST_OPENED: 8086d666775SBrian Somers (*fp->fn->LayerDown)(fp); 809455aabc3SBrian Somers FsmSendConfigReq(fp); 810455aabc3SBrian Somers NewState(fp, ST_REQSENT); 8116d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 812455aabc3SBrian Somers break; 813af57ed9fSAtsushi Murai case ST_ACKRCVD: 814af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 815af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 816af57ed9fSAtsushi Murai break; 817af57ed9fSAtsushi Murai } 81826af0ae9SBrian Somers m_freem(bp); 819af57ed9fSAtsushi Murai } 820af57ed9fSAtsushi Murai 82175240ed1SBrian Somers static void 822944f7098SBrian Somers FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 823af57ed9fSAtsushi Murai { 82426af0ae9SBrian Somers m_freem(bp); 825af57ed9fSAtsushi Murai } 826af57ed9fSAtsushi Murai 82775240ed1SBrian Somers static void 828944f7098SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 829af57ed9fSAtsushi Murai { 8308c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 8313377c28cSBrian Somers u_short proto; 832af57ed9fSAtsushi Murai 83326af0ae9SBrian Somers if (m_length(bp) < 2) { 83426af0ae9SBrian Somers m_freem(bp); 8353377c28cSBrian Somers return; 8363377c28cSBrian Somers } 8373377c28cSBrian Somers bp = mbuf_Read(bp, &proto, 2); 8383377c28cSBrian Somers proto = ntohs(proto); 839dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 840d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 841af57ed9fSAtsushi Murai 842af57ed9fSAtsushi Murai switch (proto) { 843af57ed9fSAtsushi Murai case PROTO_LQR: 8448c07a7b2SBrian Somers if (p) 845dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 8468c07a7b2SBrian Somers else 847dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 848d47dceb8SBrian Somers fp->link->name); 849af57ed9fSAtsushi Murai break; 850af57ed9fSAtsushi Murai case PROTO_CCP: 851dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 8523b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 8538a8d9927SBrian Somers /* Despite the RFC (1661), don't do an out-of-place TLF */ 8548a8d9927SBrian Somers /* (*fp->fn->LayerFinish)(fp); */ 855af57ed9fSAtsushi Murai switch (fp->state) { 856af57ed9fSAtsushi Murai case ST_CLOSED: 857af57ed9fSAtsushi Murai case ST_CLOSING: 858af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 859af57ed9fSAtsushi Murai default: 860af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 861af57ed9fSAtsushi Murai break; 862af57ed9fSAtsushi Murai } 8638a8d9927SBrian Somers /* See above */ 8648a8d9927SBrian Somers /* (*fp->parent->LayerFinish)(fp->parent->object, fp); */ 865dc0fdb6bSBrian Somers } 8661ae349f5Scvs2svn break; 8678a59beb7SBrian Somers case PROTO_IPCP: 8688a59beb7SBrian Somers if (fp->proto == PROTO_LCP) { 8698a59beb7SBrian Somers log_Printf(LogPHASE, "%s: IPCP protocol reject closes IPCP !\n", 8708a59beb7SBrian Somers fp->link->name); 8718a59beb7SBrian Somers fsm_Close(&fp->bundle->ncp.ipcp.fsm); 8728a59beb7SBrian Somers } 8738a59beb7SBrian Somers break; 874673903ecSBrian Somers case PROTO_MP: 875673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 876673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 877673903ecSBrian Somers 878673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 879dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 880d47dceb8SBrian Somers fp->link->name); 881dd7e2610SBrian Somers fsm_Close(fp); 882673903ecSBrian Somers } 883673903ecSBrian Somers } 884af57ed9fSAtsushi Murai break; 885af57ed9fSAtsushi Murai } 88626af0ae9SBrian Somers m_freem(bp); 887af57ed9fSAtsushi Murai } 888af57ed9fSAtsushi Murai 88975240ed1SBrian Somers static void 890944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 891af57ed9fSAtsushi Murai { 892dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 893af57ed9fSAtsushi Murai u_char *cp; 894fe3125a0SBrian Somers u_int32_t magic; 895af57ed9fSAtsushi Murai 89626af0ae9SBrian Somers bp = m_pullup(bp); 89726af0ae9SBrian Somers m_settype(bp, MB_ECHOIN); 89887c3786eSBrian Somers 89987c3786eSBrian Somers if (lcp && ntohs(lhp->length) - sizeof *lhp >= 4) { 900af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 9019e8ec64bSBrian Somers ua_ntohl(cp, &magic); 902dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 903990a543fSBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: magic 0x%08lx is wrong," 904990a543fSBrian Somers " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 905990a543fSBrian Somers (u_long)lcp->his_magic); 906af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 907af57ed9fSAtsushi Murai } 908af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 9099e8ec64bSBrian Somers ua_htonl(&lcp->want_magic, cp); /* local magic */ 91087c3786eSBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, 91187c3786eSBrian Somers ntohs(lhp->length) - sizeof *lhp, MB_ECHOOUT); 912af57ed9fSAtsushi Murai } 913dc0fdb6bSBrian Somers } 91426af0ae9SBrian Somers m_freem(bp); 915af57ed9fSAtsushi Murai } 916af57ed9fSAtsushi Murai 91775240ed1SBrian Somers static void 918944f7098SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 919af57ed9fSAtsushi Murai { 9206471628dSBrian Somers if (fsm2lcp(fp)) 9213377c28cSBrian Somers bp = lqr_RecvEcho(fp, bp); 9226471628dSBrian Somers 92326af0ae9SBrian Somers m_freem(bp); 924af57ed9fSAtsushi Murai } 925af57ed9fSAtsushi Murai 92675240ed1SBrian Somers static void 927944f7098SBrian Somers FsmRecvDiscReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 928af57ed9fSAtsushi Murai { 92926af0ae9SBrian Somers m_freem(bp); 930af57ed9fSAtsushi Murai } 931af57ed9fSAtsushi Murai 93275240ed1SBrian Somers static void 933944f7098SBrian Somers FsmRecvIdent(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 934af57ed9fSAtsushi Murai { 93526af0ae9SBrian Somers m_freem(bp); 936af57ed9fSAtsushi Murai } 937af57ed9fSAtsushi Murai 93875240ed1SBrian Somers static void 939944f7098SBrian Somers FsmRecvTimeRemain(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 940af57ed9fSAtsushi Murai { 94126af0ae9SBrian Somers m_freem(bp); 942af57ed9fSAtsushi Murai } 943af57ed9fSAtsushi Murai 94475240ed1SBrian Somers static void 945944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 946af57ed9fSAtsushi Murai { 947503a7782SBrian Somers (*fp->fn->RecvResetReq)(fp); 94898baf7c8SBrian Somers /* 949442f8495SBrian Somers * All sendable compressed packets are queued in the first (lowest 950442f8495SBrian Somers * priority) modem output queue.... dump 'em to the priority queue 951442f8495SBrian Somers * so that they arrive at the peer before our ResetAck. 95298baf7c8SBrian Somers */ 9538c07a7b2SBrian Somers link_SequenceQueue(fp->link); 954411675baSBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0, MB_CCPOUT); 95526af0ae9SBrian Somers m_freem(bp); 956af57ed9fSAtsushi Murai } 957af57ed9fSAtsushi Murai 95875240ed1SBrian Somers static void 959944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 960af57ed9fSAtsushi Murai { 961503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 96226af0ae9SBrian Somers m_freem(bp); 963af57ed9fSAtsushi Murai } 964af57ed9fSAtsushi Murai 965af57ed9fSAtsushi Murai void 966dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 967af57ed9fSAtsushi Murai { 968af57ed9fSAtsushi Murai int len; 9695d9e6103SBrian Somers struct fsmheader lh; 9700053cc58SBrian Somers const struct fsmcodedesc *codep; 971af57ed9fSAtsushi Murai 97226af0ae9SBrian Somers len = m_length(bp); 973af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 97426af0ae9SBrian Somers m_freem(bp); 975af57ed9fSAtsushi Murai return; 976af57ed9fSAtsushi Murai } 9775d9e6103SBrian Somers bp = mbuf_Read(bp, &lh, sizeof lh); 97887c3786eSBrian Somers 97987c3786eSBrian Somers if (ntohs(lh.length) != len) 98087c3786eSBrian Somers log_Printf(LogWARN, "%s: Oops: Got %d bytes but %d byte payload\n", 98187c3786eSBrian Somers fp->link->name, len, (int)ntohs(lh.length)); 98287c3786eSBrian Somers 9835d9e6103SBrian Somers if (lh.code < fp->min_code || lh.code > fp->max_code || 9845d9e6103SBrian Somers lh.code > sizeof FsmCodes / sizeof *FsmCodes) { 9853b0f8d2eSBrian Somers /* 9863b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 9873b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 9883b0f8d2eSBrian Somers */ 9893b0f8d2eSBrian Somers static u_char id; 990d93d3a9cSBrian Somers 99126af0ae9SBrian Somers bp = m_prepend(bp, &lh, sizeof lh, 0); 99226af0ae9SBrian Somers bp = m_pullup(bp); 99326af0ae9SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->m_len, MB_UNKNOWN); 99426af0ae9SBrian Somers m_freem(bp); 995af57ed9fSAtsushi Murai return; 996af57ed9fSAtsushi Murai } 997af57ed9fSAtsushi Murai 9985d9e6103SBrian Somers codep = FsmCodes + lh.code - 1; 9995d9e6103SBrian Somers if (lh.id != fp->reqid && codep->check_reqid && 10001342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 1001dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 10025d9e6103SBrian Somers fp->link->name, codep->name, lh.id, fp->reqid); 10032267893fSBrian Somers return; 10042267893fSBrian Somers } 10052267893fSBrian Somers 1006dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 10075d9e6103SBrian Somers fp->link->name, codep->name, lh.id, State2Nam(fp->state)); 10082267893fSBrian Somers 10095d9e6103SBrian Somers if (codep->inc_reqid && (lh.id == fp->reqid || 10101342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 10112267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 10122267893fSBrian Somers 10135d9e6103SBrian Somers (*codep->recv)(fp, &lh, bp); 10141ae349f5Scvs2svn } 1015503a7782SBrian Somers 1016503a7782SBrian Somers void 1017dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 1018503a7782SBrian Somers { 1019dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 1020d47dceb8SBrian Somers fp->link->name); 1021503a7782SBrian Somers } 1022503a7782SBrian Somers 1023503a7782SBrian Somers void 1024dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 1025503a7782SBrian Somers { 1026dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 1027d47dceb8SBrian Somers fp->link->name); 1028af57ed9fSAtsushi Murai } 102909206a6fSBrian Somers 103009206a6fSBrian Somers void 1031897f9429SBrian Somers fsm_Reopen(struct fsm *fp) 1032897f9429SBrian Somers { 1033897f9429SBrian Somers if (fp->state == ST_OPENED) { 1034897f9429SBrian Somers (*fp->fn->LayerDown)(fp); 1035479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 1036897f9429SBrian Somers FsmSendConfigReq(fp); 1037897f9429SBrian Somers NewState(fp, ST_REQSENT); 1038897f9429SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 1039897f9429SBrian Somers } 1040897f9429SBrian Somers } 1041897f9429SBrian Somers 1042897f9429SBrian Somers void 104309206a6fSBrian Somers fsm2initial(struct fsm *fp) 104409206a6fSBrian Somers { 1045479508cfSBrian Somers timer_Stop(&fp->FsmTimer); 1046479508cfSBrian Somers timer_Stop(&fp->OpenTimer); 1047479508cfSBrian Somers timer_Stop(&fp->StoppedTimer); 104809206a6fSBrian Somers if (fp->state == ST_STOPPED) 104909206a6fSBrian Somers fsm_Close(fp); 105009206a6fSBrian Somers if (fp->state > ST_INITIAL) 105109206a6fSBrian Somers fsm_Down(fp); 105209206a6fSBrian Somers if (fp->state > ST_INITIAL) 105309206a6fSBrian Somers fsm_Close(fp); 105409206a6fSBrian Somers } 1055