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 * 208a8d9927SBrian Somers * $Id: fsm.c,v 1.39 1999/02/26 21:28:11 brian Exp $ 21af57ed9fSAtsushi Murai * 22af57ed9fSAtsushi Murai * TODO: 23af57ed9fSAtsushi Murai */ 2475240ed1SBrian Somers 25972a1bcfSBrian Somers #include <sys/param.h> 261342caedSBrian Somers #include <netinet/in.h> 271342caedSBrian Somers #include <netinet/in_systm.h> 281342caedSBrian Somers #include <netinet/ip.h> 291fa665f5SBrian Somers #include <sys/un.h> 301ae349f5Scvs2svn 3175240ed1SBrian Somers #include <string.h> 3275240ed1SBrian Somers #include <termios.h> 3375240ed1SBrian Somers 349e8ec64bSBrian Somers #include "ua.h" 3575240ed1SBrian Somers #include "mbuf.h" 3675240ed1SBrian Somers #include "log.h" 3775240ed1SBrian Somers #include "defs.h" 3875240ed1SBrian Somers #include "timer.h" 39af57ed9fSAtsushi Murai #include "fsm.h" 401342caedSBrian Somers #include "iplist.h" 41af57ed9fSAtsushi Murai #include "lqr.h" 42879ed6faSBrian Somers #include "hdlc.h" 431342caedSBrian Somers #include "throughput.h" 441342caedSBrian Somers #include "slcompress.h" 451342caedSBrian Somers #include "ipcp.h" 461342caedSBrian Somers #include "filter.h" 471342caedSBrian Somers #include "descriptor.h" 48af57ed9fSAtsushi Murai #include "lcp.h" 49ed6a16c1SPoul-Henning Kamp #include "ccp.h" 508c07a7b2SBrian Somers #include "link.h" 511342caedSBrian Somers #include "mp.h" 52972a1bcfSBrian Somers #ifndef NORADIUS 53972a1bcfSBrian Somers #include "radius.h" 54972a1bcfSBrian Somers #endif 551342caedSBrian Somers #include "bundle.h" 561342caedSBrian Somers #include "async.h" 5763b73463SBrian Somers #include "physical.h" 581342caedSBrian Somers #include "lcpproto.h" 5975240ed1SBrian Somers 6075240ed1SBrian Somers static void FsmSendConfigReq(struct fsm *); 6175240ed1SBrian Somers static void FsmSendTerminateReq(struct fsm *); 62479508cfSBrian Somers static void FsmInitRestartCounter(struct fsm *, int); 63af57ed9fSAtsushi Murai 642267893fSBrian Somers typedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *); 652267893fSBrian Somers static recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak, 662267893fSBrian Somers FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck, 672267893fSBrian Somers FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq, 682267893fSBrian Somers FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent, 692267893fSBrian Somers FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck; 702267893fSBrian Somers 712267893fSBrian Somers static const struct fsmcodedesc { 722267893fSBrian Somers recvfn *recv; 732267893fSBrian Somers unsigned check_reqid : 1; 742267893fSBrian Somers unsigned inc_reqid : 1; 752267893fSBrian Somers const char *name; 762267893fSBrian Somers } FsmCodes[] = { 772267893fSBrian Somers { FsmRecvConfigReq, 0, 0, "ConfigReq" }, 782267893fSBrian Somers { FsmRecvConfigAck, 1, 1, "ConfigAck" }, 792267893fSBrian Somers { FsmRecvConfigNak, 1, 1, "ConfigNak" }, 802267893fSBrian Somers { FsmRecvConfigRej, 1, 1, "ConfigRej" }, 812267893fSBrian Somers { FsmRecvTermReq, 0, 0, "TerminateReq" }, 822267893fSBrian Somers { FsmRecvTermAck, 1, 1, "TerminateAck" }, 832267893fSBrian Somers { FsmRecvCodeRej, 0, 0, "CodeRej" }, 842267893fSBrian Somers { FsmRecvProtoRej, 0, 0, "ProtocolRej" }, 852267893fSBrian Somers { FsmRecvEchoReq, 0, 0, "EchoRequest" }, 862267893fSBrian Somers { FsmRecvEchoRep, 0, 0, "EchoReply" }, 872267893fSBrian Somers { FsmRecvDiscReq, 0, 0, "DiscardReq" }, 882267893fSBrian Somers { FsmRecvIdent, 0, 0, "Ident" }, 892267893fSBrian Somers { FsmRecvTimeRemain,0, 0, "TimeRemain" }, 902267893fSBrian Somers { FsmRecvResetReq, 0, 0, "ResetReqt" }, 912267893fSBrian Somers { FsmRecvResetAck, 0, 1, "ResetAck" } 922267893fSBrian Somers }; 932267893fSBrian Somers 942267893fSBrian Somers static const char * 952267893fSBrian Somers Code2Nam(u_int code) 962267893fSBrian Somers { 972267893fSBrian Somers if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0]) 982267893fSBrian Somers return "Unknown"; 992267893fSBrian Somers return FsmCodes[code-1].name; 1002267893fSBrian Somers } 1012267893fSBrian Somers 1021e991daaSBrian Somers const char * 1031e991daaSBrian Somers State2Nam(u_int state) 1041e991daaSBrian Somers { 1051e991daaSBrian Somers static const char *StateNames[] = { 106af57ed9fSAtsushi Murai "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", 107927145beSBrian Somers "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", 108af57ed9fSAtsushi Murai }; 109af57ed9fSAtsushi Murai 1101e991daaSBrian Somers if (state >= sizeof StateNames / sizeof StateNames[0]) 1111e991daaSBrian Somers return "unknown"; 1121e991daaSBrian Somers return StateNames[state]; 1131e991daaSBrian Somers } 1141e991daaSBrian Somers 11571144dc5SBrian Somers static void 116b6e82f33SBrian Somers StoppedTimeout(void *v) 11771144dc5SBrian Somers { 118b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 119b6e82f33SBrian Somers 120dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name); 12149b239e0SBrian Somers if (fp->OpenTimer.state == TIMER_RUNNING) { 122dd7e2610SBrian Somers log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n", 123d47dceb8SBrian Somers fp->link->name, fp->name); 124dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 12549b239e0SBrian Somers } 12609206a6fSBrian Somers if (fp->state == ST_STOPPED) 12709206a6fSBrian Somers fsm2initial(fp); 12871144dc5SBrian Somers } 12971144dc5SBrian Somers 130af57ed9fSAtsushi Murai void 1313b0f8d2eSBrian Somers fsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, 132479508cfSBrian Somers int maxcode, int LogLevel, struct bundle *bundle, 1333b0f8d2eSBrian Somers struct link *l, const struct fsm_parent *parent, 1343b0f8d2eSBrian Somers struct fsm_callbacks *fn, const char *timer_names[3]) 135af57ed9fSAtsushi Murai { 136503a7782SBrian Somers fp->name = name; 137503a7782SBrian Somers fp->proto = proto; 1383b0f8d2eSBrian Somers fp->min_code = mincode; 139503a7782SBrian Somers fp->max_code = maxcode; 1403b0f8d2eSBrian Somers fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; 141af57ed9fSAtsushi Murai fp->reqid = 1; 142af57ed9fSAtsushi Murai fp->restart = 1; 143479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = 1; 144503a7782SBrian Somers memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); 145503a7782SBrian Somers memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); 146503a7782SBrian Somers memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); 147503a7782SBrian Somers fp->LogLevel = LogLevel; 1488c07a7b2SBrian Somers fp->link = l; 1497a6f8720SBrian Somers fp->bundle = bundle; 1506d666775SBrian Somers fp->parent = parent; 151503a7782SBrian Somers fp->fn = fn; 1523b0f8d2eSBrian Somers fp->FsmTimer.name = timer_names[0]; 1533b0f8d2eSBrian Somers fp->OpenTimer.name = timer_names[1]; 1543b0f8d2eSBrian Somers fp->StoppedTimer.name = timer_names[2]; 155af57ed9fSAtsushi Murai } 156af57ed9fSAtsushi Murai 15775240ed1SBrian Somers static void 158944f7098SBrian Somers NewState(struct fsm * fp, int new) 159af57ed9fSAtsushi Murai { 160dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", 161d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state), State2Nam(new)); 162cb611434SBrian Somers if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) 163dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 164af57ed9fSAtsushi Murai fp->state = new; 16571144dc5SBrian Somers if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { 166dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 167cb611434SBrian Somers if (new == ST_STOPPED && fp->StoppedTimer.load) { 168dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 169cb611434SBrian Somers fp->StoppedTimer.func = StoppedTimeout; 170cb611434SBrian Somers fp->StoppedTimer.arg = (void *) fp; 171dd7e2610SBrian Somers timer_Start(&fp->StoppedTimer); 17271144dc5SBrian Somers } 17371144dc5SBrian Somers } 174af57ed9fSAtsushi Murai } 175af57ed9fSAtsushi Murai 176af57ed9fSAtsushi Murai void 177dd7e2610SBrian Somers fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count) 178af57ed9fSAtsushi Murai { 179af57ed9fSAtsushi Murai int plen; 180af57ed9fSAtsushi Murai struct fsmheader lh; 181af57ed9fSAtsushi Murai struct mbuf *bp; 182af57ed9fSAtsushi Murai 183dd7e2610SBrian Somers if (log_IsKept(fp->LogLevel)) { 184dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 185d47dceb8SBrian Somers fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 1862267893fSBrian Somers switch (code) { 1872267893fSBrian Somers case CODE_CONFIGREQ: 1882267893fSBrian Somers case CODE_CONFIGACK: 1892267893fSBrian Somers case CODE_CONFIGREJ: 1902267893fSBrian Somers case CODE_CONFIGNAK: 1912267893fSBrian Somers (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL); 1922267893fSBrian Somers if (count < sizeof(struct fsmconfig)) 193dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 1942267893fSBrian Somers break; 1952267893fSBrian Somers } 1962267893fSBrian Somers } 1972267893fSBrian Somers 198af57ed9fSAtsushi Murai plen = sizeof(struct fsmheader) + count; 199af57ed9fSAtsushi Murai lh.code = code; 200af57ed9fSAtsushi Murai lh.id = id; 201af57ed9fSAtsushi Murai lh.length = htons(plen); 202dd7e2610SBrian Somers bp = mbuf_Alloc(plen, MB_FSM); 20375240ed1SBrian Somers memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 204af57ed9fSAtsushi Murai if (count) 20575240ed1SBrian Somers memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 206dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "fsm_Output", bp); 207dd7e2610SBrian Somers hdlc_Output(fp->link, PRI_LINK, fp->proto, bp); 208af57ed9fSAtsushi Murai } 209af57ed9fSAtsushi Murai 21049b239e0SBrian Somers static void 21149b239e0SBrian Somers FsmOpenNow(void *v) 21249b239e0SBrian Somers { 21349b239e0SBrian Somers struct fsm *fp = (struct fsm *)v; 21449b239e0SBrian Somers 215dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 21649b239e0SBrian Somers if (fp->state <= ST_STOPPED) { 2173a2e4f62SBrian Somers if (fp->state != ST_STARTING) { 2183a2e4f62SBrian Somers /* 2193a2e4f62SBrian Somers * In practice, we're only here in ST_STOPPED (when delaying the 2203a2e4f62SBrian Somers * first config request) or ST_CLOSED (when openmode == 0). 2213a2e4f62SBrian Somers * 2223a2e4f62SBrian Somers * The ST_STOPPED bit is breaking the RFC already :-( 2233a2e4f62SBrian Somers * 2243a2e4f62SBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 2253a2e4f62SBrian Somers * required for an Open event when state == Closed, but the RFC 2263a2e4f62SBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 2273a2e4f62SBrian Somers * ie, Initial gets an `Up' event, Closing gets a RTA etc. 2283a2e4f62SBrian Somers */ 2293a2e4f62SBrian Somers (*fp->fn->LayerStart)(fp); 2303a2e4f62SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 2313a2e4f62SBrian Somers } 232479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 23349b239e0SBrian Somers FsmSendConfigReq(fp); 23449b239e0SBrian Somers NewState(fp, ST_REQSENT); 23549b239e0SBrian Somers } 23649b239e0SBrian Somers } 23749b239e0SBrian Somers 238af57ed9fSAtsushi Murai void 239dd7e2610SBrian Somers fsm_Open(struct fsm * fp) 240af57ed9fSAtsushi Murai { 241af57ed9fSAtsushi Murai switch (fp->state) { 242af57ed9fSAtsushi Murai case ST_INITIAL: 243af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 2446d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2456d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 246af57ed9fSAtsushi Murai break; 247af57ed9fSAtsushi Murai case ST_CLOSED: 248af57ed9fSAtsushi Murai if (fp->open_mode == OPEN_PASSIVE) { 2493a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 25049b239e0SBrian Somers } else if (fp->open_mode > 0) { 25149b239e0SBrian Somers if (fp->open_mode > 1) 252dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 253d47dceb8SBrian Somers fp->link->name, fp->open_mode); 2543a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 255dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 25649b239e0SBrian Somers fp->OpenTimer.load = fp->open_mode * SECTICKS; 25749b239e0SBrian Somers fp->OpenTimer.func = FsmOpenNow; 25849b239e0SBrian Somers fp->OpenTimer.arg = (void *)fp; 259dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 26049b239e0SBrian Somers } else 26149b239e0SBrian Somers FsmOpenNow(fp); 262af57ed9fSAtsushi Murai break; 263af57ed9fSAtsushi Murai case ST_STOPPED: /* XXX: restart option */ 264af57ed9fSAtsushi Murai case ST_REQSENT: 265af57ed9fSAtsushi Murai case ST_ACKRCVD: 266af57ed9fSAtsushi Murai case ST_ACKSENT: 267af57ed9fSAtsushi Murai case ST_OPENED: /* XXX: restart option */ 268af57ed9fSAtsushi Murai break; 269af57ed9fSAtsushi Murai case ST_CLOSING: /* XXX: restart option */ 270af57ed9fSAtsushi Murai case ST_STOPPING: /* XXX: restart option */ 271af57ed9fSAtsushi Murai NewState(fp, ST_STOPPING); 272af57ed9fSAtsushi Murai break; 273af57ed9fSAtsushi Murai } 274af57ed9fSAtsushi Murai } 275af57ed9fSAtsushi Murai 276af57ed9fSAtsushi Murai void 277dd7e2610SBrian Somers fsm_Up(struct fsm * fp) 278af57ed9fSAtsushi Murai { 279af57ed9fSAtsushi Murai switch (fp->state) { 280af57ed9fSAtsushi Murai case ST_INITIAL: 281dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 2821fa665f5SBrian Somers fp->link->name); 283af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 284af57ed9fSAtsushi Murai break; 285af57ed9fSAtsushi Murai case ST_STARTING: 286479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 287af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 288af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 289af57ed9fSAtsushi Murai break; 290af57ed9fSAtsushi Murai default: 291dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 292d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 293af57ed9fSAtsushi Murai break; 294af57ed9fSAtsushi Murai } 295af57ed9fSAtsushi Murai } 296af57ed9fSAtsushi Murai 297af57ed9fSAtsushi Murai void 298dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 299af57ed9fSAtsushi Murai { 300af57ed9fSAtsushi Murai switch (fp->state) { 301af57ed9fSAtsushi Murai case ST_CLOSED: 302af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 303af57ed9fSAtsushi Murai break; 304455aabc3SBrian Somers case ST_CLOSING: 3058a8d9927SBrian Somers /* This TLF contradicts the RFC (1661), which ``misses it out'' ! */ 3066d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 307455aabc3SBrian Somers NewState(fp, ST_INITIAL); 3086d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 309455aabc3SBrian Somers break; 310af57ed9fSAtsushi Murai case ST_STOPPED: 311455aabc3SBrian Somers NewState(fp, ST_STARTING); 3126d666775SBrian Somers (*fp->fn->LayerStart)(fp); 3136d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 314455aabc3SBrian Somers break; 315af57ed9fSAtsushi Murai case ST_STOPPING: 316af57ed9fSAtsushi Murai case ST_REQSENT: 317af57ed9fSAtsushi Murai case ST_ACKRCVD: 318af57ed9fSAtsushi Murai case ST_ACKSENT: 319af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 320af57ed9fSAtsushi Murai break; 321af57ed9fSAtsushi Murai case ST_OPENED: 3226d666775SBrian Somers (*fp->fn->LayerDown)(fp); 323af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 3246d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 325af57ed9fSAtsushi Murai break; 326af57ed9fSAtsushi Murai } 327af57ed9fSAtsushi Murai } 328af57ed9fSAtsushi Murai 329af57ed9fSAtsushi Murai void 330dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 331af57ed9fSAtsushi Murai { 332af57ed9fSAtsushi Murai switch (fp->state) { 333af57ed9fSAtsushi Murai case ST_STARTING: 3346d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 335af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 3366d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 337af57ed9fSAtsushi Murai break; 338af57ed9fSAtsushi Murai case ST_STOPPED: 339af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 340af57ed9fSAtsushi Murai break; 341af57ed9fSAtsushi Murai case ST_STOPPING: 342af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 343af57ed9fSAtsushi Murai break; 344af57ed9fSAtsushi Murai case ST_OPENED: 3456d666775SBrian Somers (*fp->fn->LayerDown)(fp); 346479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 347455aabc3SBrian Somers FsmSendTerminateReq(fp); 348455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3496d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 350455aabc3SBrian Somers break; 351af57ed9fSAtsushi Murai case ST_REQSENT: 352af57ed9fSAtsushi Murai case ST_ACKRCVD: 353af57ed9fSAtsushi Murai case ST_ACKSENT: 354479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 355af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 356af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 357af57ed9fSAtsushi Murai break; 358af57ed9fSAtsushi Murai } 359af57ed9fSAtsushi Murai } 360af57ed9fSAtsushi Murai 361af57ed9fSAtsushi Murai /* 362af57ed9fSAtsushi Murai * Send functions 363af57ed9fSAtsushi Murai */ 36475240ed1SBrian Somers static void 365944f7098SBrian Somers FsmSendConfigReq(struct fsm * fp) 366af57ed9fSAtsushi Murai { 367479508cfSBrian Somers if (fp->more.reqs-- > 0 && fp->restart-- > 0) { 36883d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 369dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 370af57ed9fSAtsushi Murai } else { 371479508cfSBrian Somers if (fp->more.reqs < 0) 372479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REQs sent - abandoning " 373479508cfSBrian Somers "negotiation\n", fp->link->name, fp->name); 374dd7e2610SBrian Somers fsm_Close(fp); 375af57ed9fSAtsushi Murai } 376af57ed9fSAtsushi Murai } 377af57ed9fSAtsushi Murai 37875240ed1SBrian Somers static void 379944f7098SBrian Somers FsmSendTerminateReq(struct fsm *fp) 380af57ed9fSAtsushi Murai { 381dd7e2610SBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0); 3822267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 383dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 384af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 385af57ed9fSAtsushi Murai } 386af57ed9fSAtsushi Murai 387af57ed9fSAtsushi Murai /* 388af57ed9fSAtsushi Murai * Timeout actions 389af57ed9fSAtsushi Murai */ 39075240ed1SBrian Somers static void 391b6e82f33SBrian Somers FsmTimeout(void *v) 392af57ed9fSAtsushi Murai { 393b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 394b6e82f33SBrian Somers 395af57ed9fSAtsushi Murai if (fp->restart) { 396af57ed9fSAtsushi Murai switch (fp->state) { 397af57ed9fSAtsushi Murai case ST_CLOSING: 398af57ed9fSAtsushi Murai case ST_STOPPING: 399af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 400af57ed9fSAtsushi Murai break; 401af57ed9fSAtsushi Murai case ST_REQSENT: 402af57ed9fSAtsushi Murai case ST_ACKSENT: 403af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 404af57ed9fSAtsushi Murai break; 405af57ed9fSAtsushi Murai case ST_ACKRCVD: 406af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 407af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 408af57ed9fSAtsushi Murai break; 409af57ed9fSAtsushi Murai } 410dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 411af57ed9fSAtsushi Murai } else { 412af57ed9fSAtsushi Murai switch (fp->state) { 413af57ed9fSAtsushi Murai case ST_CLOSING: 4146d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 415af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 4166d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 417af57ed9fSAtsushi Murai break; 418af57ed9fSAtsushi Murai case ST_STOPPING: 4196d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 420af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4216d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 422af57ed9fSAtsushi Murai break; 423af57ed9fSAtsushi Murai case ST_REQSENT: /* XXX: 3p */ 424af57ed9fSAtsushi Murai case ST_ACKSENT: 425af57ed9fSAtsushi Murai case ST_ACKRCVD: 4266d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 427af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4286d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 429af57ed9fSAtsushi Murai break; 430af57ed9fSAtsushi Murai } 431af57ed9fSAtsushi Murai } 432af57ed9fSAtsushi Murai } 433af57ed9fSAtsushi Murai 43475240ed1SBrian Somers static void 435479508cfSBrian Somers FsmInitRestartCounter(struct fsm *fp, int what) 436af57ed9fSAtsushi Murai { 437dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 438af57ed9fSAtsushi Murai fp->FsmTimer.func = FsmTimeout; 439af57ed9fSAtsushi Murai fp->FsmTimer.arg = (void *)fp; 440479508cfSBrian Somers (*fp->fn->InitRestartCounter)(fp, what); 441af57ed9fSAtsushi Murai } 442af57ed9fSAtsushi Murai 443af57ed9fSAtsushi Murai /* 444af57ed9fSAtsushi Murai * Actions when receive packets 445af57ed9fSAtsushi Murai */ 44675240ed1SBrian Somers static void 447944f7098SBrian Somers FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 448944f7098SBrian Somers /* RCR */ 449af57ed9fSAtsushi Murai { 45030c2f2ffSBrian Somers struct fsm_decode dec; 45153c9f6c0SAtsushi Murai int plen, flen; 452af57ed9fSAtsushi Murai int ackaction = 0; 453af57ed9fSAtsushi Murai 454dd7e2610SBrian Somers plen = mbuf_Length(bp); 45570ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 45653c9f6c0SAtsushi Murai if (plen < flen) { 457a33b2ef7SBrian Somers log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 458d47dceb8SBrian Somers fp->link->name, plen, flen); 459dd7e2610SBrian Somers mbuf_Free(bp); 460af57ed9fSAtsushi Murai return; 461af57ed9fSAtsushi Murai } 462af57ed9fSAtsushi Murai 463af57ed9fSAtsushi Murai /* 464af57ed9fSAtsushi Murai * Check and process easy case 465af57ed9fSAtsushi Murai */ 466af57ed9fSAtsushi Murai switch (fp->state) { 467af57ed9fSAtsushi Murai case ST_INITIAL: 46806337856SBrian Somers if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 46906337856SBrian Somers /* 47006337856SBrian Somers * ccp_SetOpenMode() leaves us in initial if we're disabling 47106337856SBrian Somers * & denying everything. This is a bit smelly, we know that 47206337856SBrian Somers * ``bp'' really has ``fsmheader'' in front of it, and CCP_PROTO 47306337856SBrian Somers * in front of that. CCP_PROTO isn't compressed either 'cos it 47406337856SBrian Somers * doesn't begin with 0x00.... 47506337856SBrian Somers */ 47606337856SBrian Somers bp->offset -= sizeof(struct fsmheader) + 2; 47706337856SBrian Somers bp->cnt += sizeof(struct fsmheader) + 2; 47806337856SBrian Somers lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->cnt); 47906337856SBrian Somers mbuf_Free(bp); 48006337856SBrian Somers return; 48106337856SBrian Somers } 48206337856SBrian Somers /* Drop through */ 483af57ed9fSAtsushi Murai case ST_STARTING: 484dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 485d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 486dd7e2610SBrian Somers mbuf_Free(bp); 487af57ed9fSAtsushi Murai return; 488af57ed9fSAtsushi Murai case ST_CLOSED: 4892267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 490dd7e2610SBrian Somers mbuf_Free(bp); 491af57ed9fSAtsushi Murai return; 492af57ed9fSAtsushi Murai case ST_CLOSING: 493dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 494d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 495a9c503afSBrian Somers case ST_STOPPING: 496dd7e2610SBrian Somers mbuf_Free(bp); 497af57ed9fSAtsushi Murai return; 49868a0e171SBrian Somers case ST_OPENED: 49968a0e171SBrian Somers (*fp->fn->LayerDown)(fp); 50068a0e171SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 50168a0e171SBrian Somers break; 502af57ed9fSAtsushi Murai } 503af57ed9fSAtsushi Murai 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) 525dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej); 52630c2f2ffSBrian Somers if (dec.nakend != dec.nak) 527dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak); 528af57ed9fSAtsushi Murai if (ackaction) 529dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack); 530af57ed9fSAtsushi Murai 531af57ed9fSAtsushi Murai switch (fp->state) { 532455aabc3SBrian Somers case ST_STOPPED: 533479508cfSBrian Somers /* 534479508cfSBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 535479508cfSBrian Somers * required for a RCR when state == ST_STOPPED, but the RFC 536479508cfSBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 537479508cfSBrian Somers */ 538479508cfSBrian Somers (*fp->fn->LayerStart)(fp); 539479508cfSBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 540479508cfSBrian Somers /* Fall through */ 541479508cfSBrian Somers 542479508cfSBrian Somers case ST_OPENED: 543af57ed9fSAtsushi Murai if (ackaction) 544af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 545af57ed9fSAtsushi Murai else 546af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 547af57ed9fSAtsushi Murai break; 548af57ed9fSAtsushi Murai case ST_REQSENT: 549af57ed9fSAtsushi Murai if (ackaction) 550af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 551af57ed9fSAtsushi Murai break; 552af57ed9fSAtsushi Murai case ST_ACKRCVD: 553af57ed9fSAtsushi Murai if (ackaction) { 554af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5556f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5566d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5576f384573SBrian Somers else { 5586f384573SBrian Somers (*fp->fn->LayerDown)(fp); 559479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 5606f384573SBrian Somers FsmSendTerminateReq(fp); 5616f384573SBrian Somers NewState(fp, ST_CLOSING); 5626f384573SBrian Somers } 563af57ed9fSAtsushi Murai } 564af57ed9fSAtsushi Murai break; 565af57ed9fSAtsushi Murai case ST_ACKSENT: 566af57ed9fSAtsushi Murai if (!ackaction) 567af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 568af57ed9fSAtsushi Murai break; 569af57ed9fSAtsushi Murai } 570dd7e2610SBrian Somers mbuf_Free(bp); 571479508cfSBrian Somers 572479508cfSBrian Somers if (dec.rejend != dec.rej && --fp->more.rejs <= 0) { 573479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REJs sent - abandoning negotiation\n", 574479508cfSBrian Somers fp->link->name, fp->name); 575479508cfSBrian Somers fsm_Close(fp); 576479508cfSBrian Somers } 577479508cfSBrian Somers 578479508cfSBrian Somers if (dec.nakend != dec.nak && --fp->more.naks <= 0) { 579479508cfSBrian Somers fsm_Close(fp); 580479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s NAKs sent - abandoning negotiation\n", 581479508cfSBrian Somers fp->link->name, fp->name); 582479508cfSBrian Somers fsm_Close(fp); 583479508cfSBrian Somers } 584af57ed9fSAtsushi Murai } 585af57ed9fSAtsushi Murai 58675240ed1SBrian Somers static void 587944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 588944f7098SBrian Somers /* RCA */ 589af57ed9fSAtsushi Murai { 590af57ed9fSAtsushi Murai switch (fp->state) { 591af57ed9fSAtsushi Murai case ST_CLOSED: 592af57ed9fSAtsushi Murai case ST_STOPPED: 5932267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 594af57ed9fSAtsushi Murai break; 595af57ed9fSAtsushi Murai case ST_CLOSING: 596af57ed9fSAtsushi Murai case ST_STOPPING: 597af57ed9fSAtsushi Murai break; 598af57ed9fSAtsushi Murai case ST_REQSENT: 599479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 600af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 601af57ed9fSAtsushi Murai break; 602af57ed9fSAtsushi Murai case ST_ACKRCVD: 603af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 604af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 605af57ed9fSAtsushi Murai break; 606af57ed9fSAtsushi Murai case ST_ACKSENT: 607479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 608af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 6096f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 6106d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 6116f384573SBrian Somers else { 6126f384573SBrian Somers (*fp->fn->LayerDown)(fp); 613479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 6146f384573SBrian Somers FsmSendTerminateReq(fp); 6156f384573SBrian Somers NewState(fp, ST_CLOSING); 6166f384573SBrian Somers } 617af57ed9fSAtsushi Murai break; 618af57ed9fSAtsushi Murai case ST_OPENED: 6196d666775SBrian Somers (*fp->fn->LayerDown)(fp); 620af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 621af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 6226d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 623af57ed9fSAtsushi Murai break; 624af57ed9fSAtsushi Murai } 625dd7e2610SBrian Somers mbuf_Free(bp); 626af57ed9fSAtsushi Murai } 627af57ed9fSAtsushi Murai 62875240ed1SBrian Somers static void 629944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 630944f7098SBrian Somers /* RCN */ 631af57ed9fSAtsushi Murai { 63230c2f2ffSBrian Somers struct fsm_decode dec; 63353c9f6c0SAtsushi Murai int plen, flen; 634af57ed9fSAtsushi Murai 635dd7e2610SBrian Somers plen = mbuf_Length(bp); 63670ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 63753c9f6c0SAtsushi Murai if (plen < flen) { 638dd7e2610SBrian Somers mbuf_Free(bp); 639af57ed9fSAtsushi Murai return; 640af57ed9fSAtsushi Murai } 641af57ed9fSAtsushi Murai 642af57ed9fSAtsushi Murai /* 643af57ed9fSAtsushi Murai * Check and process easy case 644af57ed9fSAtsushi Murai */ 645af57ed9fSAtsushi Murai switch (fp->state) { 646af57ed9fSAtsushi Murai case ST_INITIAL: 647af57ed9fSAtsushi Murai case ST_STARTING: 648dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 649d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 650dd7e2610SBrian Somers mbuf_Free(bp); 651af57ed9fSAtsushi Murai return; 652af57ed9fSAtsushi Murai case ST_CLOSED: 653af57ed9fSAtsushi Murai case ST_STOPPED: 6542267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 655dd7e2610SBrian Somers mbuf_Free(bp); 656af57ed9fSAtsushi Murai return; 657af57ed9fSAtsushi Murai case ST_CLOSING: 658af57ed9fSAtsushi Murai case ST_STOPPING: 659dd7e2610SBrian Somers mbuf_Free(bp); 660af57ed9fSAtsushi Murai return; 661af57ed9fSAtsushi Murai } 662af57ed9fSAtsushi Murai 66330c2f2ffSBrian Somers dec.ackend = dec.ack; 66430c2f2ffSBrian Somers dec.nakend = dec.nak; 66530c2f2ffSBrian Somers dec.rejend = dec.rej; 66630c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); 6672267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 668dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 669af57ed9fSAtsushi Murai 670af57ed9fSAtsushi Murai switch (fp->state) { 671af57ed9fSAtsushi Murai case ST_REQSENT: 672af57ed9fSAtsushi Murai case ST_ACKSENT: 673479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 674af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 675af57ed9fSAtsushi Murai break; 676af57ed9fSAtsushi Murai case ST_OPENED: 6776d666775SBrian Somers (*fp->fn->LayerDown)(fp); 678455aabc3SBrian Somers FsmSendConfigReq(fp); 679455aabc3SBrian Somers NewState(fp, ST_REQSENT); 6806d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 681455aabc3SBrian Somers break; 682af57ed9fSAtsushi Murai case ST_ACKRCVD: 683af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 684af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 685af57ed9fSAtsushi Murai break; 686af57ed9fSAtsushi Murai } 687af57ed9fSAtsushi Murai 688dd7e2610SBrian Somers mbuf_Free(bp); 689af57ed9fSAtsushi Murai } 690af57ed9fSAtsushi Murai 69175240ed1SBrian Somers static void 692944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 693944f7098SBrian Somers /* RTR */ 694af57ed9fSAtsushi Murai { 695af57ed9fSAtsushi Murai switch (fp->state) { 696af57ed9fSAtsushi Murai case ST_INITIAL: 697af57ed9fSAtsushi Murai case ST_STARTING: 698dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 699d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 700af57ed9fSAtsushi Murai break; 701af57ed9fSAtsushi Murai case ST_CLOSED: 702af57ed9fSAtsushi Murai case ST_STOPPED: 703af57ed9fSAtsushi Murai case ST_CLOSING: 704af57ed9fSAtsushi Murai case ST_STOPPING: 705af57ed9fSAtsushi Murai case ST_REQSENT: 7062267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 707af57ed9fSAtsushi Murai break; 708af57ed9fSAtsushi Murai case ST_ACKRCVD: 709af57ed9fSAtsushi Murai case ST_ACKSENT: 7102267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 711af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 712af57ed9fSAtsushi Murai break; 713af57ed9fSAtsushi Murai case ST_OPENED: 7146d666775SBrian Somers (*fp->fn->LayerDown)(fp); 7152267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 716479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 717dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 7188f2fa0eeSBrian Somers fp->restart = 0; 7198f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 7206d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 721479508cfSBrian Somers /* A delayed ST_STOPPED is now scheduled */ 722af57ed9fSAtsushi Murai break; 723af57ed9fSAtsushi Murai } 724dd7e2610SBrian Somers mbuf_Free(bp); 725af57ed9fSAtsushi Murai } 726af57ed9fSAtsushi Murai 72775240ed1SBrian Somers static void 728944f7098SBrian Somers FsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 729944f7098SBrian Somers /* RTA */ 730af57ed9fSAtsushi Murai { 731af57ed9fSAtsushi Murai switch (fp->state) { 732af57ed9fSAtsushi Murai case ST_CLOSING: 7336d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 734af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 7356d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 736af57ed9fSAtsushi Murai break; 737af57ed9fSAtsushi Murai case ST_STOPPING: 7386d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 739af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 7406d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 741af57ed9fSAtsushi Murai break; 742af57ed9fSAtsushi Murai case ST_ACKRCVD: 743af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 744af57ed9fSAtsushi Murai break; 745af57ed9fSAtsushi Murai case ST_OPENED: 7466d666775SBrian Somers (*fp->fn->LayerDown)(fp); 747af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 748af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 7496d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 750af57ed9fSAtsushi Murai break; 751af57ed9fSAtsushi Murai } 752dd7e2610SBrian Somers mbuf_Free(bp); 753af57ed9fSAtsushi Murai } 754af57ed9fSAtsushi Murai 75575240ed1SBrian Somers static void 756944f7098SBrian Somers FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 757944f7098SBrian Somers /* RCJ */ 758af57ed9fSAtsushi Murai { 75930c2f2ffSBrian Somers struct fsm_decode dec; 76053c9f6c0SAtsushi Murai int plen, flen; 761af57ed9fSAtsushi Murai 762dd7e2610SBrian Somers plen = mbuf_Length(bp); 76370ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 76453c9f6c0SAtsushi Murai if (plen < flen) { 765dd7e2610SBrian Somers mbuf_Free(bp); 766af57ed9fSAtsushi Murai return; 767af57ed9fSAtsushi Murai } 768af57ed9fSAtsushi Murai 769af57ed9fSAtsushi Murai /* 770af57ed9fSAtsushi Murai * Check and process easy case 771af57ed9fSAtsushi Murai */ 772af57ed9fSAtsushi Murai switch (fp->state) { 773af57ed9fSAtsushi Murai case ST_INITIAL: 774af57ed9fSAtsushi Murai case ST_STARTING: 775dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 776d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 777dd7e2610SBrian Somers mbuf_Free(bp); 778af57ed9fSAtsushi Murai return; 779af57ed9fSAtsushi Murai case ST_CLOSED: 780af57ed9fSAtsushi Murai case ST_STOPPED: 7812267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 782dd7e2610SBrian Somers mbuf_Free(bp); 783af57ed9fSAtsushi Murai return; 784af57ed9fSAtsushi Murai case ST_CLOSING: 785af57ed9fSAtsushi Murai case ST_STOPPING: 786dd7e2610SBrian Somers mbuf_Free(bp); 787af57ed9fSAtsushi Murai return; 788af57ed9fSAtsushi Murai } 789af57ed9fSAtsushi Murai 79030c2f2ffSBrian Somers dec.ackend = dec.ack; 79130c2f2ffSBrian Somers dec.nakend = dec.nak; 79230c2f2ffSBrian Somers dec.rejend = dec.rej; 79330c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); 7942267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 795dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 796af57ed9fSAtsushi Murai 797af57ed9fSAtsushi Murai switch (fp->state) { 798af57ed9fSAtsushi Murai case ST_REQSENT: 799af57ed9fSAtsushi Murai case ST_ACKSENT: 800479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 801af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 802af57ed9fSAtsushi Murai break; 803af57ed9fSAtsushi Murai case ST_OPENED: 8046d666775SBrian Somers (*fp->fn->LayerDown)(fp); 805455aabc3SBrian Somers FsmSendConfigReq(fp); 806455aabc3SBrian Somers NewState(fp, ST_REQSENT); 8076d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 808455aabc3SBrian Somers break; 809af57ed9fSAtsushi Murai case ST_ACKRCVD: 810af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 811af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 812af57ed9fSAtsushi Murai break; 813af57ed9fSAtsushi Murai } 814dd7e2610SBrian Somers mbuf_Free(bp); 815af57ed9fSAtsushi Murai } 816af57ed9fSAtsushi Murai 81775240ed1SBrian Somers static void 818944f7098SBrian Somers FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 819af57ed9fSAtsushi Murai { 820dd7e2610SBrian Somers mbuf_Free(bp); 821af57ed9fSAtsushi Murai } 822af57ed9fSAtsushi Murai 82375240ed1SBrian Somers static void 824944f7098SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 825af57ed9fSAtsushi Murai { 8268c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 827af57ed9fSAtsushi Murai u_short *sp, proto; 828af57ed9fSAtsushi Murai 829af57ed9fSAtsushi Murai sp = (u_short *)MBUF_CTOP(bp); 830af57ed9fSAtsushi Murai proto = ntohs(*sp); 831dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 832d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 833af57ed9fSAtsushi Murai 834af57ed9fSAtsushi Murai switch (proto) { 835af57ed9fSAtsushi Murai case PROTO_LQR: 8368c07a7b2SBrian Somers if (p) 837dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 8388c07a7b2SBrian Somers else 839dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 840d47dceb8SBrian Somers fp->link->name); 841af57ed9fSAtsushi Murai break; 842af57ed9fSAtsushi Murai case PROTO_CCP: 843dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 8443b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 8458a8d9927SBrian Somers /* Despite the RFC (1661), don't do an out-of-place TLF */ 8468a8d9927SBrian Somers /* (*fp->fn->LayerFinish)(fp); */ 847af57ed9fSAtsushi Murai switch (fp->state) { 848af57ed9fSAtsushi Murai case ST_CLOSED: 849af57ed9fSAtsushi Murai case ST_CLOSING: 850af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 851af57ed9fSAtsushi Murai default: 852af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 853af57ed9fSAtsushi Murai break; 854af57ed9fSAtsushi Murai } 8558a8d9927SBrian Somers /* See above */ 8568a8d9927SBrian Somers /* (*fp->parent->LayerFinish)(fp->parent->object, fp); */ 857dc0fdb6bSBrian Somers } 8581ae349f5Scvs2svn break; 859673903ecSBrian Somers case PROTO_MP: 860673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 861673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 862673903ecSBrian Somers 863673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 864dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 865d47dceb8SBrian Somers fp->link->name); 866dd7e2610SBrian Somers fsm_Close(fp); 867673903ecSBrian Somers } 868673903ecSBrian Somers } 869af57ed9fSAtsushi Murai break; 870af57ed9fSAtsushi Murai } 871dd7e2610SBrian Somers mbuf_Free(bp); 872af57ed9fSAtsushi Murai } 873af57ed9fSAtsushi Murai 87475240ed1SBrian Somers static void 875944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 876af57ed9fSAtsushi Murai { 877dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 878af57ed9fSAtsushi Murai u_char *cp; 879fe3125a0SBrian Somers u_int32_t magic; 880af57ed9fSAtsushi Murai 881dc0fdb6bSBrian Somers if (lcp) { 882af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 8839e8ec64bSBrian Somers ua_ntohl(cp, &magic); 884dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 885dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: Error: His magic is bad!!\n", 886d47dceb8SBrian Somers fp->link->name); 887af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 888af57ed9fSAtsushi Murai } 889af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 8909e8ec64bSBrian Somers ua_htonl(&lcp->want_magic, cp); /* local magic */ 891dd7e2610SBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, mbuf_Length(bp)); 892af57ed9fSAtsushi Murai } 893dc0fdb6bSBrian Somers } 894dd7e2610SBrian Somers mbuf_Free(bp); 895af57ed9fSAtsushi Murai } 896af57ed9fSAtsushi Murai 89775240ed1SBrian Somers static void 898944f7098SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 899af57ed9fSAtsushi Murai { 900dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 901fe3125a0SBrian Somers u_int32_t magic; 902af57ed9fSAtsushi Murai 903dc0fdb6bSBrian Somers if (lcp) { 9049e8ec64bSBrian Somers ua_ntohl(MBUF_CTOP(bp), &magic); 905879ed6faSBrian Somers /* Tolerate echo replies with either magic number */ 906dc0fdb6bSBrian Somers if (magic != 0 && magic != lcp->his_magic && magic != lcp->want_magic) { 907dd7e2610SBrian Somers log_Printf(LogWARN, 908d47dceb8SBrian Somers "%s: RecvEchoRep: Bad magic: expected 0x%08x, got: 0x%08x\n", 909d47dceb8SBrian Somers fp->link->name, lcp->his_magic, magic); 91085c59f05SJoerg Wunsch /* 911fe3125a0SBrian Somers * XXX: We should send terminate request. But poor implementations may 912fe3125a0SBrian Somers * die as a result. 913af57ed9fSAtsushi Murai */ 914af57ed9fSAtsushi Murai } 915dd7e2610SBrian Somers lqr_RecvEcho(fp, bp); 916dc0fdb6bSBrian Somers } 917dd7e2610SBrian Somers mbuf_Free(bp); 918af57ed9fSAtsushi Murai } 919af57ed9fSAtsushi Murai 92075240ed1SBrian Somers static void 921944f7098SBrian Somers FsmRecvDiscReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 922af57ed9fSAtsushi Murai { 923dd7e2610SBrian Somers mbuf_Free(bp); 924af57ed9fSAtsushi Murai } 925af57ed9fSAtsushi Murai 92675240ed1SBrian Somers static void 927944f7098SBrian Somers FsmRecvIdent(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 928af57ed9fSAtsushi Murai { 929dd7e2610SBrian Somers mbuf_Free(bp); 930af57ed9fSAtsushi Murai } 931af57ed9fSAtsushi Murai 93275240ed1SBrian Somers static void 933944f7098SBrian Somers FsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 934af57ed9fSAtsushi Murai { 935dd7e2610SBrian Somers mbuf_Free(bp); 936af57ed9fSAtsushi Murai } 937af57ed9fSAtsushi Murai 93875240ed1SBrian Somers static void 939944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 940af57ed9fSAtsushi Murai { 941503a7782SBrian Somers (*fp->fn->RecvResetReq)(fp); 94298baf7c8SBrian Somers /* 94398baf7c8SBrian Somers * All sendable compressed packets are queued in the PRI_NORMAL modem 94498baf7c8SBrian Somers * output queue.... dump 'em to the priority queue so that they arrive 94598baf7c8SBrian Somers * at the peer before our ResetAck. 94698baf7c8SBrian Somers */ 9478c07a7b2SBrian Somers link_SequenceQueue(fp->link); 948dd7e2610SBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0); 949dd7e2610SBrian Somers mbuf_Free(bp); 950af57ed9fSAtsushi Murai } 951af57ed9fSAtsushi Murai 95275240ed1SBrian Somers static void 953944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 954af57ed9fSAtsushi Murai { 955503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 956dd7e2610SBrian Somers mbuf_Free(bp); 957af57ed9fSAtsushi Murai } 958af57ed9fSAtsushi Murai 959af57ed9fSAtsushi Murai void 960dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 961af57ed9fSAtsushi Murai { 962af57ed9fSAtsushi Murai int len; 963af57ed9fSAtsushi Murai struct fsmheader *lhp; 9640053cc58SBrian Somers const struct fsmcodedesc *codep; 965af57ed9fSAtsushi Murai 966dd7e2610SBrian Somers len = mbuf_Length(bp); 967af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 968dd7e2610SBrian Somers mbuf_Free(bp); 969af57ed9fSAtsushi Murai return; 970af57ed9fSAtsushi Murai } 971af57ed9fSAtsushi Murai lhp = (struct fsmheader *) MBUF_CTOP(bp); 9723b0f8d2eSBrian Somers if (lhp->code < fp->min_code || lhp->code > fp->max_code || 9737308ec68SBrian Somers lhp->code > sizeof FsmCodes / sizeof *FsmCodes) { 9743b0f8d2eSBrian Somers /* 9753b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 9763b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 9773b0f8d2eSBrian Somers */ 9783b0f8d2eSBrian Somers static u_char id; 979d93d3a9cSBrian Somers 980dd7e2610SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->cnt); 981dd7e2610SBrian Somers mbuf_Free(bp); 982af57ed9fSAtsushi Murai return; 983af57ed9fSAtsushi Murai } 984af57ed9fSAtsushi Murai bp->offset += sizeof(struct fsmheader); 985af57ed9fSAtsushi Murai bp->cnt -= sizeof(struct fsmheader); 986af57ed9fSAtsushi Murai 987af57ed9fSAtsushi Murai codep = FsmCodes + lhp->code - 1; 9881342caedSBrian Somers if (lhp->id != fp->reqid && codep->check_reqid && 9891342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 990dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 991d47dceb8SBrian Somers fp->link->name, codep->name, lhp->id, fp->reqid); 9922267893fSBrian Somers return; 9932267893fSBrian Somers } 9942267893fSBrian Somers 995dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 996d47dceb8SBrian Somers fp->link->name, codep->name, lhp->id, State2Nam(fp->state)); 9972267893fSBrian Somers 998dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 999dd7e2610SBrian Somers mbuf_Log(); 10002267893fSBrian Somers 10012267893fSBrian Somers if (codep->inc_reqid && (lhp->id == fp->reqid || 10021342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 10032267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 10042267893fSBrian Somers 10051342caedSBrian Somers (*codep->recv)(fp, lhp, bp); 10062267893fSBrian Somers 1007dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 1008dd7e2610SBrian Somers mbuf_Log(); 10091ae349f5Scvs2svn } 1010503a7782SBrian Somers 1011503a7782SBrian Somers void 1012dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 1013503a7782SBrian Somers { 1014dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 1015d47dceb8SBrian Somers fp->link->name); 1016503a7782SBrian Somers } 1017503a7782SBrian Somers 1018503a7782SBrian Somers void 1019dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 1020503a7782SBrian Somers { 1021dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 1022d47dceb8SBrian Somers fp->link->name); 1023af57ed9fSAtsushi Murai } 102409206a6fSBrian Somers 102509206a6fSBrian Somers void 1026897f9429SBrian Somers fsm_Reopen(struct fsm *fp) 1027897f9429SBrian Somers { 1028897f9429SBrian Somers if (fp->state == ST_OPENED) { 1029897f9429SBrian Somers (*fp->fn->LayerDown)(fp); 1030479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 1031897f9429SBrian Somers FsmSendConfigReq(fp); 1032897f9429SBrian Somers NewState(fp, ST_REQSENT); 1033897f9429SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 1034897f9429SBrian Somers } 1035897f9429SBrian Somers } 1036897f9429SBrian Somers 1037897f9429SBrian Somers void 103809206a6fSBrian Somers fsm2initial(struct fsm *fp) 103909206a6fSBrian Somers { 1040479508cfSBrian Somers timer_Stop(&fp->FsmTimer); 1041479508cfSBrian Somers timer_Stop(&fp->OpenTimer); 1042479508cfSBrian Somers timer_Stop(&fp->StoppedTimer); 104309206a6fSBrian Somers if (fp->state == ST_STOPPED) 104409206a6fSBrian Somers fsm_Close(fp); 104509206a6fSBrian Somers if (fp->state > ST_INITIAL) 104609206a6fSBrian Somers fsm_Down(fp); 104709206a6fSBrian Somers if (fp->state > ST_INITIAL) 104809206a6fSBrian Somers fsm_Close(fp); 104909206a6fSBrian Somers } 1050