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 485d14cc5f9SBrian Somers /* Some things must be done before we Decode the packet */ 486d14cc5f9SBrian Somers switch (fp->state) { 487d14cc5f9SBrian Somers case ST_OPENED: 488d14cc5f9SBrian Somers (*fp->fn->LayerDown)(fp); 489d14cc5f9SBrian Somers } 490d14cc5f9SBrian Somers 491ff360cc9SBrian Somers dec.ackend = dec.ack; 492ff360cc9SBrian Somers dec.nakend = dec.nak; 493ff360cc9SBrian Somers dec.rejend = dec.rej; 494ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 495ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_REQ, &dec); 496ff360cc9SBrian Somers if (flen < sizeof(struct fsm_opt_hdr)) 497ff360cc9SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 498ff360cc9SBrian Somers 499ff360cc9SBrian Somers if (dec.nakend == dec.nak && dec.rejend == dec.rej) 500ff360cc9SBrian Somers ackaction = 1; 501ff360cc9SBrian Somers 5023377c28cSBrian Somers /* Check and process easy case */ 503af57ed9fSAtsushi Murai switch (fp->state) { 504af57ed9fSAtsushi Murai case ST_INITIAL: 50506337856SBrian Somers if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { 50606337856SBrian Somers /* 50706337856SBrian Somers * ccp_SetOpenMode() leaves us in initial if we're disabling 5085d9e6103SBrian Somers * & denying everything. 50906337856SBrian Somers */ 51026af0ae9SBrian Somers bp = m_prepend(bp, lhp, sizeof *lhp, 2); 5115d9e6103SBrian Somers bp = proto_Prepend(bp, fp->proto, 0, 0); 51226af0ae9SBrian Somers bp = m_pullup(bp); 51326af0ae9SBrian Somers lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->m_len); 51426af0ae9SBrian Somers m_freem(bp); 51506337856SBrian Somers return; 51606337856SBrian Somers } 51706337856SBrian Somers /* Drop through */ 518af57ed9fSAtsushi Murai case ST_STARTING: 519dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", 520d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 52126af0ae9SBrian Somers m_freem(bp); 522af57ed9fSAtsushi Murai return; 523af57ed9fSAtsushi Murai case ST_CLOSED: 5242267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 52526af0ae9SBrian Somers m_freem(bp); 526af57ed9fSAtsushi Murai return; 527af57ed9fSAtsushi Murai case ST_CLOSING: 528dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", 529d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 530a9c503afSBrian Somers case ST_STOPPING: 53126af0ae9SBrian Somers m_freem(bp); 532af57ed9fSAtsushi Murai return; 533af57ed9fSAtsushi Murai case ST_STOPPED: 534479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 535d14cc5f9SBrian Somers /* Drop through */ 53668a0e171SBrian Somers case ST_OPENED: 537af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 538af57ed9fSAtsushi Murai break; 539af57ed9fSAtsushi Murai } 540af57ed9fSAtsushi Murai 54130c2f2ffSBrian Somers if (dec.rejend != dec.rej) 542411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej, 543411675baSBrian Somers MB_UNKNOWN); 54430c2f2ffSBrian Somers if (dec.nakend != dec.nak) 545411675baSBrian Somers fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak, 546411675baSBrian Somers MB_UNKNOWN); 547af57ed9fSAtsushi Murai if (ackaction) 548411675baSBrian Somers fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack, 549411675baSBrian Somers MB_UNKNOWN); 550af57ed9fSAtsushi Murai 551af57ed9fSAtsushi Murai switch (fp->state) { 552455aabc3SBrian Somers case ST_STOPPED: 553479508cfSBrian Somers /* 554479508cfSBrian Somers * According to the RFC (1661) state transition table, a TLS isn't 555479508cfSBrian Somers * required for a RCR when state == ST_STOPPED, but the RFC 556479508cfSBrian Somers * must be wrong as TLS hasn't yet been called (since the last TLF) 557479508cfSBrian Somers */ 558479508cfSBrian Somers (*fp->fn->LayerStart)(fp); 559479508cfSBrian Somers (*fp->parent->LayerStart)(fp->parent->object, fp); 560479508cfSBrian Somers /* Fall through */ 561479508cfSBrian Somers 562479508cfSBrian Somers case ST_OPENED: 563af57ed9fSAtsushi Murai if (ackaction) 564af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 565af57ed9fSAtsushi Murai else 566af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 56730949fd4SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 568af57ed9fSAtsushi Murai break; 569af57ed9fSAtsushi Murai case ST_REQSENT: 570af57ed9fSAtsushi Murai if (ackaction) 571af57ed9fSAtsushi Murai NewState(fp, ST_ACKSENT); 572af57ed9fSAtsushi Murai break; 573af57ed9fSAtsushi Murai case ST_ACKRCVD: 574af57ed9fSAtsushi Murai if (ackaction) { 575af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 5766f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 5776d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 5786f384573SBrian Somers else { 5796f384573SBrian Somers (*fp->fn->LayerDown)(fp); 580479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 5816f384573SBrian Somers FsmSendTerminateReq(fp); 5826f384573SBrian Somers NewState(fp, ST_CLOSING); 5831038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 5846f384573SBrian Somers } 585af57ed9fSAtsushi Murai } 586af57ed9fSAtsushi Murai break; 587af57ed9fSAtsushi Murai case ST_ACKSENT: 588af57ed9fSAtsushi Murai if (!ackaction) 589af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 590af57ed9fSAtsushi Murai break; 591af57ed9fSAtsushi Murai } 59226af0ae9SBrian Somers m_freem(bp); 593479508cfSBrian Somers 594479508cfSBrian Somers if (dec.rejend != dec.rej && --fp->more.rejs <= 0) { 595479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s REJs sent - abandoning negotiation\n", 596479508cfSBrian Somers fp->link->name, fp->name); 5971038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 598479508cfSBrian Somers fsm_Close(fp); 599479508cfSBrian Somers } 600479508cfSBrian Somers 601479508cfSBrian Somers if (dec.nakend != dec.nak && --fp->more.naks <= 0) { 602479508cfSBrian Somers log_Printf(LogPHASE, "%s: Too many %s NAKs sent - abandoning negotiation\n", 603479508cfSBrian Somers fp->link->name, fp->name); 6041038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 605479508cfSBrian Somers fsm_Close(fp); 606479508cfSBrian Somers } 607af57ed9fSAtsushi Murai } 608af57ed9fSAtsushi Murai 60975240ed1SBrian Somers static void 610944f7098SBrian Somers FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 611944f7098SBrian Somers /* RCA */ 612af57ed9fSAtsushi Murai { 613ff360cc9SBrian Somers struct fsm_decode dec; 614ff360cc9SBrian Somers int plen, flen; 615ff360cc9SBrian Somers u_char *cp; 616ff360cc9SBrian Somers 617ff360cc9SBrian Somers plen = m_length(bp); 618ff360cc9SBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 619ff360cc9SBrian Somers if (plen < flen) { 620ff360cc9SBrian Somers m_freem(bp); 621ff360cc9SBrian Somers return; 622ff360cc9SBrian Somers } 623ff360cc9SBrian Somers 624ff360cc9SBrian Somers bp = m_pullup(bp); 625ff360cc9SBrian Somers dec.ackend = dec.ack; 626ff360cc9SBrian Somers dec.nakend = dec.nak; 627ff360cc9SBrian Somers dec.rejend = dec.rej; 628ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 629ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_ACK, &dec); 630ff360cc9SBrian Somers if (flen < sizeof(struct fsm_opt_hdr)) 631ff360cc9SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 632ff360cc9SBrian Somers 633af57ed9fSAtsushi Murai switch (fp->state) { 634af57ed9fSAtsushi Murai case ST_CLOSED: 635af57ed9fSAtsushi Murai case ST_STOPPED: 6362267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 637af57ed9fSAtsushi Murai break; 638af57ed9fSAtsushi Murai case ST_CLOSING: 639af57ed9fSAtsushi Murai case ST_STOPPING: 640af57ed9fSAtsushi Murai break; 641af57ed9fSAtsushi Murai case ST_REQSENT: 642479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 643af57ed9fSAtsushi Murai NewState(fp, ST_ACKRCVD); 644af57ed9fSAtsushi Murai break; 645af57ed9fSAtsushi Murai case ST_ACKRCVD: 646af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 647af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 648af57ed9fSAtsushi Murai break; 649af57ed9fSAtsushi Murai case ST_ACKSENT: 650479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 651af57ed9fSAtsushi Murai NewState(fp, ST_OPENED); 6526f384573SBrian Somers if ((*fp->fn->LayerUp)(fp)) 6536d666775SBrian Somers (*fp->parent->LayerUp)(fp->parent->object, fp); 6546f384573SBrian Somers else { 6556f384573SBrian Somers (*fp->fn->LayerDown)(fp); 656479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 6576f384573SBrian Somers FsmSendTerminateReq(fp); 6586f384573SBrian Somers NewState(fp, ST_CLOSING); 6591038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 6606f384573SBrian Somers } 661af57ed9fSAtsushi Murai break; 662af57ed9fSAtsushi Murai case ST_OPENED: 6636d666775SBrian Somers (*fp->fn->LayerDown)(fp); 664af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 665af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 6666d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 667af57ed9fSAtsushi Murai break; 668af57ed9fSAtsushi Murai } 66926af0ae9SBrian Somers m_freem(bp); 670af57ed9fSAtsushi Murai } 671af57ed9fSAtsushi Murai 67275240ed1SBrian Somers static void 673944f7098SBrian Somers FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 674944f7098SBrian Somers /* RCN */ 675af57ed9fSAtsushi Murai { 67630c2f2ffSBrian Somers struct fsm_decode dec; 67753c9f6c0SAtsushi Murai int plen, flen; 678ff360cc9SBrian Somers u_char *cp; 679af57ed9fSAtsushi Murai 68026af0ae9SBrian Somers plen = m_length(bp); 68170ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 68253c9f6c0SAtsushi Murai if (plen < flen) { 68326af0ae9SBrian Somers m_freem(bp); 684af57ed9fSAtsushi Murai return; 685af57ed9fSAtsushi Murai } 686af57ed9fSAtsushi Murai 687af57ed9fSAtsushi Murai /* 688af57ed9fSAtsushi Murai * Check and process easy case 689af57ed9fSAtsushi Murai */ 690af57ed9fSAtsushi Murai switch (fp->state) { 691af57ed9fSAtsushi Murai case ST_INITIAL: 692af57ed9fSAtsushi Murai case ST_STARTING: 693dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", 694d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 69526af0ae9SBrian Somers m_freem(bp); 696af57ed9fSAtsushi Murai return; 697af57ed9fSAtsushi Murai case ST_CLOSED: 698af57ed9fSAtsushi Murai case ST_STOPPED: 6992267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 70026af0ae9SBrian Somers m_freem(bp); 701af57ed9fSAtsushi Murai return; 702af57ed9fSAtsushi Murai case ST_CLOSING: 703af57ed9fSAtsushi Murai case ST_STOPPING: 70426af0ae9SBrian Somers m_freem(bp); 705af57ed9fSAtsushi Murai return; 706af57ed9fSAtsushi Murai } 707af57ed9fSAtsushi Murai 70826af0ae9SBrian Somers bp = m_pullup(bp); 70930c2f2ffSBrian Somers dec.ackend = dec.ack; 71030c2f2ffSBrian Somers dec.nakend = dec.nak; 71130c2f2ffSBrian Somers dec.rejend = dec.rej; 712ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 713ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_NAK, &dec); 714ff360cc9SBrian Somers if (flen < sizeof(struct fsm_opt_hdr)) 715dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 716af57ed9fSAtsushi Murai 717af57ed9fSAtsushi Murai switch (fp->state) { 718af57ed9fSAtsushi Murai case ST_REQSENT: 719af57ed9fSAtsushi Murai case ST_ACKSENT: 720479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 721af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 722af57ed9fSAtsushi Murai break; 723af57ed9fSAtsushi Murai case ST_OPENED: 7246d666775SBrian Somers (*fp->fn->LayerDown)(fp); 725455aabc3SBrian Somers FsmSendConfigReq(fp); 726455aabc3SBrian Somers NewState(fp, ST_REQSENT); 7276d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 728455aabc3SBrian Somers break; 729af57ed9fSAtsushi Murai case ST_ACKRCVD: 730af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 731af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 732af57ed9fSAtsushi Murai break; 733af57ed9fSAtsushi Murai } 734af57ed9fSAtsushi Murai 73526af0ae9SBrian Somers m_freem(bp); 736af57ed9fSAtsushi Murai } 737af57ed9fSAtsushi Murai 73875240ed1SBrian Somers static void 739944f7098SBrian Somers FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 740944f7098SBrian Somers /* RTR */ 741af57ed9fSAtsushi Murai { 742af57ed9fSAtsushi Murai switch (fp->state) { 743af57ed9fSAtsushi Murai case ST_INITIAL: 744af57ed9fSAtsushi Murai case ST_STARTING: 745dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", 746d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 747af57ed9fSAtsushi Murai break; 748af57ed9fSAtsushi Murai case ST_CLOSED: 749af57ed9fSAtsushi Murai case ST_STOPPED: 750af57ed9fSAtsushi Murai case ST_CLOSING: 751af57ed9fSAtsushi Murai case ST_STOPPING: 752af57ed9fSAtsushi Murai case ST_REQSENT: 7532267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 754af57ed9fSAtsushi Murai break; 755af57ed9fSAtsushi Murai case ST_ACKRCVD: 756af57ed9fSAtsushi Murai case ST_ACKSENT: 7572267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 758af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 759af57ed9fSAtsushi Murai break; 760af57ed9fSAtsushi Murai case ST_OPENED: 7616d666775SBrian Somers (*fp->fn->LayerDown)(fp); 7622267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 763479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_TRM_TIMER); 764dd7e2610SBrian Somers timer_Start(&fp->FsmTimer); /* Start restart timer */ 7658f2fa0eeSBrian Somers fp->restart = 0; 7668f2fa0eeSBrian Somers NewState(fp, ST_STOPPING); 7676d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 768479508cfSBrian Somers /* A delayed ST_STOPPED is now scheduled */ 769af57ed9fSAtsushi Murai break; 770af57ed9fSAtsushi Murai } 77126af0ae9SBrian Somers m_freem(bp); 772af57ed9fSAtsushi Murai } 773af57ed9fSAtsushi Murai 77475240ed1SBrian Somers static void 775944f7098SBrian Somers FsmRecvTermAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 776944f7098SBrian Somers /* RTA */ 777af57ed9fSAtsushi Murai { 778af57ed9fSAtsushi Murai switch (fp->state) { 779af57ed9fSAtsushi Murai case ST_CLOSING: 7806d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 781af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 7826d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 783af57ed9fSAtsushi Murai break; 784af57ed9fSAtsushi Murai case ST_STOPPING: 7856d666775SBrian Somers (*fp->fn->LayerFinish)(fp); 786af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 7876d666775SBrian Somers (*fp->parent->LayerFinish)(fp->parent->object, fp); 788af57ed9fSAtsushi Murai break; 789af57ed9fSAtsushi Murai case ST_ACKRCVD: 790af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 791af57ed9fSAtsushi Murai break; 792af57ed9fSAtsushi Murai case ST_OPENED: 7936d666775SBrian Somers (*fp->fn->LayerDown)(fp); 794af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 795af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 7966d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 797af57ed9fSAtsushi Murai break; 798af57ed9fSAtsushi Murai } 79926af0ae9SBrian Somers m_freem(bp); 800af57ed9fSAtsushi Murai } 801af57ed9fSAtsushi Murai 80275240ed1SBrian Somers static void 803944f7098SBrian Somers FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 804944f7098SBrian Somers /* RCJ */ 805af57ed9fSAtsushi Murai { 80630c2f2ffSBrian Somers struct fsm_decode dec; 80753c9f6c0SAtsushi Murai int plen, flen; 808ff360cc9SBrian Somers u_char *cp; 809af57ed9fSAtsushi Murai 81026af0ae9SBrian Somers plen = m_length(bp); 81170ee81ffSBrian Somers flen = ntohs(lhp->length) - sizeof *lhp; 81253c9f6c0SAtsushi Murai if (plen < flen) { 81326af0ae9SBrian Somers m_freem(bp); 814af57ed9fSAtsushi Murai return; 815af57ed9fSAtsushi Murai } 816af57ed9fSAtsushi Murai 8171038894eSBrian Somers lcp_SendIdentification(&fp->link->lcp); 8181038894eSBrian Somers 819af57ed9fSAtsushi Murai /* 820af57ed9fSAtsushi Murai * Check and process easy case 821af57ed9fSAtsushi Murai */ 822af57ed9fSAtsushi Murai switch (fp->state) { 823af57ed9fSAtsushi Murai case ST_INITIAL: 824af57ed9fSAtsushi Murai case ST_STARTING: 825dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", 826d47dceb8SBrian Somers fp->link->name, State2Nam(fp->state)); 82726af0ae9SBrian Somers m_freem(bp); 828af57ed9fSAtsushi Murai return; 829af57ed9fSAtsushi Murai case ST_CLOSED: 830af57ed9fSAtsushi Murai case ST_STOPPED: 8312267893fSBrian Somers (*fp->fn->SendTerminateAck)(fp, lhp->id); 83226af0ae9SBrian Somers m_freem(bp); 833af57ed9fSAtsushi Murai return; 834af57ed9fSAtsushi Murai case ST_CLOSING: 835af57ed9fSAtsushi Murai case ST_STOPPING: 83626af0ae9SBrian Somers m_freem(bp); 837af57ed9fSAtsushi Murai return; 838af57ed9fSAtsushi Murai } 839af57ed9fSAtsushi Murai 84026af0ae9SBrian Somers bp = m_pullup(bp); 84130c2f2ffSBrian Somers dec.ackend = dec.ack; 84230c2f2ffSBrian Somers dec.nakend = dec.nak; 84330c2f2ffSBrian Somers dec.rejend = dec.rej; 844ff360cc9SBrian Somers cp = MBUF_CTOP(bp); 845ff360cc9SBrian Somers (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_REJ, &dec); 846ff360cc9SBrian Somers if (flen < sizeof(struct fsm_opt_hdr)) 847dd7e2610SBrian Somers log_Printf(fp->LogLevel, " [EMPTY]\n"); 848af57ed9fSAtsushi Murai 849af57ed9fSAtsushi Murai switch (fp->state) { 850af57ed9fSAtsushi Murai case ST_REQSENT: 851af57ed9fSAtsushi Murai case ST_ACKSENT: 852479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 853af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 854af57ed9fSAtsushi Murai break; 855af57ed9fSAtsushi Murai case ST_OPENED: 8566d666775SBrian Somers (*fp->fn->LayerDown)(fp); 857455aabc3SBrian Somers FsmSendConfigReq(fp); 858455aabc3SBrian Somers NewState(fp, ST_REQSENT); 8596d666775SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 860455aabc3SBrian Somers break; 861af57ed9fSAtsushi Murai case ST_ACKRCVD: 862af57ed9fSAtsushi Murai FsmSendConfigReq(fp); 863af57ed9fSAtsushi Murai NewState(fp, ST_REQSENT); 864af57ed9fSAtsushi Murai break; 865af57ed9fSAtsushi Murai } 86626af0ae9SBrian Somers m_freem(bp); 867af57ed9fSAtsushi Murai } 868af57ed9fSAtsushi Murai 86975240ed1SBrian Somers static void 870944f7098SBrian Somers FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 871af57ed9fSAtsushi Murai { 87226af0ae9SBrian Somers m_freem(bp); 873af57ed9fSAtsushi Murai } 874af57ed9fSAtsushi Murai 87575240ed1SBrian Somers static void 876944f7098SBrian Somers FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 877af57ed9fSAtsushi Murai { 8788c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 8793377c28cSBrian Somers u_short proto; 880af57ed9fSAtsushi Murai 88126af0ae9SBrian Somers if (m_length(bp) < 2) { 88226af0ae9SBrian Somers m_freem(bp); 8833377c28cSBrian Somers return; 8843377c28cSBrian Somers } 8853377c28cSBrian Somers bp = mbuf_Read(bp, &proto, 2); 8863377c28cSBrian Somers proto = ntohs(proto); 887dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", 888d47dceb8SBrian Somers fp->link->name, proto, hdlc_Protocol2Nam(proto)); 889af57ed9fSAtsushi Murai 890af57ed9fSAtsushi Murai switch (proto) { 891af57ed9fSAtsushi Murai case PROTO_LQR: 8928c07a7b2SBrian Somers if (p) 893dd7e2610SBrian Somers lqr_Stop(p, LQM_LQR); 8948c07a7b2SBrian Somers else 895dd7e2610SBrian Somers log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", 896d47dceb8SBrian Somers fp->link->name); 897af57ed9fSAtsushi Murai break; 898af57ed9fSAtsushi Murai case PROTO_CCP: 899dc0fdb6bSBrian Somers if (fp->proto == PROTO_LCP) { 9003b0f8d2eSBrian Somers fp = &fp->link->ccp.fsm; 9018a8d9927SBrian Somers /* Despite the RFC (1661), don't do an out-of-place TLF */ 9028a8d9927SBrian Somers /* (*fp->fn->LayerFinish)(fp); */ 903af57ed9fSAtsushi Murai switch (fp->state) { 904af57ed9fSAtsushi Murai case ST_CLOSED: 905af57ed9fSAtsushi Murai case ST_CLOSING: 906af57ed9fSAtsushi Murai NewState(fp, ST_CLOSED); 907ad65ae3aSBrian Somers break; 908af57ed9fSAtsushi Murai default: 909af57ed9fSAtsushi Murai NewState(fp, ST_STOPPED); 910af57ed9fSAtsushi Murai break; 911af57ed9fSAtsushi Murai } 9128a8d9927SBrian Somers /* See above */ 9138a8d9927SBrian Somers /* (*fp->parent->LayerFinish)(fp->parent->object, fp); */ 914dc0fdb6bSBrian Somers } 9151ae349f5Scvs2svn break; 9168a59beb7SBrian Somers case PROTO_IPCP: 9178a59beb7SBrian Somers if (fp->proto == PROTO_LCP) { 9188a59beb7SBrian Somers log_Printf(LogPHASE, "%s: IPCP protocol reject closes IPCP !\n", 9198a59beb7SBrian Somers fp->link->name); 9208a59beb7SBrian Somers fsm_Close(&fp->bundle->ncp.ipcp.fsm); 9218a59beb7SBrian Somers } 9228a59beb7SBrian Somers break; 92330949fd4SBrian Somers #ifndef NOINET6 92430949fd4SBrian Somers case PROTO_IPV6CP: 9251136c6acSBrian Somers if (fp->proto == PROTO_LCP) { 92630949fd4SBrian Somers log_Printf(LogPHASE, "%s: IPV6CP protocol reject closes IPV6CP !\n", 92730949fd4SBrian Somers fp->link->name); 92830949fd4SBrian Somers fsm_Close(&fp->bundle->ncp.ipv6cp.fsm); 92930949fd4SBrian Somers } 93030949fd4SBrian Somers break; 93130949fd4SBrian Somers #endif 932673903ecSBrian Somers case PROTO_MP: 933673903ecSBrian Somers if (fp->proto == PROTO_LCP) { 934673903ecSBrian Somers struct lcp *lcp = fsm2lcp(fp); 935673903ecSBrian Somers 936673903ecSBrian Somers if (lcp->want_mrru && lcp->his_mrru) { 937dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", 938d47dceb8SBrian Somers fp->link->name); 939dd7e2610SBrian Somers fsm_Close(fp); 940673903ecSBrian Somers } 941673903ecSBrian Somers } 942af57ed9fSAtsushi Murai break; 943af57ed9fSAtsushi Murai } 94426af0ae9SBrian Somers m_freem(bp); 945af57ed9fSAtsushi Murai } 946af57ed9fSAtsushi Murai 94775240ed1SBrian Somers static void 948944f7098SBrian Somers FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 949af57ed9fSAtsushi Murai { 950dc0fdb6bSBrian Somers struct lcp *lcp = fsm2lcp(fp); 951af57ed9fSAtsushi Murai u_char *cp; 952fe3125a0SBrian Somers u_int32_t magic; 953af57ed9fSAtsushi Murai 95426af0ae9SBrian Somers bp = m_pullup(bp); 95526af0ae9SBrian Somers m_settype(bp, MB_ECHOIN); 95687c3786eSBrian Somers 95787c3786eSBrian Somers if (lcp && ntohs(lhp->length) - sizeof *lhp >= 4) { 958af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 9599e8ec64bSBrian Somers ua_ntohl(cp, &magic); 960dc0fdb6bSBrian Somers if (magic != lcp->his_magic) { 961990a543fSBrian Somers log_Printf(fp->LogLevel, "%s: RecvEchoReq: magic 0x%08lx is wrong," 962990a543fSBrian Somers " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 963990a543fSBrian Somers (u_long)lcp->his_magic); 964af57ed9fSAtsushi Murai /* XXX: We should send terminate request */ 965af57ed9fSAtsushi Murai } 966af57ed9fSAtsushi Murai if (fp->state == ST_OPENED) { 9679e8ec64bSBrian Somers ua_htonl(&lcp->want_magic, cp); /* local magic */ 96887c3786eSBrian Somers fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, 96987c3786eSBrian Somers ntohs(lhp->length) - sizeof *lhp, MB_ECHOOUT); 970af57ed9fSAtsushi Murai } 971dc0fdb6bSBrian Somers } 97226af0ae9SBrian Somers m_freem(bp); 973af57ed9fSAtsushi Murai } 974af57ed9fSAtsushi Murai 97575240ed1SBrian Somers static void 976944f7098SBrian Somers FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 977af57ed9fSAtsushi Murai { 9786471628dSBrian Somers if (fsm2lcp(fp)) 9793377c28cSBrian Somers bp = lqr_RecvEcho(fp, bp); 9806471628dSBrian Somers 98126af0ae9SBrian Somers m_freem(bp); 982af57ed9fSAtsushi Murai } 983af57ed9fSAtsushi Murai 98475240ed1SBrian Somers static void 985944f7098SBrian Somers FsmRecvDiscReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 986af57ed9fSAtsushi Murai { 98726af0ae9SBrian Somers m_freem(bp); 988af57ed9fSAtsushi Murai } 989af57ed9fSAtsushi Murai 99075240ed1SBrian Somers static void 991944f7098SBrian Somers FsmRecvIdent(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 992af57ed9fSAtsushi Murai { 9931038894eSBrian Somers u_int32_t magic; 9941038894eSBrian Somers u_short len; 9951038894eSBrian Somers u_char *cp; 9961038894eSBrian Somers 9971038894eSBrian Somers len = ntohs(lhp->length) - sizeof *lhp; 9981038894eSBrian Somers if (len >= 4) { 9991038894eSBrian Somers bp = m_pullup(m_append(bp, "", 1)); 10001038894eSBrian Somers cp = MBUF_CTOP(bp); 10011038894eSBrian Somers ua_ntohl(cp, &magic); 10021038894eSBrian Somers if (magic != fp->link->lcp.his_magic) 10031038894eSBrian Somers log_Printf(fp->LogLevel, "%s: RecvIdent: magic 0x%08lx is wrong," 10041038894eSBrian Somers " expecting 0x%08lx\n", fp->link->name, (u_long)magic, 10051038894eSBrian Somers (u_long)fp->link->lcp.his_magic); 10061038894eSBrian Somers cp[len] = '\0'; 10071038894eSBrian Somers lcp_RecvIdentification(&fp->link->lcp, cp + 4); 10081038894eSBrian Somers } 100926af0ae9SBrian Somers m_freem(bp); 1010af57ed9fSAtsushi Murai } 1011af57ed9fSAtsushi Murai 101275240ed1SBrian Somers static void 1013944f7098SBrian Somers FsmRecvTimeRemain(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 1014af57ed9fSAtsushi Murai { 101526af0ae9SBrian Somers m_freem(bp); 1016af57ed9fSAtsushi Murai } 1017af57ed9fSAtsushi Murai 101875240ed1SBrian Somers static void 1019944f7098SBrian Somers FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 1020af57ed9fSAtsushi Murai { 10216cf6ee76SBrian Somers if ((*fp->fn->RecvResetReq)(fp)) { 102298baf7c8SBrian Somers /* 1023442f8495SBrian Somers * All sendable compressed packets are queued in the first (lowest 1024442f8495SBrian Somers * priority) modem output queue.... dump 'em to the priority queue 1025442f8495SBrian Somers * so that they arrive at the peer before our ResetAck. 102698baf7c8SBrian Somers */ 10278c07a7b2SBrian Somers link_SequenceQueue(fp->link); 1028411675baSBrian Somers fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0, MB_CCPOUT); 10296cf6ee76SBrian Somers } 103026af0ae9SBrian Somers m_freem(bp); 1031af57ed9fSAtsushi Murai } 1032af57ed9fSAtsushi Murai 103375240ed1SBrian Somers static void 1034944f7098SBrian Somers FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) 1035af57ed9fSAtsushi Murai { 1036503a7782SBrian Somers (*fp->fn->RecvResetAck)(fp, lhp->id); 103726af0ae9SBrian Somers m_freem(bp); 1038af57ed9fSAtsushi Murai } 1039af57ed9fSAtsushi Murai 1040af57ed9fSAtsushi Murai void 1041dd7e2610SBrian Somers fsm_Input(struct fsm *fp, struct mbuf *bp) 1042af57ed9fSAtsushi Murai { 1043af57ed9fSAtsushi Murai int len; 10445d9e6103SBrian Somers struct fsmheader lh; 10450053cc58SBrian Somers const struct fsmcodedesc *codep; 1046af57ed9fSAtsushi Murai 104726af0ae9SBrian Somers len = m_length(bp); 1048af57ed9fSAtsushi Murai if (len < sizeof(struct fsmheader)) { 104926af0ae9SBrian Somers m_freem(bp); 1050af57ed9fSAtsushi Murai return; 1051af57ed9fSAtsushi Murai } 10525d9e6103SBrian Somers bp = mbuf_Read(bp, &lh, sizeof lh); 105387c3786eSBrian Somers 1054962a3cbcSBrian Somers if (ntohs(lh.length) > len) { 1055962a3cbcSBrian Somers log_Printf(LogWARN, "%s: Oops: Got %d bytes but %d byte payload " 1056962a3cbcSBrian Somers "- dropped\n", fp->link->name, len, (int)ntohs(lh.length)); 1057962a3cbcSBrian Somers m_freem(bp); 1058962a3cbcSBrian Somers return; 1059962a3cbcSBrian Somers } 106087c3786eSBrian Somers 10615d9e6103SBrian Somers if (lh.code < fp->min_code || lh.code > fp->max_code || 10625d9e6103SBrian Somers lh.code > sizeof FsmCodes / sizeof *FsmCodes) { 10633b0f8d2eSBrian Somers /* 10643b0f8d2eSBrian Somers * Use a private id. This is really a response-type packet, but we 10653b0f8d2eSBrian Somers * MUST send a unique id for each REQ.... 10663b0f8d2eSBrian Somers */ 10673b0f8d2eSBrian Somers static u_char id; 1068d93d3a9cSBrian Somers 106926af0ae9SBrian Somers bp = m_prepend(bp, &lh, sizeof lh, 0); 107026af0ae9SBrian Somers bp = m_pullup(bp); 107126af0ae9SBrian Somers fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->m_len, MB_UNKNOWN); 107226af0ae9SBrian Somers m_freem(bp); 1073af57ed9fSAtsushi Murai return; 1074af57ed9fSAtsushi Murai } 1075af57ed9fSAtsushi Murai 10765d9e6103SBrian Somers codep = FsmCodes + lh.code - 1; 10775d9e6103SBrian Somers if (lh.id != fp->reqid && codep->check_reqid && 10781342caedSBrian Somers Enabled(fp->bundle, OPT_IDCHECK)) { 1079dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", 10805d9e6103SBrian Somers fp->link->name, codep->name, lh.id, fp->reqid); 10812267893fSBrian Somers return; 10822267893fSBrian Somers } 10832267893fSBrian Somers 1084dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", 10855d9e6103SBrian Somers fp->link->name, codep->name, lh.id, State2Nam(fp->state)); 10862267893fSBrian Somers 10875d9e6103SBrian Somers if (codep->inc_reqid && (lh.id == fp->reqid || 10881342caedSBrian Somers (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) 10892267893fSBrian Somers fp->reqid++; /* That's the end of that ``exchange''.... */ 10902267893fSBrian Somers 10915d9e6103SBrian Somers (*codep->recv)(fp, &lh, bp); 10921ae349f5Scvs2svn } 1093503a7782SBrian Somers 10946cf6ee76SBrian Somers int 1095dd7e2610SBrian Somers fsm_NullRecvResetReq(struct fsm *fp) 1096503a7782SBrian Somers { 1097dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", 1098d47dceb8SBrian Somers fp->link->name); 10996cf6ee76SBrian Somers return 1; 1100503a7782SBrian Somers } 1101503a7782SBrian Somers 1102503a7782SBrian Somers void 1103dd7e2610SBrian Somers fsm_NullRecvResetAck(struct fsm *fp, u_char id) 1104503a7782SBrian Somers { 1105dd7e2610SBrian Somers log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", 1106d47dceb8SBrian Somers fp->link->name); 1107af57ed9fSAtsushi Murai } 110809206a6fSBrian Somers 110909206a6fSBrian Somers void 1110897f9429SBrian Somers fsm_Reopen(struct fsm *fp) 1111897f9429SBrian Somers { 1112897f9429SBrian Somers if (fp->state == ST_OPENED) { 1113897f9429SBrian Somers (*fp->fn->LayerDown)(fp); 1114479508cfSBrian Somers FsmInitRestartCounter(fp, FSM_REQ_TIMER); 1115897f9429SBrian Somers FsmSendConfigReq(fp); 1116897f9429SBrian Somers NewState(fp, ST_REQSENT); 1117897f9429SBrian Somers (*fp->parent->LayerDown)(fp->parent->object, fp); 1118897f9429SBrian Somers } 1119897f9429SBrian Somers } 1120897f9429SBrian Somers 1121897f9429SBrian Somers void 112209206a6fSBrian Somers fsm2initial(struct fsm *fp) 112309206a6fSBrian Somers { 1124479508cfSBrian Somers timer_Stop(&fp->FsmTimer); 1125479508cfSBrian Somers timer_Stop(&fp->OpenTimer); 1126479508cfSBrian Somers timer_Stop(&fp->StoppedTimer); 112709206a6fSBrian Somers if (fp->state == ST_STOPPED) 112809206a6fSBrian Somers fsm_Close(fp); 112909206a6fSBrian Somers if (fp->state > ST_INITIAL) 113009206a6fSBrian Somers fsm_Down(fp); 113109206a6fSBrian Somers if (fp->state > ST_INITIAL) 113209206a6fSBrian Somers fsm_Close(fp); 113309206a6fSBrian Somers } 1134ff360cc9SBrian Somers 1135ff360cc9SBrian Somers struct fsm_opt * 1136ff360cc9SBrian Somers fsm_readopt(u_char **cp) 1137ff360cc9SBrian Somers { 1138ff360cc9SBrian Somers struct fsm_opt *o = (struct fsm_opt *)*cp; 1139ff360cc9SBrian Somers 1140ff360cc9SBrian Somers if (o->hdr.len < sizeof(struct fsm_opt_hdr)) { 1141ff360cc9SBrian Somers log_Printf(LogERROR, "Bad option length %d (out of phase?)\n", o->hdr.len); 1142ff360cc9SBrian Somers return NULL; 1143ff360cc9SBrian Somers } 1144ff360cc9SBrian Somers 1145ff360cc9SBrian Somers *cp += o->hdr.len; 1146ff360cc9SBrian Somers 1147ff360cc9SBrian Somers if (o->hdr.len > sizeof(struct fsm_opt)) { 1148ff360cc9SBrian Somers o->hdr.len = sizeof(struct fsm_opt); 1149ff360cc9SBrian Somers log_Printf(LogERROR, "Warning: Truncating option length to %d\n", 1150ff360cc9SBrian Somers o->hdr.len); 1151ff360cc9SBrian Somers } 1152ff360cc9SBrian Somers 1153ff360cc9SBrian Somers return o; 1154ff360cc9SBrian Somers } 1155ff360cc9SBrian Somers 1156ff360cc9SBrian Somers static int 1157ff360cc9SBrian Somers fsm_opt(u_char *opt, int optlen, const struct fsm_opt *o) 1158ff360cc9SBrian Somers { 1159ff360cc9SBrian Somers int cplen = o->hdr.len; 1160ff360cc9SBrian Somers 1161ff360cc9SBrian Somers if (optlen < sizeof(struct fsm_opt_hdr)) 1162ff360cc9SBrian Somers optlen = 0; 1163ff360cc9SBrian Somers 1164ff360cc9SBrian Somers if (cplen > optlen) { 1165ff360cc9SBrian Somers log_Printf(LogERROR, "Can't REJ length %d - trunating to %d\n", 1166ff360cc9SBrian Somers cplen, optlen); 1167ff360cc9SBrian Somers cplen = optlen; 1168ff360cc9SBrian Somers } 1169ff360cc9SBrian Somers memcpy(opt, o, cplen); 1170ff360cc9SBrian Somers if (cplen) 1171ff360cc9SBrian Somers opt[1] = cplen; 1172ff360cc9SBrian Somers 1173ff360cc9SBrian Somers return cplen; 1174ff360cc9SBrian Somers } 1175ff360cc9SBrian Somers 1176ff360cc9SBrian Somers void 1177ff360cc9SBrian Somers fsm_rej(struct fsm_decode *dec, const struct fsm_opt *o) 1178ff360cc9SBrian Somers { 1179ff360cc9SBrian Somers if (!dec) 1180ff360cc9SBrian Somers return; 1181ff360cc9SBrian Somers dec->rejend += fsm_opt(dec->rejend, FSM_OPTLEN - (dec->rejend - dec->rej), o); 1182ff360cc9SBrian Somers } 1183ff360cc9SBrian Somers 1184ff360cc9SBrian Somers void 1185ff360cc9SBrian Somers fsm_ack(struct fsm_decode *dec, const struct fsm_opt *o) 1186ff360cc9SBrian Somers { 1187ff360cc9SBrian Somers if (!dec) 1188ff360cc9SBrian Somers return; 1189ff360cc9SBrian Somers dec->ackend += fsm_opt(dec->ackend, FSM_OPTLEN - (dec->ackend - dec->ack), o); 1190ff360cc9SBrian Somers } 1191ff360cc9SBrian Somers 1192ff360cc9SBrian Somers void 1193ff360cc9SBrian Somers fsm_nak(struct fsm_decode *dec, const struct fsm_opt *o) 1194ff360cc9SBrian Somers { 1195ff360cc9SBrian Somers if (!dec) 1196ff360cc9SBrian Somers return; 1197ff360cc9SBrian Somers dec->nakend += fsm_opt(dec->nakend, FSM_OPTLEN - (dec->nakend - dec->nak), o); 1198ff360cc9SBrian Somers } 1199ff360cc9SBrian Somers 1200ff360cc9SBrian Somers void 1201ff360cc9SBrian Somers fsm_opt_normalise(struct fsm_decode *dec) 1202ff360cc9SBrian Somers { 1203ff360cc9SBrian Somers if (dec->rejend != dec->rej) { 1204ff360cc9SBrian Somers /* rejects are preferred */ 1205ff360cc9SBrian Somers dec->ackend = dec->ack; 1206ff360cc9SBrian Somers dec->nakend = dec->nak; 1207ff360cc9SBrian Somers } else if (dec->nakend != dec->nak) 1208ff360cc9SBrian Somers /* then NAKs */ 1209ff360cc9SBrian Somers dec->ackend = dec->ack; 1210ff360cc9SBrian Somers } 1211