165309e5cSBrian Somers /*- 265309e5cSBrian Somers * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 365309e5cSBrian Somers * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 465309e5cSBrian Somers * Internet Initiative Japan, Inc (IIJ) 565309e5cSBrian Somers * All rights reserved. 6af57ed9fSAtsushi Murai * 765309e5cSBrian Somers * Redistribution and use in source and binary forms, with or without 865309e5cSBrian Somers * modification, are permitted provided that the following conditions 965309e5cSBrian Somers * are met: 1065309e5cSBrian Somers * 1. Redistributions of source code must retain the above copyright 1165309e5cSBrian Somers * notice, this list of conditions and the following disclaimer. 1265309e5cSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 1365309e5cSBrian Somers * notice, this list of conditions and the following disclaimer in the 1465309e5cSBrian Somers * documentation and/or other materials provided with the distribution. 15af57ed9fSAtsushi Murai * 1665309e5cSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1765309e5cSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1865309e5cSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1965309e5cSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2065309e5cSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2165309e5cSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2265309e5cSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2365309e5cSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2465309e5cSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2565309e5cSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2665309e5cSBrian Somers * SUCH DAMAGE. 27af57ed9fSAtsushi Murai * 2897d92980SPeter Wemm * $FreeBSD$ 29af57ed9fSAtsushi Murai */ 3075240ed1SBrian Somers 31972a1bcfSBrian Somers #include <sys/param.h> 321342caedSBrian Somers #include <netinet/in.h> 331342caedSBrian Somers #include <netinet/in_systm.h> 341342caedSBrian Somers #include <netinet/ip.h> 3530949fd4SBrian Somers #include <sys/socket.h> 361fa665f5SBrian Somers #include <sys/un.h> 371ae349f5Scvs2svn 3875240ed1SBrian Somers #include <string.h> 3975240ed1SBrian Somers #include <termios.h> 4075240ed1SBrian Somers 415d9e6103SBrian Somers #include "layer.h" 429e8ec64bSBrian Somers #include "ua.h" 4375240ed1SBrian Somers #include "mbuf.h" 4475240ed1SBrian Somers #include "log.h" 4575240ed1SBrian Somers #include "defs.h" 4675240ed1SBrian Somers #include "timer.h" 47af57ed9fSAtsushi Murai #include "fsm.h" 481342caedSBrian Somers #include "iplist.h" 49af57ed9fSAtsushi Murai #include "lqr.h" 50879ed6faSBrian Somers #include "hdlc.h" 511342caedSBrian Somers #include "throughput.h" 521342caedSBrian Somers #include "slcompress.h" 5330949fd4SBrian Somers #include "ncpaddr.h" 5430949fd4SBrian Somers #include "ip.h" 551342caedSBrian Somers #include "ipcp.h" 561342caedSBrian Somers #include "filter.h" 571342caedSBrian Somers #include "descriptor.h" 58af57ed9fSAtsushi Murai #include "lcp.h" 59ed6a16c1SPoul-Henning Kamp #include "ccp.h" 608c07a7b2SBrian Somers #include "link.h" 611342caedSBrian Somers #include "mp.h" 62972a1bcfSBrian Somers #ifndef NORADIUS 63972a1bcfSBrian Somers #include "radius.h" 64972a1bcfSBrian Somers #endif 6530949fd4SBrian Somers #include "ipv6cp.h" 6630949fd4SBrian Somers #include "ncp.h" 671342caedSBrian Somers #include "bundle.h" 681342caedSBrian Somers #include "async.h" 6963b73463SBrian Somers #include "physical.h" 705d9e6103SBrian Somers #include "proto.h" 7175240ed1SBrian Somers 7275240ed1SBrian Somers static void FsmSendConfigReq(struct fsm *); 7375240ed1SBrian Somers static void FsmSendTerminateReq(struct fsm *); 74479508cfSBrian Somers static void FsmInitRestartCounter(struct fsm *, int); 75af57ed9fSAtsushi Murai 762267893fSBrian Somers typedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *); 772267893fSBrian Somers static recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak, 782267893fSBrian Somers FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck, 792267893fSBrian Somers FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq, 802267893fSBrian Somers FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent, 812267893fSBrian Somers FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck; 822267893fSBrian Somers 832267893fSBrian Somers static const struct fsmcodedesc { 842267893fSBrian Somers recvfn *recv; 852267893fSBrian Somers unsigned check_reqid : 1; 862267893fSBrian Somers unsigned inc_reqid : 1; 872267893fSBrian Somers const char *name; 882267893fSBrian Somers } FsmCodes[] = { 892267893fSBrian Somers { FsmRecvConfigReq, 0, 0, "ConfigReq" }, 902267893fSBrian Somers { FsmRecvConfigAck, 1, 1, "ConfigAck" }, 912267893fSBrian Somers { FsmRecvConfigNak, 1, 1, "ConfigNak" }, 922267893fSBrian Somers { FsmRecvConfigRej, 1, 1, "ConfigRej" }, 932267893fSBrian Somers { FsmRecvTermReq, 0, 0, "TerminateReq" }, 942267893fSBrian Somers { FsmRecvTermAck, 1, 1, "TerminateAck" }, 952267893fSBrian Somers { FsmRecvCodeRej, 0, 0, "CodeRej" }, 962267893fSBrian Somers { FsmRecvProtoRej, 0, 0, "ProtocolRej" }, 972267893fSBrian Somers { FsmRecvEchoReq, 0, 0, "EchoRequest" }, 982267893fSBrian Somers { FsmRecvEchoRep, 0, 0, "EchoReply" }, 992267893fSBrian Somers { FsmRecvDiscReq, 0, 0, "DiscardReq" }, 1001038894eSBrian Somers { FsmRecvIdent, 0, 1, "Ident" }, 1012267893fSBrian Somers { FsmRecvTimeRemain,0, 0, "TimeRemain" }, 1025d9e6103SBrian Somers { FsmRecvResetReq, 0, 0, "ResetReq" }, 1032267893fSBrian Somers { FsmRecvResetAck, 0, 1, "ResetAck" } 1042267893fSBrian Somers }; 1052267893fSBrian Somers 1062267893fSBrian Somers static const char * 1072267893fSBrian Somers Code2Nam(u_int code) 1082267893fSBrian Somers { 1092267893fSBrian Somers if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0]) 1102267893fSBrian Somers return "Unknown"; 1112267893fSBrian Somers return FsmCodes[code-1].name; 1122267893fSBrian Somers } 1132267893fSBrian Somers 1141e991daaSBrian Somers const char * 1151e991daaSBrian Somers State2Nam(u_int state) 1161e991daaSBrian Somers { 117182c898aSBrian Somers static const char * const StateNames[] = { 118af57ed9fSAtsushi Murai "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", 119927145beSBrian Somers "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", 120af57ed9fSAtsushi Murai }; 121af57ed9fSAtsushi Murai 1221e991daaSBrian Somers if (state >= sizeof StateNames / sizeof StateNames[0]) 1231e991daaSBrian Somers return "unknown"; 1241e991daaSBrian Somers return StateNames[state]; 1251e991daaSBrian Somers } 1261e991daaSBrian Somers 12771144dc5SBrian Somers static void 128b6e82f33SBrian Somers StoppedTimeout(void *v) 12971144dc5SBrian Somers { 130b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 131b6e82f33SBrian Somers 132dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name); 13349b239e0SBrian Somers if (fp->OpenTimer.state == TIMER_RUNNING) { 134dd7e2610SBrian Somers log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n", 135d47dceb8SBrian Somers fp->link->name, fp->name); 136dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 13749b239e0SBrian Somers } 13809206a6fSBrian Somers if (fp->state == ST_STOPPED) 13909206a6fSBrian Somers fsm2initial(fp); 14071144dc5SBrian Somers } 14171144dc5SBrian Somers 142af57ed9fSAtsushi Murai void 1433b0f8d2eSBrian Somers fsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, 144479508cfSBrian Somers int maxcode, int LogLevel, struct bundle *bundle, 1453b0f8d2eSBrian Somers struct link *l, const struct fsm_parent *parent, 146182c898aSBrian Somers struct fsm_callbacks *fn, const char * const timer_names[3]) 147af57ed9fSAtsushi Murai { 148503a7782SBrian Somers fp->name = name; 149503a7782SBrian Somers fp->proto = proto; 1503b0f8d2eSBrian Somers fp->min_code = mincode; 151503a7782SBrian Somers fp->max_code = maxcode; 1523b0f8d2eSBrian Somers fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; 153af57ed9fSAtsushi Murai fp->reqid = 1; 154af57ed9fSAtsushi Murai fp->restart = 1; 1555d9e6103SBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = 3; 156503a7782SBrian Somers memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); 157503a7782SBrian Somers memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); 158503a7782SBrian Somers memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); 159503a7782SBrian Somers fp->LogLevel = LogLevel; 1608c07a7b2SBrian Somers fp->link = l; 1617a6f8720SBrian Somers fp->bundle = bundle; 1626d666775SBrian Somers fp->parent = parent; 163503a7782SBrian Somers fp->fn = fn; 1643b0f8d2eSBrian Somers fp->FsmTimer.name = timer_names[0]; 1653b0f8d2eSBrian Somers fp->OpenTimer.name = timer_names[1]; 1663b0f8d2eSBrian Somers fp->StoppedTimer.name = timer_names[2]; 167af57ed9fSAtsushi Murai } 168af57ed9fSAtsushi Murai 16975240ed1SBrian Somers static void 170944f7098SBrian Somers NewState(struct fsm *fp, int new) 171af57ed9fSAtsushi Murai { 172dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", 173d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state), State2Nam(new)); 174cb611434SBrian Somers if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) 175dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 176af57ed9fSAtsushi Murai fp->state = new; 17771144dc5SBrian Somers if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { 178dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 179cb611434SBrian Somers if (new == ST_STOPPED && fp->StoppedTimer.load) { 180dd7e2610SBrian Somers timer_Stop(&fp->StoppedTimer); 181cb611434SBrian Somers fp->StoppedTimer.func = StoppedTimeout; 182cb611434SBrian Somers fp->StoppedTimer.arg = (void *) fp; 183dd7e2610SBrian Somers timer_Start(&fp->StoppedTimer); 18471144dc5SBrian Somers } 18571144dc5SBrian Somers } 186af57ed9fSAtsushi Murai } 187af57ed9fSAtsushi Murai 188af57ed9fSAtsushi Murai void 189411675baSBrian Somers fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count, 190411675baSBrian Somers int mtype) 191af57ed9fSAtsushi Murai { 192af57ed9fSAtsushi Murai int plen; 193af57ed9fSAtsushi Murai struct fsmheader lh; 194af57ed9fSAtsushi Murai struct mbuf *bp; 195af57ed9fSAtsushi Murai 196dd7e2610SBrian Somers if (log_IsKept(fp->LogLevel)) { 197dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", 198d47dceb8SBrian Somers fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); 1992267893fSBrian Somers switch (code) { 2002267893fSBrian Somers case CODE_CONFIGREQ: 2012267893fSBrian Somers case CODE_CONFIGACK: 2022267893fSBrian Somers case CODE_CONFIGREJ: 2032267893fSBrian Somers case CODE_CONFIGNAK: 204ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, ptr, ptr + count, MODE_NOP, NULL); 205ff360cc9SBrian Somers if (count < sizeof(struct fsm_opt_hdr)) 206dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 2072267893fSBrian Somers break; 2082267893fSBrian Somers } 2092267893fSBrian Somers } 2102267893fSBrian Somers 211af57ed9fSAtsushi Murai plen = sizeof(struct fsmheader) + count; 212af57ed9fSAtsushi Murai lh.code = code; 213af57ed9fSAtsushi Murai lh.id = id; 214af57ed9fSAtsushi Murai lh.length = htons(plen); 21526af0ae9SBrian Somers bp = m_get(plen, mtype); 21675240ed1SBrian Somers memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 217af57ed9fSAtsushi Murai if (count) 21875240ed1SBrian Somers memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 219dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "fsm_Output", bp); 220442f8495SBrian Somers link_PushPacket(fp->link, bp, fp->bundle, LINK_QUEUES(fp->link) - 1, 221442f8495SBrian Somers fp->proto); 2221038894eSBrian Somers 2231038894eSBrian Somers if (code == CODE_CONFIGREJ) 2241038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 225af57ed9fSAtsushi Murai } 226af57ed9fSAtsushi Murai 22749b239e0SBrian Somers static void 22849b239e0SBrian Somers FsmOpenNow(void *v) 22949b239e0SBrian Somers { 23049b239e0SBrian Somers struct fsm *fp = (struct fsm *)v; 23149b239e0SBrian Somers 232dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 23349b239e0SBrian Somers if (fp->state <= ST_STOPPED) { 2343a2e4f62SBrian Somers if (fp->state != ST_STARTING) { 2353a2e4f62SBrian Somers /* 2363a2e4f62SBrian Somers * In practice, we're only here in ST_STOPPED (when delaying the 2373a2e4f62SBrian Somers * first config request) or ST_CLOSED (when openmode == 0). 2383a2e4f62SBrian Somers * 2393a2e4f62SBrian Somers * The ST_STOPPED bit is breaking the RFC already :-( 2403a2e4f62SBrian Somers * 2413a2e4f62SBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 2423a2e4f62SBrian Somers * required for an Open event when state == Closed, but the RFC 2433a2e4f62SBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 2443a2e4f62SBrian Somers * ie, Initial gets an `Up' event, Closing gets a RTA etc. 2453a2e4f62SBrian Somers */ 2463a2e4f62SBrian Somers (*fp->fn->LayerStart)(fp); 2473a2e4f62SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 2483a2e4f62SBrian Somers } 249479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 25049b239e0SBrian Somers FsmSendConfigReq(fp); 25149b239e0SBrian Somers NewState(fp, ST_REQSENT); 25249b239e0SBrian Somers } 25349b239e0SBrian Somers } 25449b239e0SBrian Somers 255af57ed9fSAtsushi Murai void 256dd7e2610SBrian Somers fsm_Open(struct fsm *fp) 257af57ed9fSAtsushi Murai { 258af57ed9fSAtsushi Murai switch (fp->state) { 259af57ed9fSAtsushi Murai case ST_INITIAL: 260af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 2616d666775SBrian Somers (*fp->fn->LayerStart)(fp); 2626d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 263af57ed9fSAtsushi Murai break; 264af57ed9fSAtsushi Murai case ST_CLOSED: 265af57ed9fSAtsushi Murai if (fp->open_mode == OPEN_PASSIVE) { 2663a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ 26749b239e0SBrian Somers } else if (fp->open_mode > 0) { 26849b239e0SBrian Somers if (fp->open_mode > 1) 269dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", 270d47dceb8SBrian Somers fp->link->name, fp->open_mode); 2713a2e4f62SBrian Somers NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ 272dd7e2610SBrian Somers timer_Stop(&fp->OpenTimer); 27349b239e0SBrian Somers fp->OpenTimer.load = fp->open_mode * SECTICKS; 27449b239e0SBrian Somers fp->OpenTimer.func = FsmOpenNow; 27549b239e0SBrian Somers fp->OpenTimer.arg = (void *)fp; 276dd7e2610SBrian Somers timer_Start(&fp->OpenTimer); 27749b239e0SBrian Somers } else 27849b239e0SBrian Somers FsmOpenNow(fp); 279af57ed9fSAtsushi Murai break; 280af57ed9fSAtsushi Murai case ST_STOPPED: /* XXX: restart option */ 281af57ed9fSAtsushi Murai case ST_REQSENT: 282af57ed9fSAtsushi Murai case ST_ACKRCVD: 283af57ed9fSAtsushi Murai case ST_ACKSENT: 284af57ed9fSAtsushi Murai case ST_OPENED: /* XXX: restart option */ 285af57ed9fSAtsushi Murai break; 286af57ed9fSAtsushi Murai case ST_CLOSING: /* XXX: restart option */ 287af57ed9fSAtsushi Murai case ST_STOPPING: /* XXX: restart option */ 288af57ed9fSAtsushi Murai NewState(fp, ST_STOPPING); 289af57ed9fSAtsushi Murai break; 290af57ed9fSAtsushi Murai } 291af57ed9fSAtsushi Murai } 292af57ed9fSAtsushi Murai 293af57ed9fSAtsushi Murai void 294dd7e2610SBrian Somers fsm_Up(struct fsm *fp) 295af57ed9fSAtsushi Murai { 296af57ed9fSAtsushi Murai switch (fp->state) { 297af57ed9fSAtsushi Murai case ST_INITIAL: 298dd7e2610SBrian Somers log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", 2991fa665f5SBrian Somers fp->link->name); 300af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 301af57ed9fSAtsushi Murai break; 302af57ed9fSAtsushi Murai case ST_STARTING: 303479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 304af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 305af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 306af57ed9fSAtsushi Murai break; 307af57ed9fSAtsushi Murai default: 308dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", 309d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 310af57ed9fSAtsushi Murai break; 311af57ed9fSAtsushi Murai } 312af57ed9fSAtsushi Murai } 313af57ed9fSAtsushi Murai 314af57ed9fSAtsushi Murai void 315dd7e2610SBrian Somers fsm_Down(struct fsm *fp) 316af57ed9fSAtsushi Murai { 317af57ed9fSAtsushi Murai switch (fp->state) { 318af57ed9fSAtsushi Murai case ST_CLOSED: 319af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 320af57ed9fSAtsushi Murai break; 321455aabc3SBrian Somers case ST_CLOSING: 3228a8d9927SBrian Somers /* This TLF contradicts the RFC (1661), which ``misses it out'' ! */ 3236d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 324455aabc3SBrian Somers NewState(fp, ST_INITIAL); 3256d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 326455aabc3SBrian Somers break; 327af57ed9fSAtsushi Murai case ST_STOPPED: 328455aabc3SBrian Somers NewState(fp, ST_STARTING); 3296d666775SBrian Somers (*fp->fn->LayerStart)(fp); 3306d666775SBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 331455aabc3SBrian Somers break; 332af57ed9fSAtsushi Murai case ST_STOPPING: 333af57ed9fSAtsushi Murai case ST_REQSENT: 334af57ed9fSAtsushi Murai case ST_ACKRCVD: 335af57ed9fSAtsushi Murai case ST_ACKSENT: 336af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 337af57ed9fSAtsushi Murai break; 338af57ed9fSAtsushi Murai case ST_OPENED: 3396d666775SBrian Somers (*fp->fn->LayerDown)(fp); 340af57ed9fSAtsushi Murai NewState(fp, ST_STARTING); 3416d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 342af57ed9fSAtsushi Murai break; 343af57ed9fSAtsushi Murai } 344af57ed9fSAtsushi Murai } 345af57ed9fSAtsushi Murai 346af57ed9fSAtsushi Murai void 347dd7e2610SBrian Somers fsm_Close(struct fsm *fp) 348af57ed9fSAtsushi Murai { 349af57ed9fSAtsushi Murai switch (fp->state) { 350af57ed9fSAtsushi Murai case ST_STARTING: 3516d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 352af57ed9fSAtsushi Murai NewState(fp, ST_INITIAL); 3536d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 354af57ed9fSAtsushi Murai break; 355af57ed9fSAtsushi Murai case ST_STOPPED: 356af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 357af57ed9fSAtsushi Murai break; 358af57ed9fSAtsushi Murai case ST_STOPPING: 359af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 360af57ed9fSAtsushi Murai break; 361af57ed9fSAtsushi Murai case ST_OPENED: 3626d666775SBrian Somers (*fp->fn->LayerDown)(fp); 36315c8dc2aSBrian Somers if (fp->state == ST_OPENED) { 364479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 365455aabc3SBrian Somers FsmSendTerminateReq(fp); 366455aabc3SBrian Somers NewState(fp, ST_CLOSING); 3676d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 36815c8dc2aSBrian Somers } 369455aabc3SBrian Somers break; 370af57ed9fSAtsushi Murai case ST_REQSENT: 371af57ed9fSAtsushi Murai case ST_ACKRCVD: 372af57ed9fSAtsushi Murai case ST_ACKSENT: 373479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 374af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 375af57ed9fSAtsushi Murai NewState(fp, ST_CLOSING); 376af57ed9fSAtsushi Murai break; 377af57ed9fSAtsushi Murai } 378af57ed9fSAtsushi Murai } 379af57ed9fSAtsushi Murai 380af57ed9fSAtsushi Murai /* 381af57ed9fSAtsushi Murai * Send functions 382af57ed9fSAtsushi Murai */ 38375240ed1SBrian Somers static void 384944f7098SBrian Somers FsmSendConfigReq(struct fsm *fp) 385af57ed9fSAtsushi Murai { 386479508cfSBrian Somers if (fp->more.reqs-- > 0 && fp->restart-- > 0) { 38783d1af55SBrian Somers (*fp->fn->SendConfigReq)(fp); 388dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 389af57ed9fSAtsushi Murai } else { 390479508cfSBrian Somers if (fp->more.reqs < 0) 391479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REQs sent - abandoning " 392479508cfSBrian Somers "negotiation\n", fp->link->name, fp->name); 3931038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 394dd7e2610SBrian Somers fsm_Close(fp); 395af57ed9fSAtsushi Murai } 396af57ed9fSAtsushi Murai } 397af57ed9fSAtsushi Murai 39875240ed1SBrian Somers static void 399944f7098SBrian Somers FsmSendTerminateReq(struct fsm *fp) 400af57ed9fSAtsushi Murai { 401411675baSBrian Somers fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0, MB_UNKNOWN); 4022267893fSBrian Somers (*fp->fn->SentTerminateReq)(fp); 403dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 404af57ed9fSAtsushi Murai fp->restart--; /* Decrement restart counter */ 405af57ed9fSAtsushi Murai } 406af57ed9fSAtsushi Murai 407af57ed9fSAtsushi Murai /* 408af57ed9fSAtsushi Murai * Timeout actions 409af57ed9fSAtsushi Murai */ 41075240ed1SBrian Somers static void 411b6e82f33SBrian Somers FsmTimeout(void *v) 412af57ed9fSAtsushi Murai { 413b6e82f33SBrian Somers struct fsm *fp = (struct fsm *)v; 414b6e82f33SBrian Somers 415af57ed9fSAtsushi Murai if (fp->restart) { 416af57ed9fSAtsushi Murai switch (fp->state) { 417af57ed9fSAtsushi Murai case ST_CLOSING: 418af57ed9fSAtsushi Murai case ST_STOPPING: 419af57ed9fSAtsushi Murai FsmSendTerminateReq(fp); 420af57ed9fSAtsushi Murai break; 421af57ed9fSAtsushi Murai case ST_REQSENT: 422af57ed9fSAtsushi Murai case ST_ACKSENT: 423af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 424af57ed9fSAtsushi Murai break; 425af57ed9fSAtsushi Murai case ST_ACKRCVD: 426af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 427af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 428af57ed9fSAtsushi Murai break; 429af57ed9fSAtsushi Murai } 430dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); 431af57ed9fSAtsushi Murai } else { 432af57ed9fSAtsushi Murai switch (fp->state) { 433af57ed9fSAtsushi Murai case ST_CLOSING: 4346d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 435af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 4366d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 437af57ed9fSAtsushi Murai break; 438af57ed9fSAtsushi Murai case ST_STOPPING: 4396d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 440af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4416d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 442af57ed9fSAtsushi Murai break; 443af57ed9fSAtsushi Murai case ST_REQSENT: /* XXX: 3p */ 444af57ed9fSAtsushi Murai case ST_ACKSENT: 445af57ed9fSAtsushi Murai case ST_ACKRCVD: 4466d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 447af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 4486d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 449af57ed9fSAtsushi Murai break; 450af57ed9fSAtsushi Murai } 451af57ed9fSAtsushi Murai } 452af57ed9fSAtsushi Murai } 453af57ed9fSAtsushi Murai 45475240ed1SBrian Somers static void 455479508cfSBrian Somers FsmInitRestartCounter(struct fsm *fp, int what) 456af57ed9fSAtsushi Murai { 457dd7e2610SBrian Somers timer_Stop(&fp->FsmTimer); 458af57ed9fSAtsushi Murai fp->FsmTimer.func = FsmTimeout; 459af57ed9fSAtsushi Murai fp->FsmTimer.arg = (void *)fp; 460479508cfSBrian Somers (*fp->fn->InitRestartCounter)(fp, what); 461af57ed9fSAtsushi Murai } 462af57ed9fSAtsushi Murai 463af57ed9fSAtsushi Murai /* 464af57ed9fSAtsushi Murai * Actions when receive packets 465af57ed9fSAtsushi Murai */ 46675240ed1SBrian Somers static void 467944f7098SBrian Somers FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 468944f7098SBrian Somers /* RCR */ 469af57ed9fSAtsushi Murai { 47030c2f2ffSBrian Somers struct fsm_decode dec; 47153c9f6c0SAtsushi Murai int plen, flen; 472af57ed9fSAtsushi Murai int ackaction = 0; 473ff360cc9SBrian Somers u_char *cp; 474af57ed9fSAtsushi Murai 475ff360cc9SBrian Somers bp = m_pullup(bp); 47626af0ae9SBrian Somers plen = m_length(bp); 47770ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 47853c9f6c0SAtsushi Murai if (plen < flen) { 479a33b2ef7SBrian Somers log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", 480d47dceb8SBrian Somers fp->link->name, plen, flen); 48126af0ae9SBrian Somers m_freem(bp); 482af57ed9fSAtsushi Murai return; 483af57ed9fSAtsushi Murai } 484af57ed9fSAtsushi Murai 485ff360cc9SBrian Somers dec.ackend = dec.ack; 486ff360cc9SBrian Somers dec.nakend = dec.nak; 487ff360cc9SBrian Somers dec.rejend = dec.rej; 488ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 489ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_REQ, &dec); 490ff360cc9SBrian Somers if (flen < sizeof(struct fsm_opt_hdr)) 491ff360cc9SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 492ff360cc9SBrian Somers 493ff360cc9SBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 494ff360cc9SBrian Somers ackaction = 1; 495ff360cc9SBrian Somers 4963377c28cSBrian Somers /* Check and process easy case */ 497af57ed9fSAtsushi Murai switch (fp->state) { 498af57ed9fSAtsushi Murai case ST_INITIAL: 49906337856SBrian Somers if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 50006337856SBrian Somers /* 50106337856SBrian Somers * ccp_SetOpenMode() leaves us in initial if we're disabling 5025d9e6103SBrian Somers * & denying everything. 50306337856SBrian Somers */ 50426af0ae9SBrian Somers bp = m_prepend(bp, lhp, sizeof *lhp, 2); 5055d9e6103SBrian Somers bp = proto_Prepend(bp, fp->proto, 0, 0); 50626af0ae9SBrian Somers bp = m_pullup(bp); 50726af0ae9SBrian Somers lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->m_len); 50826af0ae9SBrian Somers m_freem(bp); 50906337856SBrian Somers return; 51006337856SBrian Somers } 51106337856SBrian Somers /* Drop through */ 512af57ed9fSAtsushi Murai case ST_STARTING: 513dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 514d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 51526af0ae9SBrian Somers m_freem(bp); 516af57ed9fSAtsushi Murai return; 517af57ed9fSAtsushi Murai case ST_CLOSED: 5182267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 51926af0ae9SBrian Somers m_freem(bp); 520af57ed9fSAtsushi Murai return; 521af57ed9fSAtsushi Murai case ST_CLOSING: 522dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 523d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 524a9c503afSBrian Somers case ST_STOPPING: 52526af0ae9SBrian Somers m_freem(bp); 526af57ed9fSAtsushi Murai return; 527af57ed9fSAtsushi Murai case ST_STOPPED: 528479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 529ff360cc9SBrian Somers FsmSendConfigReq(fp); 530ff360cc9SBrian Somers break; 53168a0e171SBrian Somers case ST_OPENED: 532ff360cc9SBrian Somers (*fp->fn->LayerDown)(fp); 533af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 534af57ed9fSAtsushi Murai break; 535af57ed9fSAtsushi Murai } 536af57ed9fSAtsushi Murai 53730c2f2ffSBrian Somers if (dec.rejend != dec.rej) 538411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej, 539411675baSBrian Somers MB_UNKNOWN); 54030c2f2ffSBrian Somers if (dec.nakend != dec.nak) 541411675baSBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak, 542411675baSBrian Somers MB_UNKNOWN); 543af57ed9fSAtsushi Murai if (ackaction) 544411675baSBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack, 545411675baSBrian Somers MB_UNKNOWN); 546af57ed9fSAtsushi Murai 547af57ed9fSAtsushi Murai switch (fp->state) { 548455aabc3SBrian Somers case ST_STOPPED: 549479508cfSBrian Somers /* 550479508cfSBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 551479508cfSBrian Somers * required for a RCR when state == ST_STOPPED, but the RFC 552479508cfSBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 553479508cfSBrian Somers */ 554479508cfSBrian Somers (*fp->fn->LayerStart)(fp); 555479508cfSBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 556479508cfSBrian Somers /* Fall through */ 557479508cfSBrian Somers 558479508cfSBrian Somers case ST_OPENED: 559af57ed9fSAtsushi Murai if (ackaction) 560af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 561af57ed9fSAtsushi Murai else 562af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 56330949fd4SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 564af57ed9fSAtsushi Murai break; 565af57ed9fSAtsushi Murai case ST_REQSENT: 566af57ed9fSAtsushi Murai if (ackaction) 567af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 568af57ed9fSAtsushi Murai break; 569af57ed9fSAtsushi Murai case ST_ACKRCVD: 570af57ed9fSAtsushi Murai if (ackaction) { 571af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5726f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5736d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5746f384573SBrian Somers else { 5756f384573SBrian Somers (*fp->fn->LayerDown)(fp); 576479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 5776f384573SBrian Somers FsmSendTerminateReq(fp); 5786f384573SBrian Somers NewState(fp, ST_CLOSING); 5791038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 5806f384573SBrian Somers } 581af57ed9fSAtsushi Murai } 582af57ed9fSAtsushi Murai break; 583af57ed9fSAtsushi Murai case ST_ACKSENT: 584af57ed9fSAtsushi Murai if (!ackaction) 585af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 586af57ed9fSAtsushi Murai break; 587af57ed9fSAtsushi Murai } 58826af0ae9SBrian Somers m_freem(bp); 589479508cfSBrian Somers 590479508cfSBrian Somers if (dec.rejend != dec.rej && --fp->more.rejs <= 0) { 591479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REJs sent - abandoning negotiation\n", 592479508cfSBrian Somers fp->link->name, fp->name); 5931038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 594479508cfSBrian Somers fsm_Close(fp); 595479508cfSBrian Somers } 596479508cfSBrian Somers 597479508cfSBrian Somers if (dec.nakend != dec.nak && --fp->more.naks <= 0) { 598479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s NAKs sent - abandoning negotiation\n", 599479508cfSBrian Somers fp->link->name, fp->name); 6001038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 601479508cfSBrian Somers fsm_Close(fp); 602479508cfSBrian Somers } 603af57ed9fSAtsushi Murai } 604af57ed9fSAtsushi Murai 60575240ed1SBrian Somers static void 606944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 607944f7098SBrian Somers /* RCA */ 608af57ed9fSAtsushi Murai { 609ff360cc9SBrian Somers struct fsm_decode dec; 610ff360cc9SBrian Somers int plen, flen; 611ff360cc9SBrian Somers u_char *cp; 612ff360cc9SBrian Somers 613ff360cc9SBrian Somers plen = m_length(bp); 614ff360cc9SBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 615ff360cc9SBrian Somers if (plen < flen) { 616ff360cc9SBrian Somers m_freem(bp); 617ff360cc9SBrian Somers return; 618ff360cc9SBrian Somers } 619ff360cc9SBrian Somers 620ff360cc9SBrian Somers bp = m_pullup(bp); 621ff360cc9SBrian Somers dec.ackend = dec.ack; 622ff360cc9SBrian Somers dec.nakend = dec.nak; 623ff360cc9SBrian Somers dec.rejend = dec.rej; 624ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 625ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_ACK, &dec); 626ff360cc9SBrian Somers if (flen < sizeof(struct fsm_opt_hdr)) 627ff360cc9SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 628ff360cc9SBrian Somers 629af57ed9fSAtsushi Murai switch (fp->state) { 630af57ed9fSAtsushi Murai case ST_CLOSED: 631af57ed9fSAtsushi Murai case ST_STOPPED: 6322267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 633af57ed9fSAtsushi Murai break; 634af57ed9fSAtsushi Murai case ST_CLOSING: 635af57ed9fSAtsushi Murai case ST_STOPPING: 636af57ed9fSAtsushi Murai break; 637af57ed9fSAtsushi Murai case ST_REQSENT: 638479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 639af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 640af57ed9fSAtsushi Murai break; 641af57ed9fSAtsushi Murai case ST_ACKRCVD: 642af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 643af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 644af57ed9fSAtsushi Murai break; 645af57ed9fSAtsushi Murai case ST_ACKSENT: 646479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 647af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 6486f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 6496d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 6506f384573SBrian Somers else { 6516f384573SBrian Somers (*fp->fn->LayerDown)(fp); 652479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 6536f384573SBrian Somers FsmSendTerminateReq(fp); 6546f384573SBrian Somers NewState(fp, ST_CLOSING); 6551038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 6566f384573SBrian Somers } 657af57ed9fSAtsushi Murai break; 658af57ed9fSAtsushi Murai case ST_OPENED: 6596d666775SBrian Somers (*fp->fn->LayerDown)(fp); 660af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 661af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 6626d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 663af57ed9fSAtsushi Murai break; 664af57ed9fSAtsushi Murai } 66526af0ae9SBrian Somers m_freem(bp); 666af57ed9fSAtsushi Murai } 667af57ed9fSAtsushi Murai 66875240ed1SBrian Somers static void 669944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 670944f7098SBrian Somers /* RCN */ 671af57ed9fSAtsushi Murai { 67230c2f2ffSBrian Somers struct fsm_decode dec; 67353c9f6c0SAtsushi Murai int plen, flen; 674ff360cc9SBrian Somers u_char *cp; 675af57ed9fSAtsushi Murai 67626af0ae9SBrian Somers plen = m_length(bp); 67770ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 67853c9f6c0SAtsushi Murai if (plen < flen) { 67926af0ae9SBrian Somers m_freem(bp); 680af57ed9fSAtsushi Murai return; 681af57ed9fSAtsushi Murai } 682af57ed9fSAtsushi Murai 683af57ed9fSAtsushi Murai /* 684af57ed9fSAtsushi Murai * Check and process easy case 685af57ed9fSAtsushi Murai */ 686af57ed9fSAtsushi Murai switch (fp->state) { 687af57ed9fSAtsushi Murai case ST_INITIAL: 688af57ed9fSAtsushi Murai case ST_STARTING: 689dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 690d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 69126af0ae9SBrian Somers m_freem(bp); 692af57ed9fSAtsushi Murai return; 693af57ed9fSAtsushi Murai case ST_CLOSED: 694af57ed9fSAtsushi Murai case ST_STOPPED: 6952267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 69626af0ae9SBrian Somers m_freem(bp); 697af57ed9fSAtsushi Murai return; 698af57ed9fSAtsushi Murai case ST_CLOSING: 699af57ed9fSAtsushi Murai case ST_STOPPING: 70026af0ae9SBrian Somers m_freem(bp); 701af57ed9fSAtsushi Murai return; 702af57ed9fSAtsushi Murai } 703af57ed9fSAtsushi Murai 70426af0ae9SBrian Somers bp = m_pullup(bp); 70530c2f2ffSBrian Somers dec.ackend = dec.ack; 70630c2f2ffSBrian Somers dec.nakend = dec.nak; 70730c2f2ffSBrian Somers dec.rejend = dec.rej; 708ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 709ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_NAK, &dec); 710ff360cc9SBrian Somers if (flen < sizeof(struct fsm_opt_hdr)) 711dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 712af57ed9fSAtsushi Murai 713af57ed9fSAtsushi Murai switch (fp->state) { 714af57ed9fSAtsushi Murai case ST_REQSENT: 715af57ed9fSAtsushi Murai case ST_ACKSENT: 716479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 717af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 718af57ed9fSAtsushi Murai break; 719af57ed9fSAtsushi Murai case ST_OPENED: 7206d666775SBrian Somers (*fp->fn->LayerDown)(fp); 721455aabc3SBrian Somers FsmSendConfigReq(fp); 722455aabc3SBrian Somers NewState(fp, ST_REQSENT); 7236d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 724455aabc3SBrian Somers break; 725af57ed9fSAtsushi Murai case ST_ACKRCVD: 726af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 727af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 728af57ed9fSAtsushi Murai break; 729af57ed9fSAtsushi Murai } 730af57ed9fSAtsushi Murai 73126af0ae9SBrian Somers m_freem(bp); 732af57ed9fSAtsushi Murai } 733af57ed9fSAtsushi Murai 73475240ed1SBrian Somers static void 735944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 736944f7098SBrian Somers /* RTR */ 737af57ed9fSAtsushi Murai { 738af57ed9fSAtsushi Murai switch (fp->state) { 739af57ed9fSAtsushi Murai case ST_INITIAL: 740af57ed9fSAtsushi Murai case ST_STARTING: 741dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 742d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 743af57ed9fSAtsushi Murai break; 744af57ed9fSAtsushi Murai case ST_CLOSED: 745af57ed9fSAtsushi Murai case ST_STOPPED: 746af57ed9fSAtsushi Murai case ST_CLOSING: 747af57ed9fSAtsushi Murai case ST_STOPPING: 748af57ed9fSAtsushi Murai case ST_REQSENT: 7492267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 750af57ed9fSAtsushi Murai break; 751af57ed9fSAtsushi Murai case ST_ACKRCVD: 752af57ed9fSAtsushi Murai case ST_ACKSENT: 7532267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 754af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 755af57ed9fSAtsushi Murai break; 756af57ed9fSAtsushi Murai case ST_OPENED: 7576d666775SBrian Somers (*fp->fn->LayerDown)(fp); 7582267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 759479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 760dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 7618f2fa0eeSBrian Somers fp->restart = 0; 7628f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 7636d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 764479508cfSBrian Somers /* A delayed ST_STOPPED is now scheduled */ 765af57ed9fSAtsushi Murai break; 766af57ed9fSAtsushi Murai } 76726af0ae9SBrian Somers m_freem(bp); 768af57ed9fSAtsushi Murai } 769af57ed9fSAtsushi Murai 77075240ed1SBrian Somers static void 771944f7098SBrian Somers FsmRecvTermAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 772944f7098SBrian Somers /* RTA */ 773af57ed9fSAtsushi Murai { 774af57ed9fSAtsushi Murai switch (fp->state) { 775af57ed9fSAtsushi Murai case ST_CLOSING: 7766d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 777af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 7786d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 779af57ed9fSAtsushi Murai break; 780af57ed9fSAtsushi Murai case ST_STOPPING: 7816d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 782af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 7836d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 784af57ed9fSAtsushi Murai break; 785af57ed9fSAtsushi Murai case ST_ACKRCVD: 786af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 787af57ed9fSAtsushi Murai break; 788af57ed9fSAtsushi Murai case ST_OPENED: 7896d666775SBrian Somers (*fp->fn->LayerDown)(fp); 790af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 791af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 7926d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 793af57ed9fSAtsushi Murai break; 794af57ed9fSAtsushi Murai } 79526af0ae9SBrian Somers m_freem(bp); 796af57ed9fSAtsushi Murai } 797af57ed9fSAtsushi Murai 79875240ed1SBrian Somers static void 799944f7098SBrian Somers FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 800944f7098SBrian Somers /* RCJ */ 801af57ed9fSAtsushi Murai { 80230c2f2ffSBrian Somers struct fsm_decode dec; 80353c9f6c0SAtsushi Murai int plen, flen; 804ff360cc9SBrian Somers u_char *cp; 805af57ed9fSAtsushi Murai 80626af0ae9SBrian Somers plen = m_length(bp); 80770ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 80853c9f6c0SAtsushi Murai if (plen < flen) { 80926af0ae9SBrian Somers m_freem(bp); 810af57ed9fSAtsushi Murai return; 811af57ed9fSAtsushi Murai } 812af57ed9fSAtsushi Murai 8131038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 8141038894eSBrian Somers 815af57ed9fSAtsushi Murai /* 816af57ed9fSAtsushi Murai * Check and process easy case 817af57ed9fSAtsushi Murai */ 818af57ed9fSAtsushi Murai switch (fp->state) { 819af57ed9fSAtsushi Murai case ST_INITIAL: 820af57ed9fSAtsushi Murai case ST_STARTING: 821dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 822d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 82326af0ae9SBrian Somers m_freem(bp); 824af57ed9fSAtsushi Murai return; 825af57ed9fSAtsushi Murai case ST_CLOSED: 826af57ed9fSAtsushi Murai case ST_STOPPED: 8272267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 82826af0ae9SBrian Somers m_freem(bp); 829af57ed9fSAtsushi Murai return; 830af57ed9fSAtsushi Murai case ST_CLOSING: 831af57ed9fSAtsushi Murai case ST_STOPPING: 83226af0ae9SBrian Somers m_freem(bp); 833af57ed9fSAtsushi Murai return; 834af57ed9fSAtsushi Murai } 835af57ed9fSAtsushi Murai 83626af0ae9SBrian Somers bp = m_pullup(bp); 83730c2f2ffSBrian Somers dec.ackend = dec.ack; 83830c2f2ffSBrian Somers dec.nakend = dec.nak; 83930c2f2ffSBrian Somers dec.rejend = dec.rej; 840ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 841ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_REJ, &dec); 842ff360cc9SBrian Somers if (flen < sizeof(struct fsm_opt_hdr)) 843dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 844af57ed9fSAtsushi Murai 845af57ed9fSAtsushi Murai switch (fp->state) { 846af57ed9fSAtsushi Murai case ST_REQSENT: 847af57ed9fSAtsushi Murai case ST_ACKSENT: 848479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 849af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 850af57ed9fSAtsushi Murai break; 851af57ed9fSAtsushi Murai case ST_OPENED: 8526d666775SBrian Somers (*fp->fn->LayerDown)(fp); 853455aabc3SBrian Somers FsmSendConfigReq(fp); 854455aabc3SBrian Somers NewState(fp, ST_REQSENT); 8556d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 856455aabc3SBrian Somers break; 857af57ed9fSAtsushi Murai case ST_ACKRCVD: 858af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 859af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 860af57ed9fSAtsushi Murai break; 861af57ed9fSAtsushi Murai } 86226af0ae9SBrian Somers m_freem(bp); 863af57ed9fSAtsushi Murai } 864af57ed9fSAtsushi Murai 86575240ed1SBrian Somers static void 866944f7098SBrian Somers FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 867af57ed9fSAtsushi Murai { 86826af0ae9SBrian Somers m_freem(bp); 869af57ed9fSAtsushi Murai } 870af57ed9fSAtsushi Murai 87175240ed1SBrian Somers static void 872944f7098SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 873af57ed9fSAtsushi Murai { 8748c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 8753377c28cSBrian Somers u_short proto; 876af57ed9fSAtsushi Murai 87726af0ae9SBrian Somers if (m_length(bp) < 2) { 87826af0ae9SBrian Somers m_freem(bp); 8793377c28cSBrian Somers return; 8803377c28cSBrian Somers } 8813377c28cSBrian Somers bp = mbuf_Read(bp, &proto, 2); 8823377c28cSBrian Somers proto = ntohs(proto); 883dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 884d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 885af57ed9fSAtsushi Murai 886af57ed9fSAtsushi Murai switch (proto) { 887af57ed9fSAtsushi Murai case PROTO_LQR: 8888c07a7b2SBrian Somers if (p) 889dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 8908c07a7b2SBrian Somers else 891dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 892d47dceb8SBrian Somers fp->link->name); 893af57ed9fSAtsushi Murai break; 894af57ed9fSAtsushi Murai case PROTO_CCP: 895dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 8963b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 8978a8d9927SBrian Somers /* Despite the RFC (1661), don't do an out-of-place TLF */ 8988a8d9927SBrian Somers /* (*fp->fn->LayerFinish)(fp); */ 899af57ed9fSAtsushi Murai switch (fp->state) { 900af57ed9fSAtsushi Murai case ST_CLOSED: 901af57ed9fSAtsushi Murai case ST_CLOSING: 902af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 903ad65ae3aSBrian Somers break; 904af57ed9fSAtsushi Murai default: 905af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 906af57ed9fSAtsushi Murai break; 907af57ed9fSAtsushi Murai } 9088a8d9927SBrian Somers /* See above */ 9098a8d9927SBrian Somers /* (*fp->parent->LayerFinish)(fp->parent->object, fp); */ 910dc0fdb6bSBrian Somers } 9111ae349f5Scvs2svn break; 9128a59beb7SBrian Somers case PROTO_IPCP: 9138a59beb7SBrian Somers if (fp->proto == PROTO_LCP) { 9148a59beb7SBrian Somers log_Printf(LogPHASE, "%s: IPCP protocol reject closes IPCP !\n", 9158a59beb7SBrian Somers fp->link->name); 9168a59beb7SBrian Somers fsm_Close(&fp->bundle->ncp.ipcp.fsm); 9178a59beb7SBrian Somers } 9188a59beb7SBrian Somers break; 91930949fd4SBrian Somers #ifndef NOINET6 92030949fd4SBrian Somers case PROTO_IPV6CP: 9211136c6acSBrian Somers if (fp->proto == PROTO_LCP) { 92230949fd4SBrian Somers log_Printf(LogPHASE, "%s: IPV6CP protocol reject closes IPV6CP !\n", 92330949fd4SBrian Somers fp->link->name); 92430949fd4SBrian Somers fsm_Close(&fp->bundle->ncp.ipv6cp.fsm); 92530949fd4SBrian Somers } 92630949fd4SBrian Somers break; 92730949fd4SBrian Somers #endif 928673903ecSBrian Somers case PROTO_MP: 929673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 930673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 931673903ecSBrian Somers 932673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 933dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 934d47dceb8SBrian Somers fp->link->name); 935dd7e2610SBrian Somers fsm_Close(fp); 936673903ecSBrian Somers } 937673903ecSBrian Somers } 938af57ed9fSAtsushi Murai break; 939af57ed9fSAtsushi Murai } 94026af0ae9SBrian Somers m_freem(bp); 941af57ed9fSAtsushi Murai } 942af57ed9fSAtsushi Murai 94375240ed1SBrian Somers static void 944944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 945af57ed9fSAtsushi Murai { 946dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 947af57ed9fSAtsushi Murai u_char *cp; 948fe3125a0SBrian Somers u_int32_t magic; 949af57ed9fSAtsushi Murai 95026af0ae9SBrian Somers bp = m_pullup(bp); 95126af0ae9SBrian Somers m_settype(bp, MB_ECHOIN); 95287c3786eSBrian Somers 95387c3786eSBrian Somers if (lcp && ntohs(lhp->length) - sizeof *lhp >= 4) { 954af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 9559e8ec64bSBrian Somers ua_ntohl(cp, &magic); 956dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 957990a543fSBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: magic 0x%08lx is wrong," 958990a543fSBrian Somers " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 959990a543fSBrian Somers (u_long)lcp->his_magic); 960af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 961af57ed9fSAtsushi Murai } 962af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 9639e8ec64bSBrian Somers ua_htonl(&lcp->want_magic, cp); /* local magic */ 96487c3786eSBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, 96587c3786eSBrian Somers ntohs(lhp->length) - sizeof *lhp, MB_ECHOOUT); 966af57ed9fSAtsushi Murai } 967dc0fdb6bSBrian Somers } 96826af0ae9SBrian Somers m_freem(bp); 969af57ed9fSAtsushi Murai } 970af57ed9fSAtsushi Murai 97175240ed1SBrian Somers static void 972944f7098SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 973af57ed9fSAtsushi Murai { 9746471628dSBrian Somers if (fsm2lcp(fp)) 9753377c28cSBrian Somers bp = lqr_RecvEcho(fp, bp); 9766471628dSBrian Somers 97726af0ae9SBrian Somers m_freem(bp); 978af57ed9fSAtsushi Murai } 979af57ed9fSAtsushi Murai 98075240ed1SBrian Somers static void 981944f7098SBrian Somers FsmRecvDiscReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 982af57ed9fSAtsushi Murai { 98326af0ae9SBrian Somers m_freem(bp); 984af57ed9fSAtsushi Murai } 985af57ed9fSAtsushi Murai 98675240ed1SBrian Somers static void 987944f7098SBrian Somers FsmRecvIdent(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 988af57ed9fSAtsushi Murai { 9891038894eSBrian Somers u_int32_t magic; 9901038894eSBrian Somers u_short len; 9911038894eSBrian Somers u_char *cp; 9921038894eSBrian Somers 9931038894eSBrian Somers len = ntohs(lhp->length) - sizeof *lhp; 9941038894eSBrian Somers if (len >= 4) { 9951038894eSBrian Somers bp = m_pullup(m_append(bp, "", 1)); 9961038894eSBrian Somers cp = MBUF_CTOP(bp); 9971038894eSBrian Somers ua_ntohl(cp, &magic); 9981038894eSBrian Somers if (magic != fp->link->lcp.his_magic) 9991038894eSBrian Somers log_Printf(fp->LogLevel, "%s: RecvIdent: magic 0x%08lx is wrong," 10001038894eSBrian Somers " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 10011038894eSBrian Somers (u_long)fp->link->lcp.his_magic); 10021038894eSBrian Somers cp[len] = '\0'; 10031038894eSBrian Somers lcp_RecvIdentification(&fp->link->lcp, cp + 4); 10041038894eSBrian Somers } 100526af0ae9SBrian Somers m_freem(bp); 1006af57ed9fSAtsushi Murai } 1007af57ed9fSAtsushi Murai 100875240ed1SBrian Somers static void 1009944f7098SBrian Somers FsmRecvTimeRemain(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 1010af57ed9fSAtsushi Murai { 101126af0ae9SBrian Somers m_freem(bp); 1012af57ed9fSAtsushi Murai } 1013af57ed9fSAtsushi Murai 101475240ed1SBrian Somers static void 1015944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 1016af57ed9fSAtsushi Murai { 10176cf6ee76SBrian Somers if ((*fp->fn->RecvResetReq)(fp)) { 101898baf7c8SBrian Somers /* 1019442f8495SBrian Somers * All sendable compressed packets are queued in the first (lowest 1020442f8495SBrian Somers * priority) modem output queue.... dump 'em to the priority queue 1021442f8495SBrian Somers * so that they arrive at the peer before our ResetAck. 102298baf7c8SBrian Somers */ 10238c07a7b2SBrian Somers link_SequenceQueue(fp->link); 1024411675baSBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0, MB_CCPOUT); 10256cf6ee76SBrian Somers } 102626af0ae9SBrian Somers m_freem(bp); 1027af57ed9fSAtsushi Murai } 1028af57ed9fSAtsushi Murai 102975240ed1SBrian Somers static void 1030944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 1031af57ed9fSAtsushi Murai { 1032503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 103326af0ae9SBrian Somers m_freem(bp); 1034af57ed9fSAtsushi Murai } 1035af57ed9fSAtsushi Murai 1036af57ed9fSAtsushi Murai void 1037dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 1038af57ed9fSAtsushi Murai { 1039af57ed9fSAtsushi Murai int len; 10405d9e6103SBrian Somers struct fsmheader lh; 10410053cc58SBrian Somers const struct fsmcodedesc *codep; 1042af57ed9fSAtsushi Murai 104326af0ae9SBrian Somers len = m_length(bp); 1044af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 104526af0ae9SBrian Somers m_freem(bp); 1046af57ed9fSAtsushi Murai return; 1047af57ed9fSAtsushi Murai } 10485d9e6103SBrian Somers bp = mbuf_Read(bp, &lh, sizeof lh); 104987c3786eSBrian Somers 1050962a3cbcSBrian Somers if (ntohs(lh.length) > len) { 1051962a3cbcSBrian Somers log_Printf(LogWARN, "%s: Oops: Got %d bytes but %d byte payload " 1052962a3cbcSBrian Somers "- dropped\n", fp->link->name, len, (int)ntohs(lh.length)); 1053962a3cbcSBrian Somers m_freem(bp); 1054962a3cbcSBrian Somers return; 1055962a3cbcSBrian Somers } 105687c3786eSBrian Somers 10575d9e6103SBrian Somers if (lh.code < fp->min_code || lh.code > fp->max_code || 10585d9e6103SBrian Somers lh.code > sizeof FsmCodes / sizeof *FsmCodes) { 10593b0f8d2eSBrian Somers /* 10603b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 10613b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 10623b0f8d2eSBrian Somers */ 10633b0f8d2eSBrian Somers static u_char id; 1064d93d3a9cSBrian Somers 106526af0ae9SBrian Somers bp = m_prepend(bp, &lh, sizeof lh, 0); 106626af0ae9SBrian Somers bp = m_pullup(bp); 106726af0ae9SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->m_len, MB_UNKNOWN); 106826af0ae9SBrian Somers m_freem(bp); 1069af57ed9fSAtsushi Murai return; 1070af57ed9fSAtsushi Murai } 1071af57ed9fSAtsushi Murai 10725d9e6103SBrian Somers codep = FsmCodes + lh.code - 1; 10735d9e6103SBrian Somers if (lh.id != fp->reqid && codep->check_reqid && 10741342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 1075dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 10765d9e6103SBrian Somers fp->link->name, codep->name, lh.id, fp->reqid); 10772267893fSBrian Somers return; 10782267893fSBrian Somers } 10792267893fSBrian Somers 1080dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 10815d9e6103SBrian Somers fp->link->name, codep->name, lh.id, State2Nam(fp->state)); 10822267893fSBrian Somers 10835d9e6103SBrian Somers if (codep->inc_reqid && (lh.id == fp->reqid || 10841342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 10852267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 10862267893fSBrian Somers 10875d9e6103SBrian Somers (*codep->recv)(fp, &lh, bp); 10881ae349f5Scvs2svn } 1089503a7782SBrian Somers 10906cf6ee76SBrian Somers int 1091dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 1092503a7782SBrian Somers { 1093dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 1094d47dceb8SBrian Somers fp->link->name); 10956cf6ee76SBrian Somers return 1; 1096503a7782SBrian Somers } 1097503a7782SBrian Somers 1098503a7782SBrian Somers void 1099dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 1100503a7782SBrian Somers { 1101dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 1102d47dceb8SBrian Somers fp->link->name); 1103af57ed9fSAtsushi Murai } 110409206a6fSBrian Somers 110509206a6fSBrian Somers void 1106897f9429SBrian Somers fsm_Reopen(struct fsm *fp) 1107897f9429SBrian Somers { 1108897f9429SBrian Somers if (fp->state == ST_OPENED) { 1109897f9429SBrian Somers (*fp->fn->LayerDown)(fp); 1110479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 1111897f9429SBrian Somers FsmSendConfigReq(fp); 1112897f9429SBrian Somers NewState(fp, ST_REQSENT); 1113897f9429SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 1114897f9429SBrian Somers } 1115897f9429SBrian Somers } 1116897f9429SBrian Somers 1117897f9429SBrian Somers void 111809206a6fSBrian Somers fsm2initial(struct fsm *fp) 111909206a6fSBrian Somers { 1120479508cfSBrian Somers timer_Stop(&fp->FsmTimer); 1121479508cfSBrian Somers timer_Stop(&fp->OpenTimer); 1122479508cfSBrian Somers timer_Stop(&fp->StoppedTimer); 112309206a6fSBrian Somers if (fp->state == ST_STOPPED) 112409206a6fSBrian Somers fsm_Close(fp); 112509206a6fSBrian Somers if (fp->state > ST_INITIAL) 112609206a6fSBrian Somers fsm_Down(fp); 112709206a6fSBrian Somers if (fp->state > ST_INITIAL) 112809206a6fSBrian Somers fsm_Close(fp); 112909206a6fSBrian Somers } 1130ff360cc9SBrian Somers 1131ff360cc9SBrian Somers struct fsm_opt * 1132ff360cc9SBrian Somers fsm_readopt(u_char **cp) 1133ff360cc9SBrian Somers { 1134ff360cc9SBrian Somers struct fsm_opt *o = (struct fsm_opt *)*cp; 1135ff360cc9SBrian Somers 1136ff360cc9SBrian Somers if (o->hdr.len < sizeof(struct fsm_opt_hdr)) { 1137ff360cc9SBrian Somers log_Printf(LogERROR, "Bad option length %d (out of phase?)\n", o->hdr.len); 1138ff360cc9SBrian Somers return NULL; 1139ff360cc9SBrian Somers } 1140ff360cc9SBrian Somers 1141ff360cc9SBrian Somers *cp += o->hdr.len; 1142ff360cc9SBrian Somers 1143ff360cc9SBrian Somers if (o->hdr.len > sizeof(struct fsm_opt)) { 1144ff360cc9SBrian Somers o->hdr.len = sizeof(struct fsm_opt); 1145ff360cc9SBrian Somers log_Printf(LogERROR, "Warning: Truncating option length to %d\n", 1146ff360cc9SBrian Somers o->hdr.len); 1147ff360cc9SBrian Somers } 1148ff360cc9SBrian Somers 1149ff360cc9SBrian Somers return o; 1150ff360cc9SBrian Somers } 1151ff360cc9SBrian Somers 1152ff360cc9SBrian Somers static int 1153ff360cc9SBrian Somers fsm_opt(u_char *opt, int optlen, const struct fsm_opt *o) 1154ff360cc9SBrian Somers { 1155ff360cc9SBrian Somers int cplen = o->hdr.len; 1156ff360cc9SBrian Somers 1157ff360cc9SBrian Somers if (optlen < sizeof(struct fsm_opt_hdr)) 1158ff360cc9SBrian Somers optlen = 0; 1159ff360cc9SBrian Somers 1160ff360cc9SBrian Somers if (cplen > optlen) { 1161ff360cc9SBrian Somers log_Printf(LogERROR, "Can't REJ length %d - trunating to %d\n", 1162ff360cc9SBrian Somers cplen, optlen); 1163ff360cc9SBrian Somers cplen = optlen; 1164ff360cc9SBrian Somers } 1165ff360cc9SBrian Somers memcpy(opt, o, cplen); 1166ff360cc9SBrian Somers if (cplen) 1167ff360cc9SBrian Somers opt[1] = cplen; 1168ff360cc9SBrian Somers 1169ff360cc9SBrian Somers return cplen; 1170ff360cc9SBrian Somers } 1171ff360cc9SBrian Somers 1172ff360cc9SBrian Somers void 1173ff360cc9SBrian Somers fsm_rej(struct fsm_decode *dec, const struct fsm_opt *o) 1174ff360cc9SBrian Somers { 1175ff360cc9SBrian Somers if (!dec) 1176ff360cc9SBrian Somers return; 1177ff360cc9SBrian Somers dec->rejend += fsm_opt(dec->rejend, FSM_OPTLEN - (dec->rejend - dec->rej), o); 1178ff360cc9SBrian Somers } 1179ff360cc9SBrian Somers 1180ff360cc9SBrian Somers void 1181ff360cc9SBrian Somers fsm_ack(struct fsm_decode *dec, const struct fsm_opt *o) 1182ff360cc9SBrian Somers { 1183ff360cc9SBrian Somers if (!dec) 1184ff360cc9SBrian Somers return; 1185ff360cc9SBrian Somers dec->ackend += fsm_opt(dec->ackend, FSM_OPTLEN - (dec->ackend - dec->ack), o); 1186ff360cc9SBrian Somers } 1187ff360cc9SBrian Somers 1188ff360cc9SBrian Somers void 1189ff360cc9SBrian Somers fsm_nak(struct fsm_decode *dec, const struct fsm_opt *o) 1190ff360cc9SBrian Somers { 1191ff360cc9SBrian Somers if (!dec) 1192ff360cc9SBrian Somers return; 1193ff360cc9SBrian Somers dec->nakend += fsm_opt(dec->nakend, FSM_OPTLEN - (dec->nakend - dec->nak), o); 1194ff360cc9SBrian Somers } 1195ff360cc9SBrian Somers 1196ff360cc9SBrian Somers void 1197ff360cc9SBrian Somers fsm_opt_normalise(struct fsm_decode *dec) 1198ff360cc9SBrian Somers { 1199ff360cc9SBrian Somers if (dec->rejend != dec->rej) { 1200ff360cc9SBrian Somers /* rejects are preferred */ 1201ff360cc9SBrian Somers dec->ackend = dec->ack; 1202ff360cc9SBrian Somers dec->nakend = dec->nak; 1203ff360cc9SBrian Somers } else if (dec->nakend != dec->nak) 1204ff360cc9SBrian Somers /* then NAKs */ 1205ff360cc9SBrian Somers dec->ackend = dec->ack; 1206ff360cc9SBrian Somers } 1207