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" }, 891038894eSBrian Somers { FsmRecvIdent, 0, 1, "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 { 106182c898aSBrian Somers static const char * const 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, 135182c898aSBrian Somers struct fsm_callbacks *fn, const char * const 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); 2111038894eSBrian Somers 2121038894eSBrian Somers if (code == CODE_CONFIGREJ) 2131038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 214af57ed9fSAtsushi Murai } 215af57ed9fSAtsushi Murai 21649b239e0SBrian Somers static void 21749b239e0SBrian Somers FsmOpenNow(void *v) 21849b239e0SBrian Somers { 21949b239e0SBrian Somers struct fsm *fp = (struct fsm *)v; 22049b239e0SBrian Somers 221dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 22249b239e0SBrian Somers if (fp->state <= ST_STOPPED) { 2233a2e4f62SBrian Somers if (fp->state != ST_STARTING) { 2243a2e4f62SBrian Somers /* 2253a2e4f62SBrian Somers * In practice, we're only here in ST_STOPPED (when delaying the 2263a2e4f62SBrian Somers * first config request) or ST_CLOSED (when openmode == 0). 2273a2e4f62SBrian Somers * 2283a2e4f62SBrian Somers * The ST_STOPPED bit is breaking the RFC already :-( 2293a2e4f62SBrian Somers * 2303a2e4f62SBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 2313a2e4f62SBrian Somers * required for an Open event when state == Closed, but the RFC 2323a2e4f62SBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 2333a2e4f62SBrian Somers * ie, Initial gets an `Up' event, Closing gets a RTA etc. 2343a2e4f62SBrian Somers */ 2353a2e4f62SBrian Somers (*fp->fn->LayerStart)(fp); 2363a2e4f62SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 2373a2e4f62SBrian Somers } 238479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 23949b239e0SBrian Somers FsmSendConfigReq(fp); 24049b239e0SBrian Somers NewState(fp, ST_REQSENT); 24149b239e0SBrian Somers } 24249b239e0SBrian Somers } 24349b239e0SBrian Somers 244af57ed9fSAtsushi Murai void 245dd7e2610SBrian Somers fsm_Open(struct fsm *fp) 246af57ed9fSAtsushi Murai { 247af57ed9fSAtsushi Murai switch (fp->state) { 248af57ed9fSAtsushi Murai case ST_INITIAL: 249af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 2506d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2516d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 252af57ed9fSAtsushi Murai break; 253af57ed9fSAtsushi Murai case ST_CLOSED: 254af57ed9fSAtsushi Murai if (fp->open_mode == OPEN_PASSIVE) { 2553a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 25649b239e0SBrian Somers } else if (fp->open_mode > 0) { 25749b239e0SBrian Somers if (fp->open_mode > 1) 258dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 259d47dceb8SBrian Somers fp->link->name, fp->open_mode); 2603a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 261dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 26249b239e0SBrian Somers fp->OpenTimer.load = fp->open_mode * SECTICKS; 26349b239e0SBrian Somers fp->OpenTimer.func = FsmOpenNow; 26449b239e0SBrian Somers fp->OpenTimer.arg = (void *)fp; 265dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 26649b239e0SBrian Somers } else 26749b239e0SBrian Somers FsmOpenNow(fp); 268af57ed9fSAtsushi Murai break; 269af57ed9fSAtsushi Murai case ST_STOPPED: /* XXX: restart option */ 270af57ed9fSAtsushi Murai case ST_REQSENT: 271af57ed9fSAtsushi Murai case ST_ACKRCVD: 272af57ed9fSAtsushi Murai case ST_ACKSENT: 273af57ed9fSAtsushi Murai case ST_OPENED: /* XXX: restart option */ 274af57ed9fSAtsushi Murai break; 275af57ed9fSAtsushi Murai case ST_CLOSING: /* XXX: restart option */ 276af57ed9fSAtsushi Murai case ST_STOPPING: /* XXX: restart option */ 277af57ed9fSAtsushi Murai NewState(fp, ST_STOPPING); 278af57ed9fSAtsushi Murai break; 279af57ed9fSAtsushi Murai } 280af57ed9fSAtsushi Murai } 281af57ed9fSAtsushi Murai 282af57ed9fSAtsushi Murai void 283dd7e2610SBrian Somers fsm_Up(struct fsm *fp) 284af57ed9fSAtsushi Murai { 285af57ed9fSAtsushi Murai switch (fp->state) { 286af57ed9fSAtsushi Murai case ST_INITIAL: 287dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 2881fa665f5SBrian Somers fp->link->name); 289af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 290af57ed9fSAtsushi Murai break; 291af57ed9fSAtsushi Murai case ST_STARTING: 292479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 293af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 294af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 295af57ed9fSAtsushi Murai break; 296af57ed9fSAtsushi Murai default: 297dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 298d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 299af57ed9fSAtsushi Murai break; 300af57ed9fSAtsushi Murai } 301af57ed9fSAtsushi Murai } 302af57ed9fSAtsushi Murai 303af57ed9fSAtsushi Murai void 304dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 305af57ed9fSAtsushi Murai { 306af57ed9fSAtsushi Murai switch (fp->state) { 307af57ed9fSAtsushi Murai case ST_CLOSED: 308af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 309af57ed9fSAtsushi Murai break; 310455aabc3SBrian Somers case ST_CLOSING: 3118a8d9927SBrian Somers /* This TLF contradicts the RFC (1661), which ``misses it out'' ! */ 3126d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 313455aabc3SBrian Somers NewState(fp, ST_INITIAL); 3146d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 315455aabc3SBrian Somers break; 316af57ed9fSAtsushi Murai case ST_STOPPED: 317455aabc3SBrian Somers NewState(fp, ST_STARTING); 3186d666775SBrian Somers (*fp->fn->LayerStart)(fp); 3196d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 320455aabc3SBrian Somers break; 321af57ed9fSAtsushi Murai case ST_STOPPING: 322af57ed9fSAtsushi Murai case ST_REQSENT: 323af57ed9fSAtsushi Murai case ST_ACKRCVD: 324af57ed9fSAtsushi Murai case ST_ACKSENT: 325af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 326af57ed9fSAtsushi Murai break; 327af57ed9fSAtsushi Murai case ST_OPENED: 3286d666775SBrian Somers (*fp->fn->LayerDown)(fp); 329af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 3306d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 331af57ed9fSAtsushi Murai break; 332af57ed9fSAtsushi Murai } 333af57ed9fSAtsushi Murai } 334af57ed9fSAtsushi Murai 335af57ed9fSAtsushi Murai void 336dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 337af57ed9fSAtsushi Murai { 338af57ed9fSAtsushi Murai switch (fp->state) { 339af57ed9fSAtsushi Murai case ST_STARTING: 3406d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 341af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 3426d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 343af57ed9fSAtsushi Murai break; 344af57ed9fSAtsushi Murai case ST_STOPPED: 345af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 346af57ed9fSAtsushi Murai break; 347af57ed9fSAtsushi Murai case ST_STOPPING: 348af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 349af57ed9fSAtsushi Murai break; 350af57ed9fSAtsushi Murai case ST_OPENED: 3516d666775SBrian Somers (*fp->fn->LayerDown)(fp); 35215c8dc2aSBrian Somers if (fp->state == ST_OPENED) { 353479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 354455aabc3SBrian Somers FsmSendTerminateReq(fp); 355455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3566d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 35715c8dc2aSBrian Somers } 358455aabc3SBrian Somers break; 359af57ed9fSAtsushi Murai case ST_REQSENT: 360af57ed9fSAtsushi Murai case ST_ACKRCVD: 361af57ed9fSAtsushi Murai case ST_ACKSENT: 362479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 363af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 364af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 365af57ed9fSAtsushi Murai break; 366af57ed9fSAtsushi Murai } 367af57ed9fSAtsushi Murai } 368af57ed9fSAtsushi Murai 369af57ed9fSAtsushi Murai /* 370af57ed9fSAtsushi Murai * Send functions 371af57ed9fSAtsushi Murai */ 37275240ed1SBrian Somers static void 373944f7098SBrian Somers FsmSendConfigReq(struct fsm *fp) 374af57ed9fSAtsushi Murai { 375479508cfSBrian Somers if (fp->more.reqs-- > 0 && fp->restart-- > 0) { 37683d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 377dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 378af57ed9fSAtsushi Murai } else { 379479508cfSBrian Somers if (fp->more.reqs < 0) 380479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REQs sent - abandoning " 381479508cfSBrian Somers "negotiation\n", fp->link->name, fp->name); 3821038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 383dd7e2610SBrian Somers fsm_Close(fp); 384af57ed9fSAtsushi Murai } 385af57ed9fSAtsushi Murai } 386af57ed9fSAtsushi Murai 38775240ed1SBrian Somers static void 388944f7098SBrian Somers FsmSendTerminateReq(struct fsm *fp) 389af57ed9fSAtsushi Murai { 390411675baSBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0, MB_UNKNOWN); 3912267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 392dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 393af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 394af57ed9fSAtsushi Murai } 395af57ed9fSAtsushi Murai 396af57ed9fSAtsushi Murai /* 397af57ed9fSAtsushi Murai * Timeout actions 398af57ed9fSAtsushi Murai */ 39975240ed1SBrian Somers static void 400b6e82f33SBrian Somers FsmTimeout(void *v) 401af57ed9fSAtsushi Murai { 402b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 403b6e82f33SBrian Somers 404af57ed9fSAtsushi Murai if (fp->restart) { 405af57ed9fSAtsushi Murai switch (fp->state) { 406af57ed9fSAtsushi Murai case ST_CLOSING: 407af57ed9fSAtsushi Murai case ST_STOPPING: 408af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 409af57ed9fSAtsushi Murai break; 410af57ed9fSAtsushi Murai case ST_REQSENT: 411af57ed9fSAtsushi Murai case ST_ACKSENT: 412af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 413af57ed9fSAtsushi Murai break; 414af57ed9fSAtsushi Murai case ST_ACKRCVD: 415af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 416af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 417af57ed9fSAtsushi Murai break; 418af57ed9fSAtsushi Murai } 419dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 420af57ed9fSAtsushi Murai } else { 421af57ed9fSAtsushi Murai switch (fp->state) { 422af57ed9fSAtsushi Murai case ST_CLOSING: 4236d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 424af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 4256d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 426af57ed9fSAtsushi Murai break; 427af57ed9fSAtsushi Murai case ST_STOPPING: 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 case ST_REQSENT: /* XXX: 3p */ 433af57ed9fSAtsushi Murai case ST_ACKSENT: 434af57ed9fSAtsushi Murai case ST_ACKRCVD: 4356d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 436af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4376d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 438af57ed9fSAtsushi Murai break; 439af57ed9fSAtsushi Murai } 440af57ed9fSAtsushi Murai } 441af57ed9fSAtsushi Murai } 442af57ed9fSAtsushi Murai 44375240ed1SBrian Somers static void 444479508cfSBrian Somers FsmInitRestartCounter(struct fsm *fp, int what) 445af57ed9fSAtsushi Murai { 446dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 447af57ed9fSAtsushi Murai fp->FsmTimer.func = FsmTimeout; 448af57ed9fSAtsushi Murai fp->FsmTimer.arg = (void *)fp; 449479508cfSBrian Somers (*fp->fn->InitRestartCounter)(fp, what); 450af57ed9fSAtsushi Murai } 451af57ed9fSAtsushi Murai 452af57ed9fSAtsushi Murai /* 453af57ed9fSAtsushi Murai * Actions when receive packets 454af57ed9fSAtsushi Murai */ 45575240ed1SBrian Somers static void 456944f7098SBrian Somers FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 457944f7098SBrian Somers /* RCR */ 458af57ed9fSAtsushi Murai { 45930c2f2ffSBrian Somers struct fsm_decode dec; 46053c9f6c0SAtsushi Murai int plen, flen; 461af57ed9fSAtsushi Murai int ackaction = 0; 462af57ed9fSAtsushi Murai 46326af0ae9SBrian Somers plen = m_length(bp); 46470ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 46553c9f6c0SAtsushi Murai if (plen < flen) { 466a33b2ef7SBrian Somers log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 467d47dceb8SBrian Somers fp->link->name, plen, flen); 46826af0ae9SBrian Somers m_freem(bp); 469af57ed9fSAtsushi Murai return; 470af57ed9fSAtsushi Murai } 471af57ed9fSAtsushi Murai 4723377c28cSBrian Somers /* Check and process easy case */ 473af57ed9fSAtsushi Murai switch (fp->state) { 474af57ed9fSAtsushi Murai case ST_INITIAL: 47506337856SBrian Somers if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 47606337856SBrian Somers /* 47706337856SBrian Somers * ccp_SetOpenMode() leaves us in initial if we're disabling 4785d9e6103SBrian Somers * & denying everything. 47906337856SBrian Somers */ 48026af0ae9SBrian Somers bp = m_prepend(bp, lhp, sizeof *lhp, 2); 4815d9e6103SBrian Somers bp = proto_Prepend(bp, fp->proto, 0, 0); 48226af0ae9SBrian Somers bp = m_pullup(bp); 48326af0ae9SBrian Somers lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->m_len); 48426af0ae9SBrian Somers m_freem(bp); 48506337856SBrian Somers return; 48606337856SBrian Somers } 48706337856SBrian Somers /* Drop through */ 488af57ed9fSAtsushi Murai case ST_STARTING: 489dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 490d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 49126af0ae9SBrian Somers m_freem(bp); 492af57ed9fSAtsushi Murai return; 493af57ed9fSAtsushi Murai case ST_CLOSED: 4942267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 49526af0ae9SBrian Somers m_freem(bp); 496af57ed9fSAtsushi Murai return; 497af57ed9fSAtsushi Murai case ST_CLOSING: 498dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 499d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 500a9c503afSBrian Somers case ST_STOPPING: 50126af0ae9SBrian Somers m_freem(bp); 502af57ed9fSAtsushi Murai return; 50368a0e171SBrian Somers case ST_OPENED: 50468a0e171SBrian Somers (*fp->fn->LayerDown)(fp); 50568a0e171SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 50668a0e171SBrian Somers break; 507af57ed9fSAtsushi Murai } 508af57ed9fSAtsushi Murai 50926af0ae9SBrian Somers bp = m_pullup(bp); 51030c2f2ffSBrian Somers dec.ackend = dec.ack; 51130c2f2ffSBrian Somers dec.nakend = dec.nak; 51230c2f2ffSBrian Somers dec.rejend = dec.rej; 51330c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec); 5142267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 515dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 516af57ed9fSAtsushi Murai 51730c2f2ffSBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 518af57ed9fSAtsushi Murai ackaction = 1; 519af57ed9fSAtsushi Murai 520af57ed9fSAtsushi Murai switch (fp->state) { 521af57ed9fSAtsushi Murai case ST_STOPPED: 522479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 52368a0e171SBrian Somers /* Fall through */ 52468a0e171SBrian Somers 52568a0e171SBrian Somers case ST_OPENED: 526af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 527af57ed9fSAtsushi Murai break; 528af57ed9fSAtsushi Murai } 529af57ed9fSAtsushi Murai 53030c2f2ffSBrian Somers if (dec.rejend != dec.rej) 531411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej, 532411675baSBrian Somers MB_UNKNOWN); 53330c2f2ffSBrian Somers if (dec.nakend != dec.nak) 534411675baSBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak, 535411675baSBrian Somers MB_UNKNOWN); 536af57ed9fSAtsushi Murai if (ackaction) 537411675baSBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack, 538411675baSBrian Somers MB_UNKNOWN); 539af57ed9fSAtsushi Murai 540af57ed9fSAtsushi Murai switch (fp->state) { 541455aabc3SBrian Somers case ST_STOPPED: 542479508cfSBrian Somers /* 543479508cfSBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 544479508cfSBrian Somers * required for a RCR when state == ST_STOPPED, but the RFC 545479508cfSBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 546479508cfSBrian Somers */ 547479508cfSBrian Somers (*fp->fn->LayerStart)(fp); 548479508cfSBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 549479508cfSBrian Somers /* Fall through */ 550479508cfSBrian Somers 551479508cfSBrian Somers case ST_OPENED: 552af57ed9fSAtsushi Murai if (ackaction) 553af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 554af57ed9fSAtsushi Murai else 555af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 556af57ed9fSAtsushi Murai break; 557af57ed9fSAtsushi Murai case ST_REQSENT: 558af57ed9fSAtsushi Murai if (ackaction) 559af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 560af57ed9fSAtsushi Murai break; 561af57ed9fSAtsushi Murai case ST_ACKRCVD: 562af57ed9fSAtsushi Murai if (ackaction) { 563af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5646f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5656d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5666f384573SBrian Somers else { 5676f384573SBrian Somers (*fp->fn->LayerDown)(fp); 568479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 5696f384573SBrian Somers FsmSendTerminateReq(fp); 5706f384573SBrian Somers NewState(fp, ST_CLOSING); 5711038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 5726f384573SBrian Somers } 573af57ed9fSAtsushi Murai } 574af57ed9fSAtsushi Murai break; 575af57ed9fSAtsushi Murai case ST_ACKSENT: 576af57ed9fSAtsushi Murai if (!ackaction) 577af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 578af57ed9fSAtsushi Murai break; 579af57ed9fSAtsushi Murai } 58026af0ae9SBrian Somers m_freem(bp); 581479508cfSBrian Somers 582479508cfSBrian Somers if (dec.rejend != dec.rej && --fp->more.rejs <= 0) { 583479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REJs sent - abandoning negotiation\n", 584479508cfSBrian Somers fp->link->name, fp->name); 5851038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 586479508cfSBrian Somers fsm_Close(fp); 587479508cfSBrian Somers } 588479508cfSBrian Somers 589479508cfSBrian Somers if (dec.nakend != dec.nak && --fp->more.naks <= 0) { 590479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s NAKs sent - abandoning negotiation\n", 591479508cfSBrian Somers fp->link->name, fp->name); 5921038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 593479508cfSBrian Somers fsm_Close(fp); 594479508cfSBrian Somers } 595af57ed9fSAtsushi Murai } 596af57ed9fSAtsushi Murai 59775240ed1SBrian Somers static void 598944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 599944f7098SBrian Somers /* RCA */ 600af57ed9fSAtsushi Murai { 601af57ed9fSAtsushi Murai switch (fp->state) { 602af57ed9fSAtsushi Murai case ST_CLOSED: 603af57ed9fSAtsushi Murai case ST_STOPPED: 6042267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 605af57ed9fSAtsushi Murai break; 606af57ed9fSAtsushi Murai case ST_CLOSING: 607af57ed9fSAtsushi Murai case ST_STOPPING: 608af57ed9fSAtsushi Murai break; 609af57ed9fSAtsushi Murai case ST_REQSENT: 610479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 611af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 612af57ed9fSAtsushi Murai break; 613af57ed9fSAtsushi Murai case ST_ACKRCVD: 614af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 615af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 616af57ed9fSAtsushi Murai break; 617af57ed9fSAtsushi Murai case ST_ACKSENT: 618479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 619af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 6206f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 6216d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 6226f384573SBrian Somers else { 6236f384573SBrian Somers (*fp->fn->LayerDown)(fp); 624479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 6256f384573SBrian Somers FsmSendTerminateReq(fp); 6266f384573SBrian Somers NewState(fp, ST_CLOSING); 6271038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 6286f384573SBrian Somers } 629af57ed9fSAtsushi Murai break; 630af57ed9fSAtsushi Murai case ST_OPENED: 6316d666775SBrian Somers (*fp->fn->LayerDown)(fp); 632af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 633af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 6346d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 635af57ed9fSAtsushi Murai break; 636af57ed9fSAtsushi Murai } 63726af0ae9SBrian Somers m_freem(bp); 638af57ed9fSAtsushi Murai } 639af57ed9fSAtsushi Murai 64075240ed1SBrian Somers static void 641944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 642944f7098SBrian Somers /* RCN */ 643af57ed9fSAtsushi Murai { 64430c2f2ffSBrian Somers struct fsm_decode dec; 64553c9f6c0SAtsushi Murai int plen, flen; 646af57ed9fSAtsushi Murai 64726af0ae9SBrian Somers plen = m_length(bp); 64870ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 64953c9f6c0SAtsushi Murai if (plen < flen) { 65026af0ae9SBrian Somers m_freem(bp); 651af57ed9fSAtsushi Murai return; 652af57ed9fSAtsushi Murai } 653af57ed9fSAtsushi Murai 654af57ed9fSAtsushi Murai /* 655af57ed9fSAtsushi Murai * Check and process easy case 656af57ed9fSAtsushi Murai */ 657af57ed9fSAtsushi Murai switch (fp->state) { 658af57ed9fSAtsushi Murai case ST_INITIAL: 659af57ed9fSAtsushi Murai case ST_STARTING: 660dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 661d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 66226af0ae9SBrian Somers m_freem(bp); 663af57ed9fSAtsushi Murai return; 664af57ed9fSAtsushi Murai case ST_CLOSED: 665af57ed9fSAtsushi Murai case ST_STOPPED: 6662267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 66726af0ae9SBrian Somers m_freem(bp); 668af57ed9fSAtsushi Murai return; 669af57ed9fSAtsushi Murai case ST_CLOSING: 670af57ed9fSAtsushi Murai case ST_STOPPING: 67126af0ae9SBrian Somers m_freem(bp); 672af57ed9fSAtsushi Murai return; 673af57ed9fSAtsushi Murai } 674af57ed9fSAtsushi Murai 67526af0ae9SBrian Somers bp = m_pullup(bp); 67630c2f2ffSBrian Somers dec.ackend = dec.ack; 67730c2f2ffSBrian Somers dec.nakend = dec.nak; 67830c2f2ffSBrian Somers dec.rejend = dec.rej; 67930c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); 6802267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 681dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 682af57ed9fSAtsushi Murai 683af57ed9fSAtsushi Murai switch (fp->state) { 684af57ed9fSAtsushi Murai case ST_REQSENT: 685af57ed9fSAtsushi Murai case ST_ACKSENT: 686479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 687af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 688af57ed9fSAtsushi Murai break; 689af57ed9fSAtsushi Murai case ST_OPENED: 6906d666775SBrian Somers (*fp->fn->LayerDown)(fp); 691455aabc3SBrian Somers FsmSendConfigReq(fp); 692455aabc3SBrian Somers NewState(fp, ST_REQSENT); 6936d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 694455aabc3SBrian Somers break; 695af57ed9fSAtsushi Murai case ST_ACKRCVD: 696af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 697af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 698af57ed9fSAtsushi Murai break; 699af57ed9fSAtsushi Murai } 700af57ed9fSAtsushi Murai 70126af0ae9SBrian Somers m_freem(bp); 702af57ed9fSAtsushi Murai } 703af57ed9fSAtsushi Murai 70475240ed1SBrian Somers static void 705944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 706944f7098SBrian Somers /* RTR */ 707af57ed9fSAtsushi Murai { 708af57ed9fSAtsushi Murai switch (fp->state) { 709af57ed9fSAtsushi Murai case ST_INITIAL: 710af57ed9fSAtsushi Murai case ST_STARTING: 711dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 712d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 713af57ed9fSAtsushi Murai break; 714af57ed9fSAtsushi Murai case ST_CLOSED: 715af57ed9fSAtsushi Murai case ST_STOPPED: 716af57ed9fSAtsushi Murai case ST_CLOSING: 717af57ed9fSAtsushi Murai case ST_STOPPING: 718af57ed9fSAtsushi Murai case ST_REQSENT: 7192267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 720af57ed9fSAtsushi Murai break; 721af57ed9fSAtsushi Murai case ST_ACKRCVD: 722af57ed9fSAtsushi Murai case ST_ACKSENT: 7232267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 724af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 725af57ed9fSAtsushi Murai break; 726af57ed9fSAtsushi Murai case ST_OPENED: 7276d666775SBrian Somers (*fp->fn->LayerDown)(fp); 7282267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 729479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 730dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 7318f2fa0eeSBrian Somers fp->restart = 0; 7328f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 7336d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 734479508cfSBrian Somers /* A delayed ST_STOPPED is now scheduled */ 735af57ed9fSAtsushi Murai break; 736af57ed9fSAtsushi Murai } 73726af0ae9SBrian Somers m_freem(bp); 738af57ed9fSAtsushi Murai } 739af57ed9fSAtsushi Murai 74075240ed1SBrian Somers static void 741944f7098SBrian Somers FsmRecvTermAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 742944f7098SBrian Somers /* RTA */ 743af57ed9fSAtsushi Murai { 744af57ed9fSAtsushi Murai switch (fp->state) { 745af57ed9fSAtsushi Murai case ST_CLOSING: 7466d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 747af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 7486d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 749af57ed9fSAtsushi Murai break; 750af57ed9fSAtsushi Murai case ST_STOPPING: 7516d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 752af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 7536d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 754af57ed9fSAtsushi Murai break; 755af57ed9fSAtsushi Murai case ST_ACKRCVD: 756af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 757af57ed9fSAtsushi Murai break; 758af57ed9fSAtsushi Murai case ST_OPENED: 7596d666775SBrian Somers (*fp->fn->LayerDown)(fp); 760af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 761af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 7626d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 763af57ed9fSAtsushi Murai break; 764af57ed9fSAtsushi Murai } 76526af0ae9SBrian Somers m_freem(bp); 766af57ed9fSAtsushi Murai } 767af57ed9fSAtsushi Murai 76875240ed1SBrian Somers static void 769944f7098SBrian Somers FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 770944f7098SBrian Somers /* RCJ */ 771af57ed9fSAtsushi Murai { 77230c2f2ffSBrian Somers struct fsm_decode dec; 77353c9f6c0SAtsushi Murai int plen, flen; 774af57ed9fSAtsushi Murai 77526af0ae9SBrian Somers plen = m_length(bp); 77670ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 77753c9f6c0SAtsushi Murai if (plen < flen) { 77826af0ae9SBrian Somers m_freem(bp); 779af57ed9fSAtsushi Murai return; 780af57ed9fSAtsushi Murai } 781af57ed9fSAtsushi Murai 7821038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 7831038894eSBrian Somers 784af57ed9fSAtsushi Murai /* 785af57ed9fSAtsushi Murai * Check and process easy case 786af57ed9fSAtsushi Murai */ 787af57ed9fSAtsushi Murai switch (fp->state) { 788af57ed9fSAtsushi Murai case ST_INITIAL: 789af57ed9fSAtsushi Murai case ST_STARTING: 790dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 791d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 79226af0ae9SBrian Somers m_freem(bp); 793af57ed9fSAtsushi Murai return; 794af57ed9fSAtsushi Murai case ST_CLOSED: 795af57ed9fSAtsushi Murai case ST_STOPPED: 7962267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 79726af0ae9SBrian Somers m_freem(bp); 798af57ed9fSAtsushi Murai return; 799af57ed9fSAtsushi Murai case ST_CLOSING: 800af57ed9fSAtsushi Murai case ST_STOPPING: 80126af0ae9SBrian Somers m_freem(bp); 802af57ed9fSAtsushi Murai return; 803af57ed9fSAtsushi Murai } 804af57ed9fSAtsushi Murai 80526af0ae9SBrian Somers bp = m_pullup(bp); 80630c2f2ffSBrian Somers dec.ackend = dec.ack; 80730c2f2ffSBrian Somers dec.nakend = dec.nak; 80830c2f2ffSBrian Somers dec.rejend = dec.rej; 80930c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); 8102267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 811dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 812af57ed9fSAtsushi Murai 813af57ed9fSAtsushi Murai switch (fp->state) { 814af57ed9fSAtsushi Murai case ST_REQSENT: 815af57ed9fSAtsushi Murai case ST_ACKSENT: 816479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 817af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 818af57ed9fSAtsushi Murai break; 819af57ed9fSAtsushi Murai case ST_OPENED: 8206d666775SBrian Somers (*fp->fn->LayerDown)(fp); 821455aabc3SBrian Somers FsmSendConfigReq(fp); 822455aabc3SBrian Somers NewState(fp, ST_REQSENT); 8236d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 824455aabc3SBrian Somers break; 825af57ed9fSAtsushi Murai case ST_ACKRCVD: 826af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 827af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 828af57ed9fSAtsushi Murai break; 829af57ed9fSAtsushi Murai } 83026af0ae9SBrian Somers m_freem(bp); 831af57ed9fSAtsushi Murai } 832af57ed9fSAtsushi Murai 83375240ed1SBrian Somers static void 834944f7098SBrian Somers FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 835af57ed9fSAtsushi Murai { 83626af0ae9SBrian Somers m_freem(bp); 837af57ed9fSAtsushi Murai } 838af57ed9fSAtsushi Murai 83975240ed1SBrian Somers static void 840944f7098SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 841af57ed9fSAtsushi Murai { 8428c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 8433377c28cSBrian Somers u_short proto; 844af57ed9fSAtsushi Murai 84526af0ae9SBrian Somers if (m_length(bp) < 2) { 84626af0ae9SBrian Somers m_freem(bp); 8473377c28cSBrian Somers return; 8483377c28cSBrian Somers } 8493377c28cSBrian Somers bp = mbuf_Read(bp, &proto, 2); 8503377c28cSBrian Somers proto = ntohs(proto); 851dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 852d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 853af57ed9fSAtsushi Murai 854af57ed9fSAtsushi Murai switch (proto) { 855af57ed9fSAtsushi Murai case PROTO_LQR: 8568c07a7b2SBrian Somers if (p) 857dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 8588c07a7b2SBrian Somers else 859dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 860d47dceb8SBrian Somers fp->link->name); 861af57ed9fSAtsushi Murai break; 862af57ed9fSAtsushi Murai case PROTO_CCP: 863dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 8643b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 8658a8d9927SBrian Somers /* Despite the RFC (1661), don't do an out-of-place TLF */ 8668a8d9927SBrian Somers /* (*fp->fn->LayerFinish)(fp); */ 867af57ed9fSAtsushi Murai switch (fp->state) { 868af57ed9fSAtsushi Murai case ST_CLOSED: 869af57ed9fSAtsushi Murai case ST_CLOSING: 870af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 871af57ed9fSAtsushi Murai default: 872af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 873af57ed9fSAtsushi Murai break; 874af57ed9fSAtsushi Murai } 8758a8d9927SBrian Somers /* See above */ 8768a8d9927SBrian Somers /* (*fp->parent->LayerFinish)(fp->parent->object, fp); */ 877dc0fdb6bSBrian Somers } 8781ae349f5Scvs2svn break; 8798a59beb7SBrian Somers case PROTO_IPCP: 8808a59beb7SBrian Somers if (fp->proto == PROTO_LCP) { 8818a59beb7SBrian Somers log_Printf(LogPHASE, "%s: IPCP protocol reject closes IPCP !\n", 8828a59beb7SBrian Somers fp->link->name); 8838a59beb7SBrian Somers fsm_Close(&fp->bundle->ncp.ipcp.fsm); 8848a59beb7SBrian Somers } 8858a59beb7SBrian Somers break; 886673903ecSBrian Somers case PROTO_MP: 887673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 888673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 889673903ecSBrian Somers 890673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 891dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 892d47dceb8SBrian Somers fp->link->name); 893dd7e2610SBrian Somers fsm_Close(fp); 894673903ecSBrian Somers } 895673903ecSBrian Somers } 896af57ed9fSAtsushi Murai break; 897af57ed9fSAtsushi Murai } 89826af0ae9SBrian Somers m_freem(bp); 899af57ed9fSAtsushi Murai } 900af57ed9fSAtsushi Murai 90175240ed1SBrian Somers static void 902944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 903af57ed9fSAtsushi Murai { 904dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 905af57ed9fSAtsushi Murai u_char *cp; 906fe3125a0SBrian Somers u_int32_t magic; 907af57ed9fSAtsushi Murai 90826af0ae9SBrian Somers bp = m_pullup(bp); 90926af0ae9SBrian Somers m_settype(bp, MB_ECHOIN); 91087c3786eSBrian Somers 91187c3786eSBrian Somers if (lcp && ntohs(lhp->length) - sizeof *lhp >= 4) { 912af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 9139e8ec64bSBrian Somers ua_ntohl(cp, &magic); 914dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 915990a543fSBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: magic 0x%08lx is wrong," 916990a543fSBrian Somers " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 917990a543fSBrian Somers (u_long)lcp->his_magic); 918af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 919af57ed9fSAtsushi Murai } 920af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 9219e8ec64bSBrian Somers ua_htonl(&lcp->want_magic, cp); /* local magic */ 92287c3786eSBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, 92387c3786eSBrian Somers ntohs(lhp->length) - sizeof *lhp, MB_ECHOOUT); 924af57ed9fSAtsushi Murai } 925dc0fdb6bSBrian Somers } 92626af0ae9SBrian Somers m_freem(bp); 927af57ed9fSAtsushi Murai } 928af57ed9fSAtsushi Murai 92975240ed1SBrian Somers static void 930944f7098SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 931af57ed9fSAtsushi Murai { 9326471628dSBrian Somers if (fsm2lcp(fp)) 9333377c28cSBrian Somers bp = lqr_RecvEcho(fp, bp); 9346471628dSBrian Somers 93526af0ae9SBrian Somers m_freem(bp); 936af57ed9fSAtsushi Murai } 937af57ed9fSAtsushi Murai 93875240ed1SBrian Somers static void 939944f7098SBrian Somers FsmRecvDiscReq(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 FsmRecvIdent(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 946af57ed9fSAtsushi Murai { 9471038894eSBrian Somers u_int32_t magic; 9481038894eSBrian Somers u_short len; 9491038894eSBrian Somers u_char *cp; 9501038894eSBrian Somers 9511038894eSBrian Somers len = ntohs(lhp->length) - sizeof *lhp; 9521038894eSBrian Somers if (len >= 4) { 9531038894eSBrian Somers bp = m_pullup(m_append(bp, "", 1)); 9541038894eSBrian Somers cp = MBUF_CTOP(bp); 9551038894eSBrian Somers ua_ntohl(cp, &magic); 9561038894eSBrian Somers if (magic != fp->link->lcp.his_magic) 9571038894eSBrian Somers log_Printf(fp->LogLevel, "%s: RecvIdent: magic 0x%08lx is wrong," 9581038894eSBrian Somers " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 9591038894eSBrian Somers (u_long)fp->link->lcp.his_magic); 9601038894eSBrian Somers cp[len] = '\0'; 9611038894eSBrian Somers lcp_RecvIdentification(&fp->link->lcp, cp + 4); 9621038894eSBrian Somers } 96326af0ae9SBrian Somers m_freem(bp); 964af57ed9fSAtsushi Murai } 965af57ed9fSAtsushi Murai 96675240ed1SBrian Somers static void 967944f7098SBrian Somers FsmRecvTimeRemain(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 968af57ed9fSAtsushi Murai { 96926af0ae9SBrian Somers m_freem(bp); 970af57ed9fSAtsushi Murai } 971af57ed9fSAtsushi Murai 97275240ed1SBrian Somers static void 973944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 974af57ed9fSAtsushi Murai { 975503a7782SBrian Somers (*fp->fn->RecvResetReq)(fp); 97698baf7c8SBrian Somers /* 977442f8495SBrian Somers * All sendable compressed packets are queued in the first (lowest 978442f8495SBrian Somers * priority) modem output queue.... dump 'em to the priority queue 979442f8495SBrian Somers * so that they arrive at the peer before our ResetAck. 98098baf7c8SBrian Somers */ 9818c07a7b2SBrian Somers link_SequenceQueue(fp->link); 982411675baSBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0, MB_CCPOUT); 98326af0ae9SBrian Somers m_freem(bp); 984af57ed9fSAtsushi Murai } 985af57ed9fSAtsushi Murai 98675240ed1SBrian Somers static void 987944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 988af57ed9fSAtsushi Murai { 989503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 99026af0ae9SBrian Somers m_freem(bp); 991af57ed9fSAtsushi Murai } 992af57ed9fSAtsushi Murai 993af57ed9fSAtsushi Murai void 994dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 995af57ed9fSAtsushi Murai { 996af57ed9fSAtsushi Murai int len; 9975d9e6103SBrian Somers struct fsmheader lh; 9980053cc58SBrian Somers const struct fsmcodedesc *codep; 999af57ed9fSAtsushi Murai 100026af0ae9SBrian Somers len = m_length(bp); 1001af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 100226af0ae9SBrian Somers m_freem(bp); 1003af57ed9fSAtsushi Murai return; 1004af57ed9fSAtsushi Murai } 10055d9e6103SBrian Somers bp = mbuf_Read(bp, &lh, sizeof lh); 100687c3786eSBrian Somers 1007962a3cbcSBrian Somers if (ntohs(lh.length) > len) { 1008962a3cbcSBrian Somers log_Printf(LogWARN, "%s: Oops: Got %d bytes but %d byte payload " 1009962a3cbcSBrian Somers "- dropped\n", fp->link->name, len, (int)ntohs(lh.length)); 1010962a3cbcSBrian Somers m_freem(bp); 1011962a3cbcSBrian Somers return; 1012962a3cbcSBrian Somers } 101387c3786eSBrian Somers 10145d9e6103SBrian Somers if (lh.code < fp->min_code || lh.code > fp->max_code || 10155d9e6103SBrian Somers lh.code > sizeof FsmCodes / sizeof *FsmCodes) { 10163b0f8d2eSBrian Somers /* 10173b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 10183b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 10193b0f8d2eSBrian Somers */ 10203b0f8d2eSBrian Somers static u_char id; 1021d93d3a9cSBrian Somers 102226af0ae9SBrian Somers bp = m_prepend(bp, &lh, sizeof lh, 0); 102326af0ae9SBrian Somers bp = m_pullup(bp); 102426af0ae9SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->m_len, MB_UNKNOWN); 102526af0ae9SBrian Somers m_freem(bp); 1026af57ed9fSAtsushi Murai return; 1027af57ed9fSAtsushi Murai } 1028af57ed9fSAtsushi Murai 10295d9e6103SBrian Somers codep = FsmCodes + lh.code - 1; 10305d9e6103SBrian Somers if (lh.id != fp->reqid && codep->check_reqid && 10311342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 1032dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 10335d9e6103SBrian Somers fp->link->name, codep->name, lh.id, fp->reqid); 10342267893fSBrian Somers return; 10352267893fSBrian Somers } 10362267893fSBrian Somers 1037dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 10385d9e6103SBrian Somers fp->link->name, codep->name, lh.id, State2Nam(fp->state)); 10392267893fSBrian Somers 10405d9e6103SBrian Somers if (codep->inc_reqid && (lh.id == fp->reqid || 10411342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 10422267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 10432267893fSBrian Somers 10445d9e6103SBrian Somers (*codep->recv)(fp, &lh, bp); 10451ae349f5Scvs2svn } 1046503a7782SBrian Somers 1047503a7782SBrian Somers void 1048dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 1049503a7782SBrian Somers { 1050dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 1051d47dceb8SBrian Somers fp->link->name); 1052503a7782SBrian Somers } 1053503a7782SBrian Somers 1054503a7782SBrian Somers void 1055dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 1056503a7782SBrian Somers { 1057dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 1058d47dceb8SBrian Somers fp->link->name); 1059af57ed9fSAtsushi Murai } 106009206a6fSBrian Somers 106109206a6fSBrian Somers void 1062897f9429SBrian Somers fsm_Reopen(struct fsm *fp) 1063897f9429SBrian Somers { 1064897f9429SBrian Somers if (fp->state == ST_OPENED) { 1065897f9429SBrian Somers (*fp->fn->LayerDown)(fp); 1066479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 1067897f9429SBrian Somers FsmSendConfigReq(fp); 1068897f9429SBrian Somers NewState(fp, ST_REQSENT); 1069897f9429SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 1070897f9429SBrian Somers } 1071897f9429SBrian Somers } 1072897f9429SBrian Somers 1073897f9429SBrian Somers void 107409206a6fSBrian Somers fsm2initial(struct fsm *fp) 107509206a6fSBrian Somers { 1076479508cfSBrian Somers timer_Stop(&fp->FsmTimer); 1077479508cfSBrian Somers timer_Stop(&fp->OpenTimer); 1078479508cfSBrian Somers timer_Stop(&fp->StoppedTimer); 107909206a6fSBrian Somers if (fp->state == ST_STOPPED) 108009206a6fSBrian Somers fsm_Close(fp); 108109206a6fSBrian Somers if (fp->state > ST_INITIAL) 108209206a6fSBrian Somers fsm_Down(fp); 108309206a6fSBrian Somers if (fp->state > ST_INITIAL) 108409206a6fSBrian Somers fsm_Close(fp); 108509206a6fSBrian Somers } 1086