165309e5cSBrian Somers /*- 2*1de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*1de7b4b8SPedro F. Giffuni * 465309e5cSBrian Somers * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 565309e5cSBrian Somers * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 665309e5cSBrian Somers * Internet Initiative Japan, Inc (IIJ) 765309e5cSBrian Somers * All rights reserved. 8af57ed9fSAtsushi Murai * 965309e5cSBrian Somers * Redistribution and use in source and binary forms, with or without 1065309e5cSBrian Somers * modification, are permitted provided that the following conditions 1165309e5cSBrian Somers * are met: 1265309e5cSBrian Somers * 1. Redistributions of source code must retain the above copyright 1365309e5cSBrian Somers * notice, this list of conditions and the following disclaimer. 1465309e5cSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 1565309e5cSBrian Somers * notice, this list of conditions and the following disclaimer in the 1665309e5cSBrian Somers * documentation and/or other materials provided with the distribution. 17af57ed9fSAtsushi Murai * 1865309e5cSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1965309e5cSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2065309e5cSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2165309e5cSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2265309e5cSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2365309e5cSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2465309e5cSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2565309e5cSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2665309e5cSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2765309e5cSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2865309e5cSBrian Somers * SUCH DAMAGE. 29af57ed9fSAtsushi Murai * 3097d92980SPeter Wemm * $FreeBSD$ 31af57ed9fSAtsushi Murai */ 3275240ed1SBrian Somers 33972a1bcfSBrian Somers #include <sys/param.h> 341342caedSBrian Somers #include <netinet/in.h> 351342caedSBrian Somers #include <netinet/in_systm.h> 361342caedSBrian Somers #include <netinet/ip.h> 3730949fd4SBrian Somers #include <sys/socket.h> 381fa665f5SBrian Somers #include <sys/un.h> 391ae349f5Scvs2svn 4075240ed1SBrian Somers #include <string.h> 4175240ed1SBrian Somers #include <termios.h> 4275240ed1SBrian Somers 435d9e6103SBrian Somers #include "layer.h" 449e8ec64bSBrian Somers #include "ua.h" 4575240ed1SBrian Somers #include "mbuf.h" 4675240ed1SBrian Somers #include "log.h" 4775240ed1SBrian Somers #include "defs.h" 4875240ed1SBrian Somers #include "timer.h" 49af57ed9fSAtsushi Murai #include "fsm.h" 501342caedSBrian Somers #include "iplist.h" 51af57ed9fSAtsushi Murai #include "lqr.h" 52879ed6faSBrian Somers #include "hdlc.h" 531342caedSBrian Somers #include "throughput.h" 541342caedSBrian Somers #include "slcompress.h" 5530949fd4SBrian Somers #include "ncpaddr.h" 561342caedSBrian Somers #include "ipcp.h" 571342caedSBrian Somers #include "filter.h" 581342caedSBrian Somers #include "descriptor.h" 59af57ed9fSAtsushi Murai #include "lcp.h" 60ed6a16c1SPoul-Henning Kamp #include "ccp.h" 618c07a7b2SBrian Somers #include "link.h" 621342caedSBrian Somers #include "mp.h" 63972a1bcfSBrian Somers #ifndef NORADIUS 64972a1bcfSBrian Somers #include "radius.h" 65972a1bcfSBrian Somers #endif 6630949fd4SBrian Somers #include "ipv6cp.h" 6730949fd4SBrian Somers #include "ncp.h" 681342caedSBrian Somers #include "bundle.h" 691342caedSBrian Somers #include "async.h" 7063b73463SBrian Somers #include "physical.h" 715d9e6103SBrian Somers #include "proto.h" 7275240ed1SBrian Somers 7375240ed1SBrian Somers static void FsmSendConfigReq(struct fsm *); 7475240ed1SBrian Somers static void FsmSendTerminateReq(struct fsm *); 75479508cfSBrian Somers static void FsmInitRestartCounter(struct fsm *, int); 76af57ed9fSAtsushi Murai 772267893fSBrian Somers typedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *); 782267893fSBrian Somers static recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak, 792267893fSBrian Somers FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck, 802267893fSBrian Somers FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq, 812267893fSBrian Somers FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent, 822267893fSBrian Somers FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck; 832267893fSBrian Somers 842267893fSBrian Somers static const struct fsmcodedesc { 852267893fSBrian Somers recvfn *recv; 862267893fSBrian Somers unsigned check_reqid : 1; 872267893fSBrian Somers unsigned inc_reqid : 1; 882267893fSBrian Somers const char *name; 892267893fSBrian Somers } FsmCodes[] = { 902267893fSBrian Somers { FsmRecvConfigReq, 0, 0, "ConfigReq" }, 912267893fSBrian Somers { FsmRecvConfigAck, 1, 1, "ConfigAck" }, 922267893fSBrian Somers { FsmRecvConfigNak, 1, 1, "ConfigNak" }, 932267893fSBrian Somers { FsmRecvConfigRej, 1, 1, "ConfigRej" }, 942267893fSBrian Somers { FsmRecvTermReq, 0, 0, "TerminateReq" }, 952267893fSBrian Somers { FsmRecvTermAck, 1, 1, "TerminateAck" }, 962267893fSBrian Somers { FsmRecvCodeRej, 0, 0, "CodeRej" }, 972267893fSBrian Somers { FsmRecvProtoRej, 0, 0, "ProtocolRej" }, 982267893fSBrian Somers { FsmRecvEchoReq, 0, 0, "EchoRequest" }, 992267893fSBrian Somers { FsmRecvEchoRep, 0, 0, "EchoReply" }, 1002267893fSBrian Somers { FsmRecvDiscReq, 0, 0, "DiscardReq" }, 1011038894eSBrian Somers { FsmRecvIdent, 0, 1, "Ident" }, 1022267893fSBrian Somers { FsmRecvTimeRemain,0, 0, "TimeRemain" }, 1035d9e6103SBrian Somers { FsmRecvResetReq, 0, 0, "ResetReq" }, 1042267893fSBrian Somers { FsmRecvResetAck, 0, 1, "ResetAck" } 1052267893fSBrian Somers }; 1062267893fSBrian Somers 1072267893fSBrian Somers static const char * 1082267893fSBrian Somers Code2Nam(u_int code) 1092267893fSBrian Somers { 1102267893fSBrian Somers if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0]) 1112267893fSBrian Somers return "Unknown"; 1122267893fSBrian Somers return FsmCodes[code-1].name; 1132267893fSBrian Somers } 1142267893fSBrian Somers 1151e991daaSBrian Somers const char * 1161e991daaSBrian Somers State2Nam(u_int state) 1171e991daaSBrian Somers { 118182c898aSBrian Somers static const char * const StateNames[] = { 119af57ed9fSAtsushi Murai "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", 120927145beSBrian Somers "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", 121af57ed9fSAtsushi Murai }; 122af57ed9fSAtsushi Murai 1231e991daaSBrian Somers if (state >= sizeof StateNames / sizeof StateNames[0]) 1241e991daaSBrian Somers return "unknown"; 1251e991daaSBrian Somers return StateNames[state]; 1261e991daaSBrian Somers } 1271e991daaSBrian Somers 12871144dc5SBrian Somers static void 129b6e82f33SBrian Somers StoppedTimeout(void *v) 13071144dc5SBrian Somers { 131b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 132b6e82f33SBrian Somers 133dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name); 13449b239e0SBrian Somers if (fp->OpenTimer.state == TIMER_RUNNING) { 135dd7e2610SBrian Somers log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n", 136d47dceb8SBrian Somers fp->link->name, fp->name); 137dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 13849b239e0SBrian Somers } 13909206a6fSBrian Somers if (fp->state == ST_STOPPED) 14009206a6fSBrian Somers fsm2initial(fp); 14171144dc5SBrian Somers } 14271144dc5SBrian Somers 143af57ed9fSAtsushi Murai void 1443b0f8d2eSBrian Somers fsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, 145479508cfSBrian Somers int maxcode, int LogLevel, struct bundle *bundle, 1463b0f8d2eSBrian Somers struct link *l, const struct fsm_parent *parent, 147182c898aSBrian Somers struct fsm_callbacks *fn, const char * const timer_names[3]) 148af57ed9fSAtsushi Murai { 149503a7782SBrian Somers fp->name = name; 150503a7782SBrian Somers fp->proto = proto; 1513b0f8d2eSBrian Somers fp->min_code = mincode; 152503a7782SBrian Somers fp->max_code = maxcode; 1533b0f8d2eSBrian Somers fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; 154af57ed9fSAtsushi Murai fp->reqid = 1; 155af57ed9fSAtsushi Murai fp->restart = 1; 1565d9e6103SBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = 3; 157503a7782SBrian Somers memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); 158503a7782SBrian Somers memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); 159503a7782SBrian Somers memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); 160503a7782SBrian Somers fp->LogLevel = LogLevel; 1618c07a7b2SBrian Somers fp->link = l; 1627a6f8720SBrian Somers fp->bundle = bundle; 1636d666775SBrian Somers fp->parent = parent; 164503a7782SBrian Somers fp->fn = fn; 1653b0f8d2eSBrian Somers fp->FsmTimer.name = timer_names[0]; 1663b0f8d2eSBrian Somers fp->OpenTimer.name = timer_names[1]; 1673b0f8d2eSBrian Somers fp->StoppedTimer.name = timer_names[2]; 168af57ed9fSAtsushi Murai } 169af57ed9fSAtsushi Murai 17075240ed1SBrian Somers static void 171944f7098SBrian Somers NewState(struct fsm *fp, int new) 172af57ed9fSAtsushi Murai { 173dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", 174d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state), State2Nam(new)); 175cb611434SBrian Somers if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) 176dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 177af57ed9fSAtsushi Murai fp->state = new; 17871144dc5SBrian Somers if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { 179dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 180cb611434SBrian Somers if (new == ST_STOPPED && fp->StoppedTimer.load) { 181dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 182cb611434SBrian Somers fp->StoppedTimer.func = StoppedTimeout; 183cb611434SBrian Somers fp->StoppedTimer.arg = (void *) fp; 184dd7e2610SBrian Somers timer_Start(&fp->StoppedTimer); 18571144dc5SBrian Somers } 18671144dc5SBrian Somers } 187af57ed9fSAtsushi Murai } 188af57ed9fSAtsushi Murai 189af57ed9fSAtsushi Murai void 190057f1760SBrian Somers fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, unsigned count, 191411675baSBrian Somers int mtype) 192af57ed9fSAtsushi Murai { 193af57ed9fSAtsushi Murai int plen; 194af57ed9fSAtsushi Murai struct fsmheader lh; 195af57ed9fSAtsushi Murai struct mbuf *bp; 196af57ed9fSAtsushi Murai 197dd7e2610SBrian Somers if (log_IsKept(fp->LogLevel)) { 198dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 199d47dceb8SBrian Somers fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 2002267893fSBrian Somers switch (code) { 2012267893fSBrian Somers case CODE_CONFIGREQ: 2022267893fSBrian Somers case CODE_CONFIGACK: 2032267893fSBrian Somers case CODE_CONFIGREJ: 2042267893fSBrian Somers case CODE_CONFIGNAK: 205ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, ptr, ptr + count, MODE_NOP, NULL); 206ff360cc9SBrian Somers if (count < sizeof(struct fsm_opt_hdr)) 207dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 2082267893fSBrian Somers break; 2092267893fSBrian Somers } 2102267893fSBrian Somers } 2112267893fSBrian Somers 212af57ed9fSAtsushi Murai plen = sizeof(struct fsmheader) + count; 213af57ed9fSAtsushi Murai lh.code = code; 214af57ed9fSAtsushi Murai lh.id = id; 215af57ed9fSAtsushi Murai lh.length = htons(plen); 21626af0ae9SBrian Somers bp = m_get(plen, mtype); 21775240ed1SBrian Somers memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 218af57ed9fSAtsushi Murai if (count) 21975240ed1SBrian Somers memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 220dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "fsm_Output", bp); 221442f8495SBrian Somers link_PushPacket(fp->link, bp, fp->bundle, LINK_QUEUES(fp->link) - 1, 222442f8495SBrian Somers fp->proto); 2231038894eSBrian Somers 2241038894eSBrian Somers if (code == CODE_CONFIGREJ) 2251038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 226af57ed9fSAtsushi Murai } 227af57ed9fSAtsushi Murai 22849b239e0SBrian Somers static void 22949b239e0SBrian Somers FsmOpenNow(void *v) 23049b239e0SBrian Somers { 23149b239e0SBrian Somers struct fsm *fp = (struct fsm *)v; 23249b239e0SBrian Somers 233dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 23449b239e0SBrian Somers if (fp->state <= ST_STOPPED) { 2353a2e4f62SBrian Somers if (fp->state != ST_STARTING) { 2363a2e4f62SBrian Somers /* 2373a2e4f62SBrian Somers * In practice, we're only here in ST_STOPPED (when delaying the 2383a2e4f62SBrian Somers * first config request) or ST_CLOSED (when openmode == 0). 2393a2e4f62SBrian Somers * 2403a2e4f62SBrian Somers * The ST_STOPPED bit is breaking the RFC already :-( 2413a2e4f62SBrian Somers * 2423a2e4f62SBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 2433a2e4f62SBrian Somers * required for an Open event when state == Closed, but the RFC 2443a2e4f62SBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 2453a2e4f62SBrian Somers * ie, Initial gets an `Up' event, Closing gets a RTA etc. 2463a2e4f62SBrian Somers */ 2473a2e4f62SBrian Somers (*fp->fn->LayerStart)(fp); 2483a2e4f62SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 2493a2e4f62SBrian Somers } 250479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 25149b239e0SBrian Somers FsmSendConfigReq(fp); 25249b239e0SBrian Somers NewState(fp, ST_REQSENT); 25349b239e0SBrian Somers } 25449b239e0SBrian Somers } 25549b239e0SBrian Somers 256af57ed9fSAtsushi Murai void 257dd7e2610SBrian Somers fsm_Open(struct fsm *fp) 258af57ed9fSAtsushi Murai { 259af57ed9fSAtsushi Murai switch (fp->state) { 260af57ed9fSAtsushi Murai case ST_INITIAL: 261af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 2626d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2636d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 264af57ed9fSAtsushi Murai break; 265af57ed9fSAtsushi Murai case ST_CLOSED: 266af57ed9fSAtsushi Murai if (fp->open_mode == OPEN_PASSIVE) { 2673a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 26849b239e0SBrian Somers } else if (fp->open_mode > 0) { 26949b239e0SBrian Somers if (fp->open_mode > 1) 270dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 271d47dceb8SBrian Somers fp->link->name, fp->open_mode); 2723a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 273dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 27449b239e0SBrian Somers fp->OpenTimer.load = fp->open_mode * SECTICKS; 27549b239e0SBrian Somers fp->OpenTimer.func = FsmOpenNow; 27649b239e0SBrian Somers fp->OpenTimer.arg = (void *)fp; 277dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 27849b239e0SBrian Somers } else 27949b239e0SBrian Somers FsmOpenNow(fp); 280af57ed9fSAtsushi Murai break; 281af57ed9fSAtsushi Murai case ST_STOPPED: /* XXX: restart option */ 282af57ed9fSAtsushi Murai case ST_REQSENT: 283af57ed9fSAtsushi Murai case ST_ACKRCVD: 284af57ed9fSAtsushi Murai case ST_ACKSENT: 285af57ed9fSAtsushi Murai case ST_OPENED: /* XXX: restart option */ 286af57ed9fSAtsushi Murai break; 287af57ed9fSAtsushi Murai case ST_CLOSING: /* XXX: restart option */ 288af57ed9fSAtsushi Murai case ST_STOPPING: /* XXX: restart option */ 289af57ed9fSAtsushi Murai NewState(fp, ST_STOPPING); 290af57ed9fSAtsushi Murai break; 291af57ed9fSAtsushi Murai } 292af57ed9fSAtsushi Murai } 293af57ed9fSAtsushi Murai 294af57ed9fSAtsushi Murai void 295dd7e2610SBrian Somers fsm_Up(struct fsm *fp) 296af57ed9fSAtsushi Murai { 297af57ed9fSAtsushi Murai switch (fp->state) { 298af57ed9fSAtsushi Murai case ST_INITIAL: 299dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 3001fa665f5SBrian Somers fp->link->name); 301af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 302af57ed9fSAtsushi Murai break; 303af57ed9fSAtsushi Murai case ST_STARTING: 304479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 305af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 306af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 307af57ed9fSAtsushi Murai break; 308af57ed9fSAtsushi Murai default: 309dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 310d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 311af57ed9fSAtsushi Murai break; 312af57ed9fSAtsushi Murai } 313af57ed9fSAtsushi Murai } 314af57ed9fSAtsushi Murai 315af57ed9fSAtsushi Murai void 316dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 317af57ed9fSAtsushi Murai { 318af57ed9fSAtsushi Murai switch (fp->state) { 319af57ed9fSAtsushi Murai case ST_CLOSED: 320af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 321af57ed9fSAtsushi Murai break; 322455aabc3SBrian Somers case ST_CLOSING: 3238a8d9927SBrian Somers /* This TLF contradicts the RFC (1661), which ``misses it out'' ! */ 3246d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 325455aabc3SBrian Somers NewState(fp, ST_INITIAL); 3266d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 327455aabc3SBrian Somers break; 328af57ed9fSAtsushi Murai case ST_STOPPED: 329455aabc3SBrian Somers NewState(fp, ST_STARTING); 3306d666775SBrian Somers (*fp->fn->LayerStart)(fp); 3316d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 332455aabc3SBrian Somers break; 333af57ed9fSAtsushi Murai case ST_STOPPING: 334af57ed9fSAtsushi Murai case ST_REQSENT: 335af57ed9fSAtsushi Murai case ST_ACKRCVD: 336af57ed9fSAtsushi Murai case ST_ACKSENT: 337af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 338af57ed9fSAtsushi Murai break; 339af57ed9fSAtsushi Murai case ST_OPENED: 3406d666775SBrian Somers (*fp->fn->LayerDown)(fp); 341af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 3426d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 343af57ed9fSAtsushi Murai break; 344af57ed9fSAtsushi Murai } 345af57ed9fSAtsushi Murai } 346af57ed9fSAtsushi Murai 347af57ed9fSAtsushi Murai void 348dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 349af57ed9fSAtsushi Murai { 350af57ed9fSAtsushi Murai switch (fp->state) { 351af57ed9fSAtsushi Murai case ST_STARTING: 3526d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 353af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 3546d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 355af57ed9fSAtsushi Murai break; 356af57ed9fSAtsushi Murai case ST_STOPPED: 357af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 358af57ed9fSAtsushi Murai break; 359af57ed9fSAtsushi Murai case ST_STOPPING: 360af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 361af57ed9fSAtsushi Murai break; 362af57ed9fSAtsushi Murai case ST_OPENED: 3636d666775SBrian Somers (*fp->fn->LayerDown)(fp); 36415c8dc2aSBrian Somers if (fp->state == ST_OPENED) { 365479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 366455aabc3SBrian Somers FsmSendTerminateReq(fp); 367455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3686d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 36915c8dc2aSBrian Somers } 370455aabc3SBrian Somers break; 371af57ed9fSAtsushi Murai case ST_REQSENT: 372af57ed9fSAtsushi Murai case ST_ACKRCVD: 373af57ed9fSAtsushi Murai case ST_ACKSENT: 374479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 375af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 376af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 377af57ed9fSAtsushi Murai break; 378af57ed9fSAtsushi Murai } 379af57ed9fSAtsushi Murai } 380af57ed9fSAtsushi Murai 381af57ed9fSAtsushi Murai /* 382af57ed9fSAtsushi Murai * Send functions 383af57ed9fSAtsushi Murai */ 38475240ed1SBrian Somers static void 385944f7098SBrian Somers FsmSendConfigReq(struct fsm *fp) 386af57ed9fSAtsushi Murai { 387479508cfSBrian Somers if (fp->more.reqs-- > 0 && fp->restart-- > 0) { 38883d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 389dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 390af57ed9fSAtsushi Murai } else { 391479508cfSBrian Somers if (fp->more.reqs < 0) 392479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REQs sent - abandoning " 393479508cfSBrian Somers "negotiation\n", fp->link->name, fp->name); 3941038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 395dd7e2610SBrian Somers fsm_Close(fp); 396af57ed9fSAtsushi Murai } 397af57ed9fSAtsushi Murai } 398af57ed9fSAtsushi Murai 39975240ed1SBrian Somers static void 400944f7098SBrian Somers FsmSendTerminateReq(struct fsm *fp) 401af57ed9fSAtsushi Murai { 402411675baSBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0, MB_UNKNOWN); 4032267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 404dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 405af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 406af57ed9fSAtsushi Murai } 407af57ed9fSAtsushi Murai 408af57ed9fSAtsushi Murai /* 409af57ed9fSAtsushi Murai * Timeout actions 410af57ed9fSAtsushi Murai */ 41175240ed1SBrian Somers static void 412b6e82f33SBrian Somers FsmTimeout(void *v) 413af57ed9fSAtsushi Murai { 414b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 415b6e82f33SBrian Somers 416af57ed9fSAtsushi Murai if (fp->restart) { 417af57ed9fSAtsushi Murai switch (fp->state) { 418af57ed9fSAtsushi Murai case ST_CLOSING: 419af57ed9fSAtsushi Murai case ST_STOPPING: 420af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 421af57ed9fSAtsushi Murai break; 422af57ed9fSAtsushi Murai case ST_REQSENT: 423af57ed9fSAtsushi Murai case ST_ACKSENT: 424af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 425af57ed9fSAtsushi Murai break; 426af57ed9fSAtsushi Murai case ST_ACKRCVD: 427af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 428af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 429af57ed9fSAtsushi Murai break; 430af57ed9fSAtsushi Murai } 431dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 432af57ed9fSAtsushi Murai } else { 433af57ed9fSAtsushi Murai switch (fp->state) { 434af57ed9fSAtsushi Murai case ST_CLOSING: 4356d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 436af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 4376d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 438af57ed9fSAtsushi Murai break; 439af57ed9fSAtsushi Murai case ST_STOPPING: 4406d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 441af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4426d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 443af57ed9fSAtsushi Murai break; 444af57ed9fSAtsushi Murai case ST_REQSENT: /* XXX: 3p */ 445af57ed9fSAtsushi Murai case ST_ACKSENT: 446af57ed9fSAtsushi Murai case ST_ACKRCVD: 4476d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 448af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4496d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 450af57ed9fSAtsushi Murai break; 451af57ed9fSAtsushi Murai } 452af57ed9fSAtsushi Murai } 453af57ed9fSAtsushi Murai } 454af57ed9fSAtsushi Murai 45575240ed1SBrian Somers static void 456479508cfSBrian Somers FsmInitRestartCounter(struct fsm *fp, int what) 457af57ed9fSAtsushi Murai { 458dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 459af57ed9fSAtsushi Murai fp->FsmTimer.func = FsmTimeout; 460af57ed9fSAtsushi Murai fp->FsmTimer.arg = (void *)fp; 461479508cfSBrian Somers (*fp->fn->InitRestartCounter)(fp, what); 462af57ed9fSAtsushi Murai } 463af57ed9fSAtsushi Murai 464af57ed9fSAtsushi Murai /* 465af57ed9fSAtsushi Murai * Actions when receive packets 466af57ed9fSAtsushi Murai */ 46775240ed1SBrian Somers static void 468944f7098SBrian Somers FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 469944f7098SBrian Somers /* RCR */ 470af57ed9fSAtsushi Murai { 47130c2f2ffSBrian Somers struct fsm_decode dec; 47253c9f6c0SAtsushi Murai int plen, flen; 473af57ed9fSAtsushi Murai int ackaction = 0; 474ff360cc9SBrian Somers u_char *cp; 475af57ed9fSAtsushi Murai 476ff360cc9SBrian Somers bp = m_pullup(bp); 47726af0ae9SBrian Somers plen = m_length(bp); 47870ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 47953c9f6c0SAtsushi Murai if (plen < flen) { 480a33b2ef7SBrian Somers log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 481d47dceb8SBrian Somers fp->link->name, plen, flen); 48226af0ae9SBrian Somers m_freem(bp); 483af57ed9fSAtsushi Murai return; 484af57ed9fSAtsushi Murai } 485af57ed9fSAtsushi Murai 486d14cc5f9SBrian Somers /* Some things must be done before we Decode the packet */ 487d14cc5f9SBrian Somers switch (fp->state) { 488d14cc5f9SBrian Somers case ST_OPENED: 489d14cc5f9SBrian Somers (*fp->fn->LayerDown)(fp); 490d14cc5f9SBrian Somers } 491d14cc5f9SBrian Somers 492ff360cc9SBrian Somers dec.ackend = dec.ack; 493ff360cc9SBrian Somers dec.nakend = dec.nak; 494ff360cc9SBrian Somers dec.rejend = dec.rej; 495ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 496ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_REQ, &dec); 497057f1760SBrian Somers if (flen < (int)sizeof(struct fsm_opt_hdr)) 498ff360cc9SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 499ff360cc9SBrian Somers 500ff360cc9SBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 501ff360cc9SBrian Somers ackaction = 1; 502ff360cc9SBrian Somers 5033377c28cSBrian Somers /* Check and process easy case */ 504af57ed9fSAtsushi Murai switch (fp->state) { 505af57ed9fSAtsushi Murai case ST_INITIAL: 50606337856SBrian Somers if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 50706337856SBrian Somers /* 50806337856SBrian Somers * ccp_SetOpenMode() leaves us in initial if we're disabling 5095d9e6103SBrian Somers * & denying everything. 51006337856SBrian Somers */ 51126af0ae9SBrian Somers bp = m_prepend(bp, lhp, sizeof *lhp, 2); 5125d9e6103SBrian Somers bp = proto_Prepend(bp, fp->proto, 0, 0); 51326af0ae9SBrian Somers bp = m_pullup(bp); 51426af0ae9SBrian Somers lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->m_len); 51526af0ae9SBrian Somers m_freem(bp); 51606337856SBrian Somers return; 51706337856SBrian Somers } 51806337856SBrian Somers /* Drop through */ 519af57ed9fSAtsushi Murai case ST_STARTING: 520dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 521d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 52226af0ae9SBrian Somers m_freem(bp); 523af57ed9fSAtsushi Murai return; 524af57ed9fSAtsushi Murai case ST_CLOSED: 5252267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 52626af0ae9SBrian Somers m_freem(bp); 527af57ed9fSAtsushi Murai return; 528af57ed9fSAtsushi Murai case ST_CLOSING: 529dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 530d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 531a9c503afSBrian Somers case ST_STOPPING: 53226af0ae9SBrian Somers m_freem(bp); 533af57ed9fSAtsushi Murai return; 534af57ed9fSAtsushi Murai case ST_STOPPED: 535479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 536d14cc5f9SBrian Somers /* Drop through */ 53768a0e171SBrian Somers case ST_OPENED: 538af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 539af57ed9fSAtsushi Murai break; 540af57ed9fSAtsushi Murai } 541af57ed9fSAtsushi Murai 54230c2f2ffSBrian Somers if (dec.rejend != dec.rej) 543411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej, 544411675baSBrian Somers MB_UNKNOWN); 54530c2f2ffSBrian Somers if (dec.nakend != dec.nak) 546411675baSBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak, 547411675baSBrian Somers MB_UNKNOWN); 548af57ed9fSAtsushi Murai if (ackaction) 549411675baSBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack, 550411675baSBrian Somers MB_UNKNOWN); 551af57ed9fSAtsushi Murai 552af57ed9fSAtsushi Murai switch (fp->state) { 553455aabc3SBrian Somers case ST_STOPPED: 554479508cfSBrian Somers /* 555479508cfSBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 556479508cfSBrian Somers * required for a RCR when state == ST_STOPPED, but the RFC 557479508cfSBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 558479508cfSBrian Somers */ 559479508cfSBrian Somers (*fp->fn->LayerStart)(fp); 560479508cfSBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 561f0067240SPhilippe Charnier /* FALLTHROUGH */ 562479508cfSBrian Somers 563479508cfSBrian Somers case ST_OPENED: 564af57ed9fSAtsushi Murai if (ackaction) 565af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 566af57ed9fSAtsushi Murai else 567af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 56830949fd4SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 569af57ed9fSAtsushi Murai break; 570af57ed9fSAtsushi Murai case ST_REQSENT: 571af57ed9fSAtsushi Murai if (ackaction) 572af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 573af57ed9fSAtsushi Murai break; 574af57ed9fSAtsushi Murai case ST_ACKRCVD: 575af57ed9fSAtsushi Murai if (ackaction) { 576af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5776f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5786d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5796f384573SBrian Somers else { 5806f384573SBrian Somers (*fp->fn->LayerDown)(fp); 581479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 5826f384573SBrian Somers FsmSendTerminateReq(fp); 5836f384573SBrian Somers NewState(fp, ST_CLOSING); 5841038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 5856f384573SBrian Somers } 586af57ed9fSAtsushi Murai } 587af57ed9fSAtsushi Murai break; 588af57ed9fSAtsushi Murai case ST_ACKSENT: 589af57ed9fSAtsushi Murai if (!ackaction) 590af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 591af57ed9fSAtsushi Murai break; 592af57ed9fSAtsushi Murai } 59326af0ae9SBrian Somers m_freem(bp); 594479508cfSBrian Somers 595479508cfSBrian Somers if (dec.rejend != dec.rej && --fp->more.rejs <= 0) { 596479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REJs sent - abandoning negotiation\n", 597479508cfSBrian Somers fp->link->name, fp->name); 5981038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 599479508cfSBrian Somers fsm_Close(fp); 600479508cfSBrian Somers } 601479508cfSBrian Somers 602479508cfSBrian Somers if (dec.nakend != dec.nak && --fp->more.naks <= 0) { 603479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s NAKs sent - abandoning negotiation\n", 604479508cfSBrian Somers fp->link->name, fp->name); 6051038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 606479508cfSBrian Somers fsm_Close(fp); 607479508cfSBrian Somers } 608af57ed9fSAtsushi Murai } 609af57ed9fSAtsushi Murai 61075240ed1SBrian Somers static void 611944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 612944f7098SBrian Somers /* RCA */ 613af57ed9fSAtsushi Murai { 614ff360cc9SBrian Somers struct fsm_decode dec; 615ff360cc9SBrian Somers int plen, flen; 616ff360cc9SBrian Somers u_char *cp; 617ff360cc9SBrian Somers 618ff360cc9SBrian Somers plen = m_length(bp); 619ff360cc9SBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 620ff360cc9SBrian Somers if (plen < flen) { 621ff360cc9SBrian Somers m_freem(bp); 622ff360cc9SBrian Somers return; 623ff360cc9SBrian Somers } 624ff360cc9SBrian Somers 625ff360cc9SBrian Somers bp = m_pullup(bp); 626ff360cc9SBrian Somers dec.ackend = dec.ack; 627ff360cc9SBrian Somers dec.nakend = dec.nak; 628ff360cc9SBrian Somers dec.rejend = dec.rej; 629ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 630ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_ACK, &dec); 631057f1760SBrian Somers if (flen < (int)sizeof(struct fsm_opt_hdr)) 632ff360cc9SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 633ff360cc9SBrian Somers 634af57ed9fSAtsushi Murai switch (fp->state) { 635af57ed9fSAtsushi Murai case ST_CLOSED: 636af57ed9fSAtsushi Murai case ST_STOPPED: 6372267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 638af57ed9fSAtsushi Murai break; 639af57ed9fSAtsushi Murai case ST_CLOSING: 640af57ed9fSAtsushi Murai case ST_STOPPING: 641af57ed9fSAtsushi Murai break; 642af57ed9fSAtsushi Murai case ST_REQSENT: 643479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 644af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 645af57ed9fSAtsushi Murai break; 646af57ed9fSAtsushi Murai case ST_ACKRCVD: 647af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 648af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 649af57ed9fSAtsushi Murai break; 650af57ed9fSAtsushi Murai case ST_ACKSENT: 651479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 652af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 6536f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 6546d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 6556f384573SBrian Somers else { 6566f384573SBrian Somers (*fp->fn->LayerDown)(fp); 657479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 6586f384573SBrian Somers FsmSendTerminateReq(fp); 6596f384573SBrian Somers NewState(fp, ST_CLOSING); 6601038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 6616f384573SBrian Somers } 662af57ed9fSAtsushi Murai break; 663af57ed9fSAtsushi Murai case ST_OPENED: 6646d666775SBrian Somers (*fp->fn->LayerDown)(fp); 665af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 666af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 6676d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 668af57ed9fSAtsushi Murai break; 669af57ed9fSAtsushi Murai } 67026af0ae9SBrian Somers m_freem(bp); 671af57ed9fSAtsushi Murai } 672af57ed9fSAtsushi Murai 67375240ed1SBrian Somers static void 674944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 675944f7098SBrian Somers /* RCN */ 676af57ed9fSAtsushi Murai { 67730c2f2ffSBrian Somers struct fsm_decode dec; 67853c9f6c0SAtsushi Murai int plen, flen; 679ff360cc9SBrian Somers u_char *cp; 680af57ed9fSAtsushi Murai 68126af0ae9SBrian Somers plen = m_length(bp); 68270ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 68353c9f6c0SAtsushi Murai if (plen < flen) { 68426af0ae9SBrian Somers m_freem(bp); 685af57ed9fSAtsushi Murai return; 686af57ed9fSAtsushi Murai } 687af57ed9fSAtsushi Murai 688af57ed9fSAtsushi Murai /* 689af57ed9fSAtsushi Murai * Check and process easy case 690af57ed9fSAtsushi Murai */ 691af57ed9fSAtsushi Murai switch (fp->state) { 692af57ed9fSAtsushi Murai case ST_INITIAL: 693af57ed9fSAtsushi Murai case ST_STARTING: 694dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 695d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 69626af0ae9SBrian Somers m_freem(bp); 697af57ed9fSAtsushi Murai return; 698af57ed9fSAtsushi Murai case ST_CLOSED: 699af57ed9fSAtsushi Murai case ST_STOPPED: 7002267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 70126af0ae9SBrian Somers m_freem(bp); 702af57ed9fSAtsushi Murai return; 703af57ed9fSAtsushi Murai case ST_CLOSING: 704af57ed9fSAtsushi Murai case ST_STOPPING: 70526af0ae9SBrian Somers m_freem(bp); 706af57ed9fSAtsushi Murai return; 707af57ed9fSAtsushi Murai } 708af57ed9fSAtsushi Murai 70926af0ae9SBrian Somers bp = m_pullup(bp); 71030c2f2ffSBrian Somers dec.ackend = dec.ack; 71130c2f2ffSBrian Somers dec.nakend = dec.nak; 71230c2f2ffSBrian Somers dec.rejend = dec.rej; 713ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 714ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_NAK, &dec); 715057f1760SBrian Somers if (flen < (int)sizeof(struct fsm_opt_hdr)) 716dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 717af57ed9fSAtsushi Murai 718af57ed9fSAtsushi Murai switch (fp->state) { 719af57ed9fSAtsushi Murai case ST_REQSENT: 720af57ed9fSAtsushi Murai case ST_ACKSENT: 721479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 722af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 723af57ed9fSAtsushi Murai break; 724af57ed9fSAtsushi Murai case ST_OPENED: 7256d666775SBrian Somers (*fp->fn->LayerDown)(fp); 726455aabc3SBrian Somers FsmSendConfigReq(fp); 727455aabc3SBrian Somers NewState(fp, ST_REQSENT); 7286d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 729455aabc3SBrian Somers break; 730af57ed9fSAtsushi Murai case ST_ACKRCVD: 731af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 732af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 733af57ed9fSAtsushi Murai break; 734af57ed9fSAtsushi Murai } 735af57ed9fSAtsushi Murai 73626af0ae9SBrian Somers m_freem(bp); 737af57ed9fSAtsushi Murai } 738af57ed9fSAtsushi Murai 73975240ed1SBrian Somers static void 740944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 741944f7098SBrian Somers /* RTR */ 742af57ed9fSAtsushi Murai { 743af57ed9fSAtsushi Murai switch (fp->state) { 744af57ed9fSAtsushi Murai case ST_INITIAL: 745af57ed9fSAtsushi Murai case ST_STARTING: 746dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 747d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 748af57ed9fSAtsushi Murai break; 749af57ed9fSAtsushi Murai case ST_CLOSED: 750af57ed9fSAtsushi Murai case ST_STOPPED: 751af57ed9fSAtsushi Murai case ST_CLOSING: 752af57ed9fSAtsushi Murai case ST_STOPPING: 753af57ed9fSAtsushi Murai case ST_REQSENT: 7542267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 755af57ed9fSAtsushi Murai break; 756af57ed9fSAtsushi Murai case ST_ACKRCVD: 757af57ed9fSAtsushi Murai case ST_ACKSENT: 7582267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 759af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 760af57ed9fSAtsushi Murai break; 761af57ed9fSAtsushi Murai case ST_OPENED: 7626d666775SBrian Somers (*fp->fn->LayerDown)(fp); 7632267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 764479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 765dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 7668f2fa0eeSBrian Somers fp->restart = 0; 7678f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 7686d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 769479508cfSBrian Somers /* A delayed ST_STOPPED is now scheduled */ 770af57ed9fSAtsushi Murai break; 771af57ed9fSAtsushi Murai } 77226af0ae9SBrian Somers m_freem(bp); 773af57ed9fSAtsushi Murai } 774af57ed9fSAtsushi Murai 77575240ed1SBrian Somers static void 776057f1760SBrian Somers FsmRecvTermAck(struct fsm *fp, struct fsmheader *lhp __unused, struct mbuf *bp) 777944f7098SBrian Somers /* RTA */ 778af57ed9fSAtsushi Murai { 779af57ed9fSAtsushi Murai switch (fp->state) { 780af57ed9fSAtsushi Murai case ST_CLOSING: 7816d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 782af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 7836d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 784af57ed9fSAtsushi Murai break; 785af57ed9fSAtsushi Murai case ST_STOPPING: 7866d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 787af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 7886d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 789af57ed9fSAtsushi Murai break; 790af57ed9fSAtsushi Murai case ST_ACKRCVD: 791af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 792af57ed9fSAtsushi Murai break; 793af57ed9fSAtsushi Murai case ST_OPENED: 7946d666775SBrian Somers (*fp->fn->LayerDown)(fp); 795af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 796af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 7976d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 798af57ed9fSAtsushi Murai break; 799af57ed9fSAtsushi Murai } 80026af0ae9SBrian Somers m_freem(bp); 801af57ed9fSAtsushi Murai } 802af57ed9fSAtsushi Murai 80375240ed1SBrian Somers static void 804944f7098SBrian Somers FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 805944f7098SBrian Somers /* RCJ */ 806af57ed9fSAtsushi Murai { 80730c2f2ffSBrian Somers struct fsm_decode dec; 808057f1760SBrian Somers size_t plen; 809057f1760SBrian Somers int flen; 810ff360cc9SBrian Somers u_char *cp; 811af57ed9fSAtsushi Murai 81226af0ae9SBrian Somers plen = m_length(bp); 81370ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 814057f1760SBrian Somers if ((int)plen < flen) { 81526af0ae9SBrian Somers m_freem(bp); 816af57ed9fSAtsushi Murai return; 817af57ed9fSAtsushi Murai } 818af57ed9fSAtsushi Murai 8191038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 8201038894eSBrian Somers 821af57ed9fSAtsushi Murai /* 822af57ed9fSAtsushi Murai * Check and process easy case 823af57ed9fSAtsushi Murai */ 824af57ed9fSAtsushi Murai switch (fp->state) { 825af57ed9fSAtsushi Murai case ST_INITIAL: 826af57ed9fSAtsushi Murai case ST_STARTING: 827dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 828d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 82926af0ae9SBrian Somers m_freem(bp); 830af57ed9fSAtsushi Murai return; 831af57ed9fSAtsushi Murai case ST_CLOSED: 832af57ed9fSAtsushi Murai case ST_STOPPED: 8332267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 83426af0ae9SBrian Somers m_freem(bp); 835af57ed9fSAtsushi Murai return; 836af57ed9fSAtsushi Murai case ST_CLOSING: 837af57ed9fSAtsushi Murai case ST_STOPPING: 83826af0ae9SBrian Somers m_freem(bp); 839af57ed9fSAtsushi Murai return; 840af57ed9fSAtsushi Murai } 841af57ed9fSAtsushi Murai 84226af0ae9SBrian Somers bp = m_pullup(bp); 84330c2f2ffSBrian Somers dec.ackend = dec.ack; 84430c2f2ffSBrian Somers dec.nakend = dec.nak; 84530c2f2ffSBrian Somers dec.rejend = dec.rej; 846ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 847ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_REJ, &dec); 848057f1760SBrian Somers if (flen < (int)sizeof(struct fsm_opt_hdr)) 849dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 850af57ed9fSAtsushi Murai 851af57ed9fSAtsushi Murai switch (fp->state) { 852af57ed9fSAtsushi Murai case ST_REQSENT: 853af57ed9fSAtsushi Murai case ST_ACKSENT: 854479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 855af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 856af57ed9fSAtsushi Murai break; 857af57ed9fSAtsushi Murai case ST_OPENED: 8586d666775SBrian Somers (*fp->fn->LayerDown)(fp); 859455aabc3SBrian Somers FsmSendConfigReq(fp); 860455aabc3SBrian Somers NewState(fp, ST_REQSENT); 8616d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 862455aabc3SBrian Somers break; 863af57ed9fSAtsushi Murai case ST_ACKRCVD: 864af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 865af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 866af57ed9fSAtsushi Murai break; 867af57ed9fSAtsushi Murai } 86826af0ae9SBrian Somers m_freem(bp); 869af57ed9fSAtsushi Murai } 870af57ed9fSAtsushi Murai 87175240ed1SBrian Somers static void 872057f1760SBrian Somers FsmRecvCodeRej(struct fsm *fp __unused, struct fsmheader *lhp __unused, 873057f1760SBrian Somers struct mbuf *bp) 874af57ed9fSAtsushi Murai { 87526af0ae9SBrian Somers m_freem(bp); 876af57ed9fSAtsushi Murai } 877af57ed9fSAtsushi Murai 87875240ed1SBrian Somers static void 879057f1760SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp __unused, struct mbuf *bp) 880af57ed9fSAtsushi Murai { 8818c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 8823377c28cSBrian Somers u_short proto; 883af57ed9fSAtsushi Murai 88426af0ae9SBrian Somers if (m_length(bp) < 2) { 88526af0ae9SBrian Somers m_freem(bp); 8863377c28cSBrian Somers return; 8873377c28cSBrian Somers } 8883377c28cSBrian Somers bp = mbuf_Read(bp, &proto, 2); 8893377c28cSBrian Somers proto = ntohs(proto); 890dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 891d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 892af57ed9fSAtsushi Murai 893af57ed9fSAtsushi Murai switch (proto) { 894af57ed9fSAtsushi Murai case PROTO_LQR: 8958c07a7b2SBrian Somers if (p) 896dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 8978c07a7b2SBrian Somers else 898dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 899d47dceb8SBrian Somers fp->link->name); 900af57ed9fSAtsushi Murai break; 901af57ed9fSAtsushi Murai case PROTO_CCP: 902dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 9033b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 9048a8d9927SBrian Somers /* Despite the RFC (1661), don't do an out-of-place TLF */ 9058a8d9927SBrian Somers /* (*fp->fn->LayerFinish)(fp); */ 906af57ed9fSAtsushi Murai switch (fp->state) { 907af57ed9fSAtsushi Murai case ST_CLOSED: 908af57ed9fSAtsushi Murai case ST_CLOSING: 909af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 910ad65ae3aSBrian Somers break; 911af57ed9fSAtsushi Murai default: 912af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 913af57ed9fSAtsushi Murai break; 914af57ed9fSAtsushi Murai } 9158a8d9927SBrian Somers /* See above */ 9168a8d9927SBrian Somers /* (*fp->parent->LayerFinish)(fp->parent->object, fp); */ 917dc0fdb6bSBrian Somers } 9181ae349f5Scvs2svn break; 9198a59beb7SBrian Somers case PROTO_IPCP: 9208a59beb7SBrian Somers if (fp->proto == PROTO_LCP) { 9218a59beb7SBrian Somers log_Printf(LogPHASE, "%s: IPCP protocol reject closes IPCP !\n", 9228a59beb7SBrian Somers fp->link->name); 9238a59beb7SBrian Somers fsm_Close(&fp->bundle->ncp.ipcp.fsm); 9248a59beb7SBrian Somers } 9258a59beb7SBrian Somers break; 92630949fd4SBrian Somers #ifndef NOINET6 92730949fd4SBrian Somers case PROTO_IPV6CP: 9281136c6acSBrian Somers if (fp->proto == PROTO_LCP) { 92930949fd4SBrian Somers log_Printf(LogPHASE, "%s: IPV6CP protocol reject closes IPV6CP !\n", 93030949fd4SBrian Somers fp->link->name); 93130949fd4SBrian Somers fsm_Close(&fp->bundle->ncp.ipv6cp.fsm); 93230949fd4SBrian Somers } 93330949fd4SBrian Somers break; 93430949fd4SBrian Somers #endif 935673903ecSBrian Somers case PROTO_MP: 936673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 937673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 938673903ecSBrian Somers 939673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 940dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 941d47dceb8SBrian Somers fp->link->name); 942dd7e2610SBrian Somers fsm_Close(fp); 943673903ecSBrian Somers } 944673903ecSBrian Somers } 945af57ed9fSAtsushi Murai break; 946af57ed9fSAtsushi Murai } 94726af0ae9SBrian Somers m_freem(bp); 948af57ed9fSAtsushi Murai } 949af57ed9fSAtsushi Murai 95075240ed1SBrian Somers static void 951944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 952af57ed9fSAtsushi Murai { 953dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 954af57ed9fSAtsushi Murai u_char *cp; 955fe3125a0SBrian Somers u_int32_t magic; 956af57ed9fSAtsushi Murai 95726af0ae9SBrian Somers bp = m_pullup(bp); 95826af0ae9SBrian Somers m_settype(bp, MB_ECHOIN); 95987c3786eSBrian Somers 96087c3786eSBrian Somers if (lcp && ntohs(lhp->length) - sizeof *lhp >= 4) { 961af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 9629e8ec64bSBrian Somers ua_ntohl(cp, &magic); 963dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 964990a543fSBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: magic 0x%08lx is wrong," 965990a543fSBrian Somers " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 966990a543fSBrian Somers (u_long)lcp->his_magic); 967af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 968af57ed9fSAtsushi Murai } 969af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 9709e8ec64bSBrian Somers ua_htonl(&lcp->want_magic, cp); /* local magic */ 97187c3786eSBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, 97287c3786eSBrian Somers ntohs(lhp->length) - sizeof *lhp, MB_ECHOOUT); 973af57ed9fSAtsushi Murai } 974dc0fdb6bSBrian Somers } 97526af0ae9SBrian Somers m_freem(bp); 976af57ed9fSAtsushi Murai } 977af57ed9fSAtsushi Murai 97875240ed1SBrian Somers static void 979057f1760SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp __unused, struct mbuf *bp) 980af57ed9fSAtsushi Murai { 9816471628dSBrian Somers if (fsm2lcp(fp)) 9823377c28cSBrian Somers bp = lqr_RecvEcho(fp, bp); 9836471628dSBrian Somers 98426af0ae9SBrian Somers m_freem(bp); 985af57ed9fSAtsushi Murai } 986af57ed9fSAtsushi Murai 98775240ed1SBrian Somers static void 988057f1760SBrian Somers FsmRecvDiscReq(struct fsm *fp __unused, struct fsmheader *lhp __unused, 989057f1760SBrian Somers struct mbuf *bp) 990af57ed9fSAtsushi Murai { 99126af0ae9SBrian Somers m_freem(bp); 992af57ed9fSAtsushi Murai } 993af57ed9fSAtsushi Murai 99475240ed1SBrian Somers static void 995944f7098SBrian Somers FsmRecvIdent(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 996af57ed9fSAtsushi Murai { 9971038894eSBrian Somers u_int32_t magic; 9981038894eSBrian Somers u_short len; 9991038894eSBrian Somers u_char *cp; 10001038894eSBrian Somers 10011038894eSBrian Somers len = ntohs(lhp->length) - sizeof *lhp; 10021038894eSBrian Somers if (len >= 4) { 10031038894eSBrian Somers bp = m_pullup(m_append(bp, "", 1)); 10041038894eSBrian Somers cp = MBUF_CTOP(bp); 10051038894eSBrian Somers ua_ntohl(cp, &magic); 10061038894eSBrian Somers if (magic != fp->link->lcp.his_magic) 10071038894eSBrian Somers log_Printf(fp->LogLevel, "%s: RecvIdent: magic 0x%08lx is wrong," 10081038894eSBrian Somers " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 10091038894eSBrian Somers (u_long)fp->link->lcp.his_magic); 10101038894eSBrian Somers cp[len] = '\0'; 10111038894eSBrian Somers lcp_RecvIdentification(&fp->link->lcp, cp + 4); 10121038894eSBrian Somers } 101326af0ae9SBrian Somers m_freem(bp); 1014af57ed9fSAtsushi Murai } 1015af57ed9fSAtsushi Murai 101675240ed1SBrian Somers static void 1017057f1760SBrian Somers FsmRecvTimeRemain(struct fsm *fp __unused, struct fsmheader *lhp __unused, 1018057f1760SBrian Somers struct mbuf *bp) 1019af57ed9fSAtsushi Murai { 102026af0ae9SBrian Somers m_freem(bp); 1021af57ed9fSAtsushi Murai } 1022af57ed9fSAtsushi Murai 102375240ed1SBrian Somers static void 1024944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 1025af57ed9fSAtsushi Murai { 10266cf6ee76SBrian Somers if ((*fp->fn->RecvResetReq)(fp)) { 102798baf7c8SBrian Somers /* 1028442f8495SBrian Somers * All sendable compressed packets are queued in the first (lowest 1029442f8495SBrian Somers * priority) modem output queue.... dump 'em to the priority queue 1030442f8495SBrian Somers * so that they arrive at the peer before our ResetAck. 103198baf7c8SBrian Somers */ 10328c07a7b2SBrian Somers link_SequenceQueue(fp->link); 1033411675baSBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0, MB_CCPOUT); 10346cf6ee76SBrian Somers } 103526af0ae9SBrian Somers m_freem(bp); 1036af57ed9fSAtsushi Murai } 1037af57ed9fSAtsushi Murai 103875240ed1SBrian Somers static void 1039944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 1040af57ed9fSAtsushi Murai { 1041503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 104226af0ae9SBrian Somers m_freem(bp); 1043af57ed9fSAtsushi Murai } 1044af57ed9fSAtsushi Murai 1045af57ed9fSAtsushi Murai void 1046dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 1047af57ed9fSAtsushi Murai { 1048057f1760SBrian Somers size_t len; 10495d9e6103SBrian Somers struct fsmheader lh; 10500053cc58SBrian Somers const struct fsmcodedesc *codep; 1051af57ed9fSAtsushi Murai 105226af0ae9SBrian Somers len = m_length(bp); 1053af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 105426af0ae9SBrian Somers m_freem(bp); 1055af57ed9fSAtsushi Murai return; 1056af57ed9fSAtsushi Murai } 10575d9e6103SBrian Somers bp = mbuf_Read(bp, &lh, sizeof lh); 105887c3786eSBrian Somers 1059962a3cbcSBrian Somers if (ntohs(lh.length) > len) { 10601814213eSMarcel Moolenaar log_Printf(LogWARN, "%s: Oops: Got %zu bytes but %d byte payload " 1061962a3cbcSBrian Somers "- dropped\n", fp->link->name, len, (int)ntohs(lh.length)); 1062962a3cbcSBrian Somers m_freem(bp); 1063962a3cbcSBrian Somers return; 1064962a3cbcSBrian Somers } 106587c3786eSBrian Somers 10665d9e6103SBrian Somers if (lh.code < fp->min_code || lh.code > fp->max_code || 10675d9e6103SBrian Somers lh.code > sizeof FsmCodes / sizeof *FsmCodes) { 10683b0f8d2eSBrian Somers /* 10693b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 10703b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 10713b0f8d2eSBrian Somers */ 10723b0f8d2eSBrian Somers static u_char id; 1073d93d3a9cSBrian Somers 107426af0ae9SBrian Somers bp = m_prepend(bp, &lh, sizeof lh, 0); 107526af0ae9SBrian Somers bp = m_pullup(bp); 107626af0ae9SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->m_len, MB_UNKNOWN); 107726af0ae9SBrian Somers m_freem(bp); 1078af57ed9fSAtsushi Murai return; 1079af57ed9fSAtsushi Murai } 1080af57ed9fSAtsushi Murai 10815d9e6103SBrian Somers codep = FsmCodes + lh.code - 1; 10825d9e6103SBrian Somers if (lh.id != fp->reqid && codep->check_reqid && 10831342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 1084dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 10855d9e6103SBrian Somers fp->link->name, codep->name, lh.id, fp->reqid); 10862267893fSBrian Somers return; 10872267893fSBrian Somers } 10882267893fSBrian Somers 1089dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 10905d9e6103SBrian Somers fp->link->name, codep->name, lh.id, State2Nam(fp->state)); 10912267893fSBrian Somers 10925d9e6103SBrian Somers if (codep->inc_reqid && (lh.id == fp->reqid || 10931342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 10942267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 10952267893fSBrian Somers 10965d9e6103SBrian Somers (*codep->recv)(fp, &lh, bp); 10971ae349f5Scvs2svn } 1098503a7782SBrian Somers 10996cf6ee76SBrian Somers int 1100dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 1101503a7782SBrian Somers { 1102dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 1103d47dceb8SBrian Somers fp->link->name); 11046cf6ee76SBrian Somers return 1; 1105503a7782SBrian Somers } 1106503a7782SBrian Somers 1107503a7782SBrian Somers void 1108057f1760SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id __unused) 1109503a7782SBrian Somers { 1110dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 1111d47dceb8SBrian Somers fp->link->name); 1112af57ed9fSAtsushi Murai } 111309206a6fSBrian Somers 111409206a6fSBrian Somers void 1115897f9429SBrian Somers fsm_Reopen(struct fsm *fp) 1116897f9429SBrian Somers { 1117897f9429SBrian Somers if (fp->state == ST_OPENED) { 1118897f9429SBrian Somers (*fp->fn->LayerDown)(fp); 1119479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 1120897f9429SBrian Somers FsmSendConfigReq(fp); 1121897f9429SBrian Somers NewState(fp, ST_REQSENT); 1122897f9429SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 1123897f9429SBrian Somers } 1124897f9429SBrian Somers } 1125897f9429SBrian Somers 1126897f9429SBrian Somers void 112709206a6fSBrian Somers fsm2initial(struct fsm *fp) 112809206a6fSBrian Somers { 1129479508cfSBrian Somers timer_Stop(&fp->FsmTimer); 1130479508cfSBrian Somers timer_Stop(&fp->OpenTimer); 1131479508cfSBrian Somers timer_Stop(&fp->StoppedTimer); 113209206a6fSBrian Somers if (fp->state == ST_STOPPED) 113309206a6fSBrian Somers fsm_Close(fp); 113409206a6fSBrian Somers if (fp->state > ST_INITIAL) 113509206a6fSBrian Somers fsm_Down(fp); 113609206a6fSBrian Somers if (fp->state > ST_INITIAL) 113709206a6fSBrian Somers fsm_Close(fp); 113809206a6fSBrian Somers } 1139ff360cc9SBrian Somers 1140ff360cc9SBrian Somers struct fsm_opt * 1141ff360cc9SBrian Somers fsm_readopt(u_char **cp) 1142ff360cc9SBrian Somers { 1143ff360cc9SBrian Somers struct fsm_opt *o = (struct fsm_opt *)*cp; 1144ff360cc9SBrian Somers 1145ff360cc9SBrian Somers if (o->hdr.len < sizeof(struct fsm_opt_hdr)) { 1146ff360cc9SBrian Somers log_Printf(LogERROR, "Bad option length %d (out of phase?)\n", o->hdr.len); 1147ff360cc9SBrian Somers return NULL; 1148ff360cc9SBrian Somers } 1149ff360cc9SBrian Somers 1150ff360cc9SBrian Somers *cp += o->hdr.len; 1151ff360cc9SBrian Somers 1152ff360cc9SBrian Somers if (o->hdr.len > sizeof(struct fsm_opt)) { 11533627fe88SBrian Somers log_Printf(LogERROR, "Warning: Truncating option length from %d to %d\n", 11543627fe88SBrian Somers o->hdr.len, (int)sizeof(struct fsm_opt)); 1155ff360cc9SBrian Somers o->hdr.len = sizeof(struct fsm_opt); 1156ff360cc9SBrian Somers } 1157ff360cc9SBrian Somers 1158ff360cc9SBrian Somers return o; 1159ff360cc9SBrian Somers } 1160ff360cc9SBrian Somers 1161ff360cc9SBrian Somers static int 1162ff360cc9SBrian Somers fsm_opt(u_char *opt, int optlen, const struct fsm_opt *o) 1163ff360cc9SBrian Somers { 1164057f1760SBrian Somers unsigned cplen = o->hdr.len; 1165ff360cc9SBrian Somers 1166057f1760SBrian Somers if (optlen < (int)sizeof(struct fsm_opt_hdr)) 1167ff360cc9SBrian Somers optlen = 0; 1168ff360cc9SBrian Somers 1169057f1760SBrian Somers if ((int)cplen > optlen) { 1170ff360cc9SBrian Somers log_Printf(LogERROR, "Can't REJ length %d - trunating to %d\n", 1171ff360cc9SBrian Somers cplen, optlen); 1172ff360cc9SBrian Somers cplen = optlen; 1173ff360cc9SBrian Somers } 1174ff360cc9SBrian Somers memcpy(opt, o, cplen); 1175ff360cc9SBrian Somers if (cplen) 1176ff360cc9SBrian Somers opt[1] = cplen; 1177ff360cc9SBrian Somers 1178ff360cc9SBrian Somers return cplen; 1179ff360cc9SBrian Somers } 1180ff360cc9SBrian Somers 1181ff360cc9SBrian Somers void 1182ff360cc9SBrian Somers fsm_rej(struct fsm_decode *dec, const struct fsm_opt *o) 1183ff360cc9SBrian Somers { 1184ff360cc9SBrian Somers if (!dec) 1185ff360cc9SBrian Somers return; 1186ff360cc9SBrian Somers dec->rejend += fsm_opt(dec->rejend, FSM_OPTLEN - (dec->rejend - dec->rej), o); 1187ff360cc9SBrian Somers } 1188ff360cc9SBrian Somers 1189ff360cc9SBrian Somers void 1190ff360cc9SBrian Somers fsm_ack(struct fsm_decode *dec, const struct fsm_opt *o) 1191ff360cc9SBrian Somers { 1192ff360cc9SBrian Somers if (!dec) 1193ff360cc9SBrian Somers return; 1194ff360cc9SBrian Somers dec->ackend += fsm_opt(dec->ackend, FSM_OPTLEN - (dec->ackend - dec->ack), o); 1195ff360cc9SBrian Somers } 1196ff360cc9SBrian Somers 1197ff360cc9SBrian Somers void 1198ff360cc9SBrian Somers fsm_nak(struct fsm_decode *dec, const struct fsm_opt *o) 1199ff360cc9SBrian Somers { 1200ff360cc9SBrian Somers if (!dec) 1201ff360cc9SBrian Somers return; 1202ff360cc9SBrian Somers dec->nakend += fsm_opt(dec->nakend, FSM_OPTLEN - (dec->nakend - dec->nak), o); 1203ff360cc9SBrian Somers } 1204ff360cc9SBrian Somers 1205ff360cc9SBrian Somers void 1206ff360cc9SBrian Somers fsm_opt_normalise(struct fsm_decode *dec) 1207ff360cc9SBrian Somers { 1208ff360cc9SBrian Somers if (dec->rejend != dec->rej) { 1209ff360cc9SBrian Somers /* rejects are preferred */ 1210ff360cc9SBrian Somers dec->ackend = dec->ack; 1211ff360cc9SBrian Somers dec->nakend = dec->nak; 1212ff360cc9SBrian Somers } else if (dec->nakend != dec->nak) 1213ff360cc9SBrian Somers /* then NAKs */ 1214ff360cc9SBrian Somers dec->ackend = dec->ack; 1215ff360cc9SBrian Somers } 1216