11ae349f5Scvs2svn /* 21ae349f5Scvs2svn * PPP Finite State Machine for LCP/IPCP 31ae349f5Scvs2svn * 41ae349f5Scvs2svn * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 51ae349f5Scvs2svn * 61ae349f5Scvs2svn * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 71ae349f5Scvs2svn * 81ae349f5Scvs2svn * Redistribution and use in source and binary forms are permitted 91ae349f5Scvs2svn * provided that the above copyright notice and this paragraph are 101ae349f5Scvs2svn * duplicated in all such forms and that any documentation, 111ae349f5Scvs2svn * advertising materials, and other materials related to such 121ae349f5Scvs2svn * distribution and use acknowledge that the software was developed 131ae349f5Scvs2svn * by the Internet Initiative Japan, Inc. The name of the 141ae349f5Scvs2svn * IIJ may not be used to endorse or promote products derived 151ae349f5Scvs2svn * from this software without specific prior written permission. 161ae349f5Scvs2svn * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 171ae349f5Scvs2svn * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 181ae349f5Scvs2svn * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 191ae349f5Scvs2svn * 20dd7e2610SBrian Somers * $Id: fsm.c,v 1.27.2.34 1998/04/30 23:53:38 brian Exp $ 211ae349f5Scvs2svn * 221ae349f5Scvs2svn * TODO: 231ae349f5Scvs2svn */ 241342caedSBrian Somers 252764b86aSBrian Somers #include <sys/types.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 311ae349f5Scvs2svn #include <string.h> 321ae349f5Scvs2svn #include <termios.h> 331ae349f5Scvs2svn 341ae349f5Scvs2svn #include "mbuf.h" 351ae349f5Scvs2svn #include "log.h" 361ae349f5Scvs2svn #include "defs.h" 371ae349f5Scvs2svn #include "timer.h" 381ae349f5Scvs2svn #include "fsm.h" 391342caedSBrian Somers #include "iplist.h" 401ae349f5Scvs2svn #include "lqr.h" 41879ed6faSBrian Somers #include "hdlc.h" 421342caedSBrian Somers #include "throughput.h" 431342caedSBrian Somers #include "slcompress.h" 441342caedSBrian Somers #include "ipcp.h" 451342caedSBrian Somers #include "filter.h" 461342caedSBrian Somers #include "descriptor.h" 471ae349f5Scvs2svn #include "lcp.h" 481ae349f5Scvs2svn #include "ccp.h" 498c07a7b2SBrian Somers #include "link.h" 501342caedSBrian Somers #include "mp.h" 511342caedSBrian Somers #include "bundle.h" 521342caedSBrian Somers #include "async.h" 5363b73463SBrian Somers #include "physical.h" 541342caedSBrian Somers #include "lcpproto.h" 551ae349f5Scvs2svn 561ae349f5Scvs2svn static void FsmSendConfigReq(struct fsm *); 571ae349f5Scvs2svn static void FsmSendTerminateReq(struct fsm *); 581ae349f5Scvs2svn static void FsmInitRestartCounter(struct fsm *); 591ae349f5Scvs2svn 602267893fSBrian Somers typedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *); 612267893fSBrian Somers static recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak, 622267893fSBrian Somers FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck, 632267893fSBrian Somers FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq, 642267893fSBrian Somers FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent, 652267893fSBrian Somers FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck; 662267893fSBrian Somers 672267893fSBrian Somers static const struct fsmcodedesc { 682267893fSBrian Somers recvfn *recv; 692267893fSBrian Somers unsigned check_reqid : 1; 702267893fSBrian Somers unsigned inc_reqid : 1; 712267893fSBrian Somers const char *name; 722267893fSBrian Somers } FsmCodes[] = { 732267893fSBrian Somers { FsmRecvConfigReq, 0, 0, "ConfigReq" }, 742267893fSBrian Somers { FsmRecvConfigAck, 1, 1, "ConfigAck" }, 752267893fSBrian Somers { FsmRecvConfigNak, 1, 1, "ConfigNak" }, 762267893fSBrian Somers { FsmRecvConfigRej, 1, 1, "ConfigRej" }, 772267893fSBrian Somers { FsmRecvTermReq, 0, 0, "TerminateReq" }, 782267893fSBrian Somers { FsmRecvTermAck, 1, 1, "TerminateAck" }, 792267893fSBrian Somers { FsmRecvCodeRej, 0, 0, "CodeRej" }, 802267893fSBrian Somers { FsmRecvProtoRej, 0, 0, "ProtocolRej" }, 812267893fSBrian Somers { FsmRecvEchoReq, 0, 0, "EchoRequest" }, 822267893fSBrian Somers { FsmRecvEchoRep, 0, 0, "EchoReply" }, 832267893fSBrian Somers { FsmRecvDiscReq, 0, 0, "DiscardReq" }, 842267893fSBrian Somers { FsmRecvIdent, 0, 0, "Ident" }, 852267893fSBrian Somers { FsmRecvTimeRemain,0, 0, "TimeRemain" }, 862267893fSBrian Somers { FsmRecvResetReq, 0, 0, "ResetReqt" }, 872267893fSBrian Somers { FsmRecvResetAck, 0, 1, "ResetAck" } 882267893fSBrian Somers }; 892267893fSBrian Somers 902267893fSBrian Somers static const char * 912267893fSBrian Somers Code2Nam(u_int code) 922267893fSBrian Somers { 932267893fSBrian Somers if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0]) 942267893fSBrian Somers return "Unknown"; 952267893fSBrian Somers return FsmCodes[code-1].name; 962267893fSBrian Somers } 972267893fSBrian Somers 981e991daaSBrian Somers const char * 991e991daaSBrian Somers State2Nam(u_int state) 1001e991daaSBrian Somers { 1011e991daaSBrian Somers static const char *StateNames[] = { 1021e991daaSBrian Somers "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", 1031e991daaSBrian Somers "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", 1041e991daaSBrian Somers }; 1051e991daaSBrian Somers 1061e991daaSBrian Somers if (state >= sizeof StateNames / sizeof StateNames[0]) 1071e991daaSBrian Somers return "unknown"; 1081e991daaSBrian Somers return StateNames[state]; 1091e991daaSBrian Somers } 1101e991daaSBrian Somers 1111ae349f5Scvs2svn static void 1121ae349f5Scvs2svn StoppedTimeout(void *v) 1131ae349f5Scvs2svn { 1141ae349f5Scvs2svn struct fsm *fp = (struct fsm *)v; 1151ae349f5Scvs2svn 116dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name); 1171ae349f5Scvs2svn if (fp->OpenTimer.state == TIMER_RUNNING) { 118dd7e2610SBrian Somers log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n", 119d47dceb8SBrian Somers fp->link->name, fp->name); 120dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 1211ae349f5Scvs2svn } 1223b0f8d2eSBrian Somers if (fp->state == ST_STOPPED) { 1233b0f8d2eSBrian Somers /* Force ourselves back to initial */ 124dd7e2610SBrian Somers fsm_Down(fp); 125dd7e2610SBrian Somers fsm_Close(fp); 1263b0f8d2eSBrian Somers } 1271ae349f5Scvs2svn } 1281ae349f5Scvs2svn 1291ae349f5Scvs2svn void 1303b0f8d2eSBrian Somers fsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, 1313b0f8d2eSBrian Somers int maxcode, int maxcfg, int LogLevel, struct bundle *bundle, 1323b0f8d2eSBrian Somers struct link *l, const struct fsm_parent *parent, 1333b0f8d2eSBrian Somers struct fsm_callbacks *fn, const char *timer_names[3]) 1341ae349f5Scvs2svn { 135503a7782SBrian Somers fp->name = name; 136503a7782SBrian Somers fp->proto = proto; 1373b0f8d2eSBrian Somers fp->min_code = mincode; 138503a7782SBrian Somers fp->max_code = maxcode; 1393b0f8d2eSBrian Somers fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; 1401ae349f5Scvs2svn fp->reqid = 1; 1411ae349f5Scvs2svn fp->restart = 1; 142503a7782SBrian Somers fp->maxconfig = maxcfg; 143503a7782SBrian Somers memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); 144503a7782SBrian Somers memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); 145503a7782SBrian Somers memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); 146503a7782SBrian Somers fp->LogLevel = LogLevel; 1478c07a7b2SBrian Somers fp->link = l; 1487a6f8720SBrian Somers fp->bundle = bundle; 1496d666775SBrian Somers fp->parent = parent; 150503a7782SBrian Somers fp->fn = fn; 1513b0f8d2eSBrian Somers fp->FsmTimer.name = timer_names[0]; 1523b0f8d2eSBrian Somers fp->OpenTimer.name = timer_names[1]; 1533b0f8d2eSBrian Somers fp->StoppedTimer.name = timer_names[2]; 1541ae349f5Scvs2svn } 1551ae349f5Scvs2svn 1561ae349f5Scvs2svn static void 1571ae349f5Scvs2svn NewState(struct fsm * fp, int new) 1581ae349f5Scvs2svn { 159dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", 160d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state), State2Nam(new)); 1611ae349f5Scvs2svn if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) 162dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 1631ae349f5Scvs2svn fp->state = new; 1641ae349f5Scvs2svn if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { 165dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 1661ae349f5Scvs2svn if (new == ST_STOPPED && fp->StoppedTimer.load) { 167dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 1681ae349f5Scvs2svn fp->StoppedTimer.func = StoppedTimeout; 1691ae349f5Scvs2svn fp->StoppedTimer.arg = (void *) fp; 170dd7e2610SBrian Somers timer_Start(&fp->StoppedTimer); 1711ae349f5Scvs2svn } 1721ae349f5Scvs2svn } 1731ae349f5Scvs2svn } 1741ae349f5Scvs2svn 1751ae349f5Scvs2svn void 176dd7e2610SBrian Somers fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count) 1771ae349f5Scvs2svn { 1781ae349f5Scvs2svn int plen; 1791ae349f5Scvs2svn struct fsmheader lh; 1801ae349f5Scvs2svn struct mbuf *bp; 1811ae349f5Scvs2svn 182dd7e2610SBrian Somers if (log_IsKept(fp->LogLevel)) { 183dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 184d47dceb8SBrian Somers fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 1852267893fSBrian Somers switch (code) { 1862267893fSBrian Somers case CODE_CONFIGREQ: 1872267893fSBrian Somers case CODE_CONFIGACK: 1882267893fSBrian Somers case CODE_CONFIGREJ: 1892267893fSBrian Somers case CODE_CONFIGNAK: 1902267893fSBrian Somers (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL); 1912267893fSBrian Somers if (count < sizeof(struct fsmconfig)) 192dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 1932267893fSBrian Somers break; 1942267893fSBrian Somers } 1952267893fSBrian Somers } 1962267893fSBrian Somers 1971ae349f5Scvs2svn plen = sizeof(struct fsmheader) + count; 1981ae349f5Scvs2svn lh.code = code; 1991ae349f5Scvs2svn lh.id = id; 2001ae349f5Scvs2svn lh.length = htons(plen); 201dd7e2610SBrian Somers bp = mbuf_Alloc(plen, MB_FSM); 2021ae349f5Scvs2svn memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 2031ae349f5Scvs2svn if (count) 2041ae349f5Scvs2svn memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 205dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "fsm_Output", bp); 206dd7e2610SBrian Somers hdlc_Output(fp->link, PRI_LINK, fp->proto, bp); 2071ae349f5Scvs2svn } 2081ae349f5Scvs2svn 2091ae349f5Scvs2svn static void 2101ae349f5Scvs2svn FsmOpenNow(void *v) 2111ae349f5Scvs2svn { 2121ae349f5Scvs2svn struct fsm *fp = (struct fsm *)v; 2131ae349f5Scvs2svn 214dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 2151ae349f5Scvs2svn if (fp->state <= ST_STOPPED) { 2161ae349f5Scvs2svn FsmInitRestartCounter(fp); 2171ae349f5Scvs2svn FsmSendConfigReq(fp); 2181ae349f5Scvs2svn NewState(fp, ST_REQSENT); 2191ae349f5Scvs2svn } 2201ae349f5Scvs2svn } 2211ae349f5Scvs2svn 2221ae349f5Scvs2svn void 223dd7e2610SBrian Somers fsm_Open(struct fsm * fp) 2241ae349f5Scvs2svn { 2251ae349f5Scvs2svn switch (fp->state) { 2261ae349f5Scvs2svn case ST_INITIAL: 2271ae349f5Scvs2svn NewState(fp, ST_STARTING); 2286d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2296d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 2301ae349f5Scvs2svn break; 2311ae349f5Scvs2svn case ST_CLOSED: 2321ae349f5Scvs2svn if (fp->open_mode == OPEN_PASSIVE) { 2331ae349f5Scvs2svn NewState(fp, ST_STOPPED); 2341ae349f5Scvs2svn } else if (fp->open_mode > 0) { 2351ae349f5Scvs2svn if (fp->open_mode > 1) 236dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 237d47dceb8SBrian Somers fp->link->name, fp->open_mode); 2381ae349f5Scvs2svn NewState(fp, ST_STOPPED); 239dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 2401ae349f5Scvs2svn fp->OpenTimer.load = fp->open_mode * SECTICKS; 2411ae349f5Scvs2svn fp->OpenTimer.func = FsmOpenNow; 2421ae349f5Scvs2svn fp->OpenTimer.arg = (void *)fp; 243dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 2441ae349f5Scvs2svn } else 2451ae349f5Scvs2svn FsmOpenNow(fp); 2461ae349f5Scvs2svn break; 2471ae349f5Scvs2svn case ST_STOPPED: /* XXX: restart option */ 2481ae349f5Scvs2svn case ST_REQSENT: 2491ae349f5Scvs2svn case ST_ACKRCVD: 2501ae349f5Scvs2svn case ST_ACKSENT: 2511ae349f5Scvs2svn case ST_OPENED: /* XXX: restart option */ 2521ae349f5Scvs2svn break; 2531ae349f5Scvs2svn case ST_CLOSING: /* XXX: restart option */ 2541ae349f5Scvs2svn case ST_STOPPING: /* XXX: restart option */ 2551ae349f5Scvs2svn NewState(fp, ST_STOPPING); 2561ae349f5Scvs2svn break; 2571ae349f5Scvs2svn } 2581ae349f5Scvs2svn } 2591ae349f5Scvs2svn 2601ae349f5Scvs2svn void 261dd7e2610SBrian Somers fsm_Up(struct fsm * fp) 2621ae349f5Scvs2svn { 2631ae349f5Scvs2svn switch (fp->state) { 2641ae349f5Scvs2svn case ST_INITIAL: 265dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 2661fa665f5SBrian Somers fp->link->name); 2671ae349f5Scvs2svn NewState(fp, ST_CLOSED); 2681ae349f5Scvs2svn break; 2691ae349f5Scvs2svn case ST_STARTING: 2701ae349f5Scvs2svn FsmInitRestartCounter(fp); 2711ae349f5Scvs2svn FsmSendConfigReq(fp); 2721ae349f5Scvs2svn NewState(fp, ST_REQSENT); 2731ae349f5Scvs2svn break; 2741ae349f5Scvs2svn default: 275dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 276d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 2771ae349f5Scvs2svn break; 2781ae349f5Scvs2svn } 2791ae349f5Scvs2svn } 2801ae349f5Scvs2svn 2811ae349f5Scvs2svn void 282dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 2831ae349f5Scvs2svn { 2841ae349f5Scvs2svn switch (fp->state) { 2851ae349f5Scvs2svn case ST_CLOSED: 2861ae349f5Scvs2svn NewState(fp, ST_INITIAL); 2871ae349f5Scvs2svn break; 288455aabc3SBrian Somers case ST_CLOSING: 2896d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 290455aabc3SBrian Somers NewState(fp, ST_INITIAL); 2916d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 292455aabc3SBrian Somers break; 2931ae349f5Scvs2svn case ST_STOPPED: 294455aabc3SBrian Somers NewState(fp, ST_STARTING); 2956d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2966d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 297455aabc3SBrian Somers break; 2981ae349f5Scvs2svn case ST_STOPPING: 2991ae349f5Scvs2svn case ST_REQSENT: 3001ae349f5Scvs2svn case ST_ACKRCVD: 3011ae349f5Scvs2svn case ST_ACKSENT: 3021ae349f5Scvs2svn NewState(fp, ST_STARTING); 3031ae349f5Scvs2svn break; 3041ae349f5Scvs2svn case ST_OPENED: 3056d666775SBrian Somers (*fp->fn->LayerDown)(fp); 3061ae349f5Scvs2svn NewState(fp, ST_STARTING); 3076d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 3081ae349f5Scvs2svn break; 3091ae349f5Scvs2svn } 3101ae349f5Scvs2svn } 3111ae349f5Scvs2svn 3121ae349f5Scvs2svn void 313dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 3141ae349f5Scvs2svn { 3151ae349f5Scvs2svn switch (fp->state) { 3161ae349f5Scvs2svn case ST_STARTING: 3176d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 3181ae349f5Scvs2svn NewState(fp, ST_INITIAL); 3196d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 3201ae349f5Scvs2svn break; 3211ae349f5Scvs2svn case ST_STOPPED: 3221ae349f5Scvs2svn NewState(fp, ST_CLOSED); 3231ae349f5Scvs2svn break; 3241ae349f5Scvs2svn case ST_STOPPING: 3251ae349f5Scvs2svn NewState(fp, ST_CLOSING); 3261ae349f5Scvs2svn break; 3271ae349f5Scvs2svn case ST_OPENED: 3286d666775SBrian Somers (*fp->fn->LayerDown)(fp); 329455aabc3SBrian Somers FsmInitRestartCounter(fp); 330455aabc3SBrian Somers FsmSendTerminateReq(fp); 331455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3326d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 333455aabc3SBrian Somers break; 3341ae349f5Scvs2svn case ST_REQSENT: 3351ae349f5Scvs2svn case ST_ACKRCVD: 3361ae349f5Scvs2svn case ST_ACKSENT: 3371ae349f5Scvs2svn FsmInitRestartCounter(fp); 3381ae349f5Scvs2svn FsmSendTerminateReq(fp); 3391ae349f5Scvs2svn NewState(fp, ST_CLOSING); 3401ae349f5Scvs2svn break; 3411ae349f5Scvs2svn } 3421ae349f5Scvs2svn } 3431ae349f5Scvs2svn 3441ae349f5Scvs2svn /* 3451ae349f5Scvs2svn * Send functions 3461ae349f5Scvs2svn */ 3471ae349f5Scvs2svn static void 3481ae349f5Scvs2svn FsmSendConfigReq(struct fsm * fp) 3491ae349f5Scvs2svn { 3501ae349f5Scvs2svn if (--fp->maxconfig > 0) { 35183d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 352dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 3531ae349f5Scvs2svn fp->restart--; /* Decrement restart counter */ 3541ae349f5Scvs2svn } else { 355dd7e2610SBrian Somers fsm_Close(fp); 3561ae349f5Scvs2svn } 3571ae349f5Scvs2svn } 3581ae349f5Scvs2svn 3591ae349f5Scvs2svn static void 3601ae349f5Scvs2svn FsmSendTerminateReq(struct fsm *fp) 3611ae349f5Scvs2svn { 362dd7e2610SBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0); 3632267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 364dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 3651ae349f5Scvs2svn fp->restart--; /* Decrement restart counter */ 3661ae349f5Scvs2svn } 3671ae349f5Scvs2svn 3681ae349f5Scvs2svn /* 3691ae349f5Scvs2svn * Timeout actions 3701ae349f5Scvs2svn */ 3711ae349f5Scvs2svn static void 3721ae349f5Scvs2svn FsmTimeout(void *v) 3731ae349f5Scvs2svn { 3741ae349f5Scvs2svn struct fsm *fp = (struct fsm *)v; 3751ae349f5Scvs2svn 3761ae349f5Scvs2svn if (fp->restart) { 3771ae349f5Scvs2svn switch (fp->state) { 3781ae349f5Scvs2svn case ST_CLOSING: 3791ae349f5Scvs2svn case ST_STOPPING: 3801ae349f5Scvs2svn FsmSendTerminateReq(fp); 3811ae349f5Scvs2svn break; 3821ae349f5Scvs2svn case ST_REQSENT: 3831ae349f5Scvs2svn case ST_ACKSENT: 3841ae349f5Scvs2svn FsmSendConfigReq(fp); 3851ae349f5Scvs2svn break; 3861ae349f5Scvs2svn case ST_ACKRCVD: 3871ae349f5Scvs2svn FsmSendConfigReq(fp); 3881ae349f5Scvs2svn NewState(fp, ST_REQSENT); 3891ae349f5Scvs2svn break; 3901ae349f5Scvs2svn } 391dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 3921ae349f5Scvs2svn } else { 3931ae349f5Scvs2svn switch (fp->state) { 3941ae349f5Scvs2svn case ST_CLOSING: 3956d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 396455aabc3SBrian Somers NewState(fp, ST_CLOSED); 3976d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 3981ae349f5Scvs2svn break; 3991ae349f5Scvs2svn case ST_STOPPING: 4006d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 401455aabc3SBrian Somers NewState(fp, ST_STOPPED); 4026d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 4031ae349f5Scvs2svn break; 4041ae349f5Scvs2svn case ST_REQSENT: /* XXX: 3p */ 4051ae349f5Scvs2svn case ST_ACKSENT: 4061ae349f5Scvs2svn case ST_ACKRCVD: 4076d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 408455aabc3SBrian Somers NewState(fp, ST_STOPPED); 4096d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 4101ae349f5Scvs2svn break; 4111ae349f5Scvs2svn } 4121ae349f5Scvs2svn } 4131ae349f5Scvs2svn } 4141ae349f5Scvs2svn 4151ae349f5Scvs2svn static void 4161ae349f5Scvs2svn FsmInitRestartCounter(struct fsm * fp) 4171ae349f5Scvs2svn { 418dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 4191ae349f5Scvs2svn fp->FsmTimer.func = FsmTimeout; 4201ae349f5Scvs2svn fp->FsmTimer.arg = (void *) fp; 42183d1af55SBrian Somers (*fp->fn->InitRestartCounter)(fp); 4221ae349f5Scvs2svn } 4231ae349f5Scvs2svn 4241ae349f5Scvs2svn /* 4251ae349f5Scvs2svn * Actions when receive packets 4261ae349f5Scvs2svn */ 4271ae349f5Scvs2svn static void 4281ae349f5Scvs2svn FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 4291ae349f5Scvs2svn /* RCR */ 4301ae349f5Scvs2svn { 43130c2f2ffSBrian Somers struct fsm_decode dec; 4321ae349f5Scvs2svn int plen, flen; 4331ae349f5Scvs2svn int ackaction = 0; 4341ae349f5Scvs2svn 435dd7e2610SBrian Somers plen = mbuf_Length(bp); 4361ae349f5Scvs2svn flen = ntohs(lhp->length) - sizeof *lhp; 4371ae349f5Scvs2svn if (plen < flen) { 438dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 439d47dceb8SBrian Somers fp->link->name, plen, flen); 440dd7e2610SBrian Somers mbuf_Free(bp); 4411ae349f5Scvs2svn return; 4421ae349f5Scvs2svn } 4431ae349f5Scvs2svn 4441ae349f5Scvs2svn /* 4451ae349f5Scvs2svn * Check and process easy case 4461ae349f5Scvs2svn */ 4471ae349f5Scvs2svn switch (fp->state) { 4481ae349f5Scvs2svn case ST_INITIAL: 4491ae349f5Scvs2svn case ST_STARTING: 450dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 451d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 452dd7e2610SBrian Somers mbuf_Free(bp); 4531ae349f5Scvs2svn return; 4541ae349f5Scvs2svn case ST_CLOSED: 4552267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 456dd7e2610SBrian Somers mbuf_Free(bp); 4571ae349f5Scvs2svn return; 4581ae349f5Scvs2svn case ST_CLOSING: 459dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 460d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 4611ae349f5Scvs2svn case ST_STOPPING: 462dd7e2610SBrian Somers mbuf_Free(bp); 4631ae349f5Scvs2svn return; 4641ae349f5Scvs2svn } 4651ae349f5Scvs2svn 46630c2f2ffSBrian Somers dec.ackend = dec.ack; 46730c2f2ffSBrian Somers dec.nakend = dec.nak; 46830c2f2ffSBrian Somers dec.rejend = dec.rej; 46930c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec); 4702267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 471dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 4721ae349f5Scvs2svn 47330c2f2ffSBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 4741ae349f5Scvs2svn ackaction = 1; 4751ae349f5Scvs2svn 4761ae349f5Scvs2svn switch (fp->state) { 4771ae349f5Scvs2svn case ST_OPENED: 4786d666775SBrian Somers (*fp->fn->LayerDown)(fp); 4791ae349f5Scvs2svn FsmSendConfigReq(fp); 4806d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 4811ae349f5Scvs2svn break; 4821ae349f5Scvs2svn case ST_STOPPED: 4831ae349f5Scvs2svn FsmInitRestartCounter(fp); 4841ae349f5Scvs2svn FsmSendConfigReq(fp); 4851ae349f5Scvs2svn break; 4861ae349f5Scvs2svn } 4871ae349f5Scvs2svn 48830c2f2ffSBrian Somers if (dec.rejend != dec.rej) 489dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej); 49030c2f2ffSBrian Somers if (dec.nakend != dec.nak) 491dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak); 4921ae349f5Scvs2svn if (ackaction) 493dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack); 4941ae349f5Scvs2svn 4951ae349f5Scvs2svn switch (fp->state) { 4961ae349f5Scvs2svn case ST_OPENED: 497455aabc3SBrian Somers case ST_STOPPED: 4981ae349f5Scvs2svn if (ackaction) 4991ae349f5Scvs2svn NewState(fp, ST_ACKSENT); 5001ae349f5Scvs2svn else 5011ae349f5Scvs2svn NewState(fp, ST_REQSENT); 5021ae349f5Scvs2svn break; 5031ae349f5Scvs2svn case ST_REQSENT: 5041ae349f5Scvs2svn if (ackaction) 5051ae349f5Scvs2svn NewState(fp, ST_ACKSENT); 5061ae349f5Scvs2svn break; 5071ae349f5Scvs2svn case ST_ACKRCVD: 5081ae349f5Scvs2svn if (ackaction) { 5091ae349f5Scvs2svn NewState(fp, ST_OPENED); 5106f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5116d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5126f384573SBrian Somers else { 5136f384573SBrian Somers (*fp->fn->LayerDown)(fp); 5146f384573SBrian Somers FsmInitRestartCounter(fp); 5156f384573SBrian Somers FsmSendTerminateReq(fp); 5166f384573SBrian Somers NewState(fp, ST_CLOSING); 5176f384573SBrian Somers } 5181ae349f5Scvs2svn } 5191ae349f5Scvs2svn break; 5201ae349f5Scvs2svn case ST_ACKSENT: 5211ae349f5Scvs2svn if (!ackaction) 5221ae349f5Scvs2svn NewState(fp, ST_REQSENT); 5231ae349f5Scvs2svn break; 5241ae349f5Scvs2svn } 525dd7e2610SBrian Somers mbuf_Free(bp); 5261ae349f5Scvs2svn } 5271ae349f5Scvs2svn 5281ae349f5Scvs2svn static void 5291ae349f5Scvs2svn FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 5301ae349f5Scvs2svn /* RCA */ 5311ae349f5Scvs2svn { 5321ae349f5Scvs2svn switch (fp->state) { 5331ae349f5Scvs2svn case ST_CLOSED: 5341ae349f5Scvs2svn case ST_STOPPED: 5352267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 5361ae349f5Scvs2svn break; 5371ae349f5Scvs2svn case ST_CLOSING: 5381ae349f5Scvs2svn case ST_STOPPING: 5391ae349f5Scvs2svn break; 5401ae349f5Scvs2svn case ST_REQSENT: 5411ae349f5Scvs2svn FsmInitRestartCounter(fp); 5421ae349f5Scvs2svn NewState(fp, ST_ACKRCVD); 5431ae349f5Scvs2svn break; 5441ae349f5Scvs2svn case ST_ACKRCVD: 5451ae349f5Scvs2svn FsmSendConfigReq(fp); 5461ae349f5Scvs2svn NewState(fp, ST_REQSENT); 5471ae349f5Scvs2svn break; 5481ae349f5Scvs2svn case ST_ACKSENT: 5491ae349f5Scvs2svn FsmInitRestartCounter(fp); 5501ae349f5Scvs2svn NewState(fp, ST_OPENED); 5516f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5526d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5536f384573SBrian Somers else { 5546f384573SBrian Somers (*fp->fn->LayerDown)(fp); 5556f384573SBrian Somers FsmInitRestartCounter(fp); 5566f384573SBrian Somers FsmSendTerminateReq(fp); 5576f384573SBrian Somers NewState(fp, ST_CLOSING); 5586f384573SBrian Somers } 5591ae349f5Scvs2svn break; 5601ae349f5Scvs2svn case ST_OPENED: 5616d666775SBrian Somers (*fp->fn->LayerDown)(fp); 5621ae349f5Scvs2svn FsmSendConfigReq(fp); 5631ae349f5Scvs2svn NewState(fp, ST_REQSENT); 5646d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 5651ae349f5Scvs2svn break; 5661ae349f5Scvs2svn } 567dd7e2610SBrian Somers mbuf_Free(bp); 5681ae349f5Scvs2svn } 5691ae349f5Scvs2svn 5701ae349f5Scvs2svn static void 5711ae349f5Scvs2svn FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 5721ae349f5Scvs2svn /* RCN */ 5731ae349f5Scvs2svn { 57430c2f2ffSBrian Somers struct fsm_decode dec; 5751ae349f5Scvs2svn int plen, flen; 5761ae349f5Scvs2svn 577dd7e2610SBrian Somers plen = mbuf_Length(bp); 5781ae349f5Scvs2svn flen = ntohs(lhp->length) - sizeof *lhp; 5791ae349f5Scvs2svn if (plen < flen) { 580dd7e2610SBrian Somers mbuf_Free(bp); 5811ae349f5Scvs2svn return; 5821ae349f5Scvs2svn } 5831ae349f5Scvs2svn 5841ae349f5Scvs2svn /* 5851ae349f5Scvs2svn * Check and process easy case 5861ae349f5Scvs2svn */ 5871ae349f5Scvs2svn switch (fp->state) { 5881ae349f5Scvs2svn case ST_INITIAL: 5891ae349f5Scvs2svn case ST_STARTING: 590dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 591d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 592dd7e2610SBrian Somers mbuf_Free(bp); 5931ae349f5Scvs2svn return; 5941ae349f5Scvs2svn case ST_CLOSED: 5951ae349f5Scvs2svn case ST_STOPPED: 5962267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 597dd7e2610SBrian Somers mbuf_Free(bp); 5981ae349f5Scvs2svn return; 5991ae349f5Scvs2svn case ST_CLOSING: 6001ae349f5Scvs2svn case ST_STOPPING: 601dd7e2610SBrian Somers mbuf_Free(bp); 6021ae349f5Scvs2svn return; 6031ae349f5Scvs2svn } 6041ae349f5Scvs2svn 60530c2f2ffSBrian Somers dec.ackend = dec.ack; 60630c2f2ffSBrian Somers dec.nakend = dec.nak; 60730c2f2ffSBrian Somers dec.rejend = dec.rej; 60830c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); 6092267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 610dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 6111ae349f5Scvs2svn 6121ae349f5Scvs2svn switch (fp->state) { 6131ae349f5Scvs2svn case ST_REQSENT: 6141ae349f5Scvs2svn case ST_ACKSENT: 6151ae349f5Scvs2svn FsmInitRestartCounter(fp); 6161ae349f5Scvs2svn FsmSendConfigReq(fp); 6171ae349f5Scvs2svn break; 6181ae349f5Scvs2svn case ST_OPENED: 6196d666775SBrian Somers (*fp->fn->LayerDown)(fp); 620455aabc3SBrian Somers FsmSendConfigReq(fp); 621455aabc3SBrian Somers NewState(fp, ST_REQSENT); 6226d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 623455aabc3SBrian Somers break; 6241ae349f5Scvs2svn case ST_ACKRCVD: 6251ae349f5Scvs2svn FsmSendConfigReq(fp); 6261ae349f5Scvs2svn NewState(fp, ST_REQSENT); 6271ae349f5Scvs2svn break; 6281ae349f5Scvs2svn } 6291ae349f5Scvs2svn 630dd7e2610SBrian Somers mbuf_Free(bp); 6311ae349f5Scvs2svn } 6321ae349f5Scvs2svn 6331ae349f5Scvs2svn static void 6341ae349f5Scvs2svn FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 6351ae349f5Scvs2svn /* RTR */ 6361ae349f5Scvs2svn { 6371ae349f5Scvs2svn switch (fp->state) { 6381ae349f5Scvs2svn case ST_INITIAL: 6391ae349f5Scvs2svn case ST_STARTING: 640dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 641d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 6421ae349f5Scvs2svn break; 6431ae349f5Scvs2svn case ST_CLOSED: 6441ae349f5Scvs2svn case ST_STOPPED: 6451ae349f5Scvs2svn case ST_CLOSING: 6461ae349f5Scvs2svn case ST_STOPPING: 6471ae349f5Scvs2svn case ST_REQSENT: 6482267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 6491ae349f5Scvs2svn break; 6501ae349f5Scvs2svn case ST_ACKRCVD: 6511ae349f5Scvs2svn case ST_ACKSENT: 6522267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 6531ae349f5Scvs2svn NewState(fp, ST_REQSENT); 6541ae349f5Scvs2svn break; 6551ae349f5Scvs2svn case ST_OPENED: 6566d666775SBrian Somers (*fp->fn->LayerDown)(fp); 6572267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 658dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 6591ae349f5Scvs2svn fp->restart = 0; 6601ae349f5Scvs2svn NewState(fp, ST_STOPPING); 6616d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 6621ae349f5Scvs2svn break; 6631ae349f5Scvs2svn } 664dd7e2610SBrian Somers mbuf_Free(bp); 6651ae349f5Scvs2svn } 6661ae349f5Scvs2svn 6671ae349f5Scvs2svn static void 6681ae349f5Scvs2svn FsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 6691ae349f5Scvs2svn /* RTA */ 6701ae349f5Scvs2svn { 6711ae349f5Scvs2svn switch (fp->state) { 6721ae349f5Scvs2svn case ST_CLOSING: 6736d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 674455aabc3SBrian Somers NewState(fp, ST_CLOSED); 6756d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 6761ae349f5Scvs2svn break; 6771ae349f5Scvs2svn case ST_STOPPING: 6786d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 679455aabc3SBrian Somers NewState(fp, ST_STOPPED); 6806d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 6811ae349f5Scvs2svn break; 6821ae349f5Scvs2svn case ST_ACKRCVD: 6831ae349f5Scvs2svn NewState(fp, ST_REQSENT); 6841ae349f5Scvs2svn break; 6851ae349f5Scvs2svn case ST_OPENED: 6866d666775SBrian Somers (*fp->fn->LayerDown)(fp); 6871ae349f5Scvs2svn FsmSendConfigReq(fp); 6881ae349f5Scvs2svn NewState(fp, ST_REQSENT); 6896d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 6901ae349f5Scvs2svn break; 6911ae349f5Scvs2svn } 692dd7e2610SBrian Somers mbuf_Free(bp); 6931ae349f5Scvs2svn } 6941ae349f5Scvs2svn 6951ae349f5Scvs2svn static void 6961ae349f5Scvs2svn FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 6971ae349f5Scvs2svn /* RCJ */ 6981ae349f5Scvs2svn { 69930c2f2ffSBrian Somers struct fsm_decode dec; 7001ae349f5Scvs2svn int plen, flen; 7011ae349f5Scvs2svn 702dd7e2610SBrian Somers plen = mbuf_Length(bp); 7031ae349f5Scvs2svn flen = ntohs(lhp->length) - sizeof *lhp; 7041ae349f5Scvs2svn if (plen < flen) { 705dd7e2610SBrian Somers mbuf_Free(bp); 7061ae349f5Scvs2svn return; 7071ae349f5Scvs2svn } 7081ae349f5Scvs2svn 7091ae349f5Scvs2svn /* 7101ae349f5Scvs2svn * Check and process easy case 7111ae349f5Scvs2svn */ 7121ae349f5Scvs2svn switch (fp->state) { 7131ae349f5Scvs2svn case ST_INITIAL: 7141ae349f5Scvs2svn case ST_STARTING: 715dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 716d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 717dd7e2610SBrian Somers mbuf_Free(bp); 7181ae349f5Scvs2svn return; 7191ae349f5Scvs2svn case ST_CLOSED: 7201ae349f5Scvs2svn case ST_STOPPED: 7212267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 722dd7e2610SBrian Somers mbuf_Free(bp); 7231ae349f5Scvs2svn return; 7241ae349f5Scvs2svn case ST_CLOSING: 7251ae349f5Scvs2svn case ST_STOPPING: 726dd7e2610SBrian Somers mbuf_Free(bp); 7271ae349f5Scvs2svn return; 7281ae349f5Scvs2svn } 7291ae349f5Scvs2svn 73030c2f2ffSBrian Somers dec.ackend = dec.ack; 73130c2f2ffSBrian Somers dec.nakend = dec.nak; 73230c2f2ffSBrian Somers dec.rejend = dec.rej; 73330c2f2ffSBrian Somers (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); 7342267893fSBrian Somers if (flen < sizeof(struct fsmconfig)) 735dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 7361ae349f5Scvs2svn 7371ae349f5Scvs2svn switch (fp->state) { 7381ae349f5Scvs2svn case ST_REQSENT: 7391ae349f5Scvs2svn case ST_ACKSENT: 7401ae349f5Scvs2svn FsmInitRestartCounter(fp); 7411ae349f5Scvs2svn FsmSendConfigReq(fp); 7421ae349f5Scvs2svn break; 7431ae349f5Scvs2svn case ST_OPENED: 7446d666775SBrian Somers (*fp->fn->LayerDown)(fp); 745455aabc3SBrian Somers FsmSendConfigReq(fp); 746455aabc3SBrian Somers NewState(fp, ST_REQSENT); 7476d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 748455aabc3SBrian Somers break; 7491ae349f5Scvs2svn case ST_ACKRCVD: 7501ae349f5Scvs2svn FsmSendConfigReq(fp); 7511ae349f5Scvs2svn NewState(fp, ST_REQSENT); 7521ae349f5Scvs2svn break; 7531ae349f5Scvs2svn } 754dd7e2610SBrian Somers mbuf_Free(bp); 7551ae349f5Scvs2svn } 7561ae349f5Scvs2svn 7571ae349f5Scvs2svn static void 7581ae349f5Scvs2svn FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 7591ae349f5Scvs2svn { 760dd7e2610SBrian Somers mbuf_Free(bp); 7611ae349f5Scvs2svn } 7621ae349f5Scvs2svn 7631ae349f5Scvs2svn static void 7641ae349f5Scvs2svn FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 7651ae349f5Scvs2svn { 7668c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 7671ae349f5Scvs2svn u_short *sp, proto; 7681ae349f5Scvs2svn 7691ae349f5Scvs2svn sp = (u_short *) MBUF_CTOP(bp); 7701ae349f5Scvs2svn proto = ntohs(*sp); 771dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 772d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 7731ae349f5Scvs2svn 7741ae349f5Scvs2svn switch (proto) { 7751ae349f5Scvs2svn case PROTO_LQR: 7768c07a7b2SBrian Somers if (p) 777dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 7788c07a7b2SBrian Somers else 779dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 780d47dceb8SBrian Somers fp->link->name); 7811ae349f5Scvs2svn break; 7821ae349f5Scvs2svn case PROTO_CCP: 783dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 7843b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 7856d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 7861ae349f5Scvs2svn switch (fp->state) { 7871ae349f5Scvs2svn case ST_CLOSED: 7881ae349f5Scvs2svn case ST_CLOSING: 7891ae349f5Scvs2svn NewState(fp, ST_CLOSED); 7901ae349f5Scvs2svn default: 7911ae349f5Scvs2svn NewState(fp, ST_STOPPED); 7921ae349f5Scvs2svn break; 7931ae349f5Scvs2svn } 7946d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 795dc0fdb6bSBrian Somers } 7961ae349f5Scvs2svn break; 797673903ecSBrian Somers case PROTO_MP: 798673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 799673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 800673903ecSBrian Somers 801673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 802dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 803d47dceb8SBrian Somers fp->link->name); 804dd7e2610SBrian Somers fsm_Close(fp); 805673903ecSBrian Somers } 806673903ecSBrian Somers } 807673903ecSBrian Somers break; 8081ae349f5Scvs2svn } 809dd7e2610SBrian Somers mbuf_Free(bp); 8101ae349f5Scvs2svn } 8111ae349f5Scvs2svn 8121ae349f5Scvs2svn static void 8131ae349f5Scvs2svn FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 8141ae349f5Scvs2svn { 815dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 8161ae349f5Scvs2svn u_char *cp; 817fe3125a0SBrian Somers u_int32_t magic; 8181ae349f5Scvs2svn 819dc0fdb6bSBrian Somers if (lcp) { 8201ae349f5Scvs2svn cp = MBUF_CTOP(bp); 821fe3125a0SBrian Somers magic = ntohl(*(u_int32_t *)cp); 822dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 823dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: Error: His magic is bad!!\n", 824d47dceb8SBrian Somers fp->link->name); 8251ae349f5Scvs2svn /* XXX: We should send terminate request */ 8261ae349f5Scvs2svn } 8271ae349f5Scvs2svn if (fp->state == ST_OPENED) { 828fe3125a0SBrian Somers *(u_int32_t *)cp = htonl(lcp->want_magic); /* local magic */ 829dd7e2610SBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, mbuf_Length(bp)); 8301ae349f5Scvs2svn } 831dc0fdb6bSBrian Somers } 832dd7e2610SBrian Somers mbuf_Free(bp); 8331ae349f5Scvs2svn } 8341ae349f5Scvs2svn 8351ae349f5Scvs2svn static void 8361ae349f5Scvs2svn FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 8371ae349f5Scvs2svn { 838dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 839fe3125a0SBrian Somers u_int32_t magic; 8401ae349f5Scvs2svn 841dc0fdb6bSBrian Somers if (lcp) { 842fe3125a0SBrian Somers magic = ntohl(*(u_int32_t *)MBUF_CTOP(bp)); 843879ed6faSBrian Somers /* Tolerate echo replies with either magic number */ 844dc0fdb6bSBrian Somers if (magic != 0 && magic != lcp->his_magic && magic != lcp->want_magic) { 845dd7e2610SBrian Somers log_Printf(LogWARN, 846d47dceb8SBrian Somers "%s: RecvEchoRep: Bad magic: expected 0x%08x, got: 0x%08x\n", 847d47dceb8SBrian Somers fp->link->name, lcp->his_magic, magic); 8481ae349f5Scvs2svn /* 849fe3125a0SBrian Somers * XXX: We should send terminate request. But poor implementations may 850fe3125a0SBrian Somers * die as a result. 8511ae349f5Scvs2svn */ 8521ae349f5Scvs2svn } 853dd7e2610SBrian Somers lqr_RecvEcho(fp, bp); 854dc0fdb6bSBrian Somers } 855dd7e2610SBrian Somers mbuf_Free(bp); 8561ae349f5Scvs2svn } 8571ae349f5Scvs2svn 8581ae349f5Scvs2svn static void 8591ae349f5Scvs2svn FsmRecvDiscReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 8601ae349f5Scvs2svn { 861dd7e2610SBrian Somers mbuf_Free(bp); 8621ae349f5Scvs2svn } 8631ae349f5Scvs2svn 8641ae349f5Scvs2svn static void 8651ae349f5Scvs2svn FsmRecvIdent(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 8661ae349f5Scvs2svn { 867dd7e2610SBrian Somers mbuf_Free(bp); 8681ae349f5Scvs2svn } 8691ae349f5Scvs2svn 8701ae349f5Scvs2svn static void 8711ae349f5Scvs2svn FsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) 8721ae349f5Scvs2svn { 873dd7e2610SBrian Somers mbuf_Free(bp); 8741ae349f5Scvs2svn } 8751ae349f5Scvs2svn 8761ae349f5Scvs2svn static void 8771ae349f5Scvs2svn FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 8781ae349f5Scvs2svn { 879503a7782SBrian Somers (*fp->fn->RecvResetReq)(fp); 8801ae349f5Scvs2svn /* 8811ae349f5Scvs2svn * All sendable compressed packets are queued in the PRI_NORMAL modem 8821ae349f5Scvs2svn * output queue.... dump 'em to the priority queue so that they arrive 8831ae349f5Scvs2svn * at the peer before our ResetAck. 8841ae349f5Scvs2svn */ 8858c07a7b2SBrian Somers link_SequenceQueue(fp->link); 886dd7e2610SBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0); 887dd7e2610SBrian Somers mbuf_Free(bp); 8881ae349f5Scvs2svn } 8891ae349f5Scvs2svn 8901ae349f5Scvs2svn static void 8911ae349f5Scvs2svn FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 8921ae349f5Scvs2svn { 893503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 894dd7e2610SBrian Somers mbuf_Free(bp); 8951ae349f5Scvs2svn } 8961ae349f5Scvs2svn 8971ae349f5Scvs2svn void 898dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 8991ae349f5Scvs2svn { 9001ae349f5Scvs2svn int len; 9011ae349f5Scvs2svn struct fsmheader *lhp; 9021ae349f5Scvs2svn const struct fsmcodedesc *codep; 9031ae349f5Scvs2svn 904dd7e2610SBrian Somers len = mbuf_Length(bp); 9051ae349f5Scvs2svn if (len < sizeof(struct fsmheader)) { 906dd7e2610SBrian Somers mbuf_Free(bp); 9071ae349f5Scvs2svn return; 9081ae349f5Scvs2svn } 9091ae349f5Scvs2svn lhp = (struct fsmheader *) MBUF_CTOP(bp); 9103b0f8d2eSBrian Somers if (lhp->code < fp->min_code || lhp->code > fp->max_code || 9117308ec68SBrian Somers lhp->code > sizeof FsmCodes / sizeof *FsmCodes) { 9123b0f8d2eSBrian Somers /* 9133b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 9143b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 9153b0f8d2eSBrian Somers */ 9163b0f8d2eSBrian Somers static u_char id; 917dd7e2610SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->cnt); 918dd7e2610SBrian Somers mbuf_Free(bp); 9191ae349f5Scvs2svn return; 9201ae349f5Scvs2svn } 9211ae349f5Scvs2svn bp->offset += sizeof(struct fsmheader); 9221ae349f5Scvs2svn bp->cnt -= sizeof(struct fsmheader); 9231ae349f5Scvs2svn 9241ae349f5Scvs2svn codep = FsmCodes + lhp->code - 1; 9251342caedSBrian Somers if (lhp->id != fp->reqid && codep->check_reqid && 9261342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 927dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 928d47dceb8SBrian Somers fp->link->name, codep->name, lhp->id, fp->reqid); 9292267893fSBrian Somers return; 9302267893fSBrian Somers } 9312267893fSBrian Somers 932dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 933d47dceb8SBrian Somers fp->link->name, codep->name, lhp->id, State2Nam(fp->state)); 9342267893fSBrian Somers 935dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 936dd7e2610SBrian Somers mbuf_Log(); 9372267893fSBrian Somers 9382267893fSBrian Somers if (codep->inc_reqid && (lhp->id == fp->reqid || 9391342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 9402267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 9412267893fSBrian Somers 9421342caedSBrian Somers (*codep->recv)(fp, lhp, bp); 9432267893fSBrian Somers 944dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 945dd7e2610SBrian Somers mbuf_Log(); 9461ae349f5Scvs2svn } 947503a7782SBrian Somers 948503a7782SBrian Somers void 949dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 950503a7782SBrian Somers { 951dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 952d47dceb8SBrian Somers fp->link->name); 953503a7782SBrian Somers } 954503a7782SBrian Somers 955503a7782SBrian Somers void 956dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 957503a7782SBrian Somers { 958dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 959d47dceb8SBrian Somers fp->link->name); 960503a7782SBrian Somers } 961