178189Sbrian/*-
278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
378189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
478189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai *
2850479Speter * $FreeBSD$
296059Samurai */
3036285Sbrian
3143313Sbrian#include <sys/param.h>
3230715Sbrian#include <netinet/in.h>
3336285Sbrian#include <netinet/in_systm.h>
3436285Sbrian#include <netinet/ip.h>
3581634Sbrian#include <sys/socket.h>
3636285Sbrian#include <sys/un.h>
3730715Sbrian
3830715Sbrian#include <string.h>
3930715Sbrian#include <termios.h>
4030715Sbrian
4146686Sbrian#include "layer.h"
4238814Sbrian#include "ua.h"
4330715Sbrian#include "mbuf.h"
4430715Sbrian#include "log.h"
4530715Sbrian#include "defs.h"
4630715Sbrian#include "timer.h"
476059Samurai#include "fsm.h"
4836285Sbrian#include "iplist.h"
4936285Sbrian#include "lqr.h"
506059Samurai#include "hdlc.h"
5136285Sbrian#include "throughput.h"
5236285Sbrian#include "slcompress.h"
5381634Sbrian#include "ncpaddr.h"
5436285Sbrian#include "ipcp.h"
5536285Sbrian#include "filter.h"
5636285Sbrian#include "descriptor.h"
576059Samurai#include "lcp.h"
5813389Sphk#include "ccp.h"
5936285Sbrian#include "link.h"
6036285Sbrian#include "mp.h"
6143313Sbrian#ifndef NORADIUS
6243313Sbrian#include "radius.h"
6343313Sbrian#endif
6481634Sbrian#include "ipv6cp.h"
6581634Sbrian#include "ncp.h"
6636285Sbrian#include "bundle.h"
6736285Sbrian#include "async.h"
6836285Sbrian#include "physical.h"
6946686Sbrian#include "proto.h"
706059Samurai
7130715Sbrianstatic void FsmSendConfigReq(struct fsm *);
7230715Sbrianstatic void FsmSendTerminateReq(struct fsm *);
7344305Sbrianstatic void FsmInitRestartCounter(struct fsm *, int);
7430715Sbrian
7536285Sbriantypedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *);
7636285Sbrianstatic recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak,
7736285Sbrian              FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck,
7836285Sbrian              FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq,
7936285Sbrian              FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent,
8036285Sbrian              FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck;
8136285Sbrian
8236285Sbrianstatic const struct fsmcodedesc {
8336285Sbrian  recvfn *recv;
8436285Sbrian  unsigned check_reqid : 1;
8536285Sbrian  unsigned inc_reqid : 1;
8636285Sbrian  const char *name;
8736285Sbrian} FsmCodes[] = {
8836285Sbrian  { FsmRecvConfigReq, 0, 0, "ConfigReq"    },
8936285Sbrian  { FsmRecvConfigAck, 1, 1, "ConfigAck"    },
9036285Sbrian  { FsmRecvConfigNak, 1, 1, "ConfigNak"    },
9136285Sbrian  { FsmRecvConfigRej, 1, 1, "ConfigRej"    },
9236285Sbrian  { FsmRecvTermReq,   0, 0, "TerminateReq" },
9336285Sbrian  { FsmRecvTermAck,   1, 1, "TerminateAck" },
9436285Sbrian  { FsmRecvCodeRej,   0, 0, "CodeRej"      },
9536285Sbrian  { FsmRecvProtoRej,  0, 0, "ProtocolRej"  },
9636285Sbrian  { FsmRecvEchoReq,   0, 0, "EchoRequest"  },
9736285Sbrian  { FsmRecvEchoRep,   0, 0, "EchoReply"    },
9836285Sbrian  { FsmRecvDiscReq,   0, 0, "DiscardReq"   },
9963484Sbrian  { FsmRecvIdent,     0, 1, "Ident"        },
10036285Sbrian  { FsmRecvTimeRemain,0, 0, "TimeRemain"   },
10146686Sbrian  { FsmRecvResetReq,  0, 0, "ResetReq"     },
10236285Sbrian  { FsmRecvResetAck,  0, 1, "ResetAck"     }
1036059Samurai};
1046059Samurai
10536285Sbrianstatic const char *
10636285SbrianCode2Nam(u_int code)
10736285Sbrian{
10836285Sbrian  if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0])
10936285Sbrian    return "Unknown";
11036285Sbrian  return FsmCodes[code-1].name;
11136285Sbrian}
11236285Sbrian
11336285Sbrianconst char *
11436285SbrianState2Nam(u_int state)
11536285Sbrian{
11655146Sbrian  static const char * const StateNames[] = {
11736285Sbrian    "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping",
11836285Sbrian    "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened",
11936285Sbrian  };
12036285Sbrian
12136285Sbrian  if (state >= sizeof StateNames / sizeof StateNames[0])
12236285Sbrian    return "unknown";
12336285Sbrian  return StateNames[state];
12436285Sbrian}
12536285Sbrian
12628327Sbrianstatic void
12731343SbrianStoppedTimeout(void *v)
12828327Sbrian{
12931343Sbrian  struct fsm *fp = (struct fsm *)v;
13031343Sbrian
13136285Sbrian  log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name);
13232658Sbrian  if (fp->OpenTimer.state == TIMER_RUNNING) {
13336285Sbrian    log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n",
13436285Sbrian              fp->link->name, fp->name);
13536285Sbrian    timer_Stop(&fp->OpenTimer);
13632658Sbrian  }
13737060Sbrian  if (fp->state == ST_STOPPED)
13837060Sbrian    fsm2initial(fp);
13928327Sbrian}
14028327Sbrian
1416059Samuraivoid
14236285Sbrianfsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode,
14344305Sbrian         int maxcode, int LogLevel, struct bundle *bundle,
14436285Sbrian         struct link *l, const struct fsm_parent *parent,
14555146Sbrian         struct fsm_callbacks *fn, const char * const timer_names[3])
1466059Samurai{
14736285Sbrian  fp->name = name;
14836285Sbrian  fp->proto = proto;
14936285Sbrian  fp->min_code = mincode;
15036285Sbrian  fp->max_code = maxcode;
15136285Sbrian  fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL;
1526059Samurai  fp->reqid = 1;
1536059Samurai  fp->restart = 1;
15446686Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = 3;
15536285Sbrian  memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer);
15636285Sbrian  memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer);
15736285Sbrian  memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer);
15836285Sbrian  fp->LogLevel = LogLevel;
15936285Sbrian  fp->link = l;
16036285Sbrian  fp->bundle = bundle;
16136285Sbrian  fp->parent = parent;
16236285Sbrian  fp->fn = fn;
16336285Sbrian  fp->FsmTimer.name = timer_names[0];
16436285Sbrian  fp->OpenTimer.name = timer_names[1];
16536285Sbrian  fp->StoppedTimer.name = timer_names[2];
1666059Samurai}
1676059Samurai
16830715Sbrianstatic void
16946828SbrianNewState(struct fsm *fp, int new)
1706059Samurai{
17136285Sbrian  log_Printf(fp->LogLevel, "%s: State change %s --> %s\n",
17294894Sbrian             fp->link->name, State2Nam(fp->state), State2Nam(new));
17328461Sbrian  if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING)
17436285Sbrian    timer_Stop(&fp->StoppedTimer);
1756059Samurai  fp->state = new;
17628327Sbrian  if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) {
17736285Sbrian    timer_Stop(&fp->FsmTimer);
17828461Sbrian    if (new == ST_STOPPED && fp->StoppedTimer.load) {
17936285Sbrian      timer_Stop(&fp->StoppedTimer);
18028461Sbrian      fp->StoppedTimer.func = StoppedTimeout;
18128679Sbrian      fp->StoppedTimer.arg = (void *) fp;
18236285Sbrian      timer_Start(&fp->StoppedTimer);
18328327Sbrian    }
18428327Sbrian  }
1856059Samurai}
1866059Samurai
1876059Samuraivoid
188134789Sbrianfsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, unsigned count,
18947695Sbrian           int mtype)
1906059Samurai{
1916059Samurai  int plen;
1926059Samurai  struct fsmheader lh;
1936059Samurai  struct mbuf *bp;
1946059Samurai
19536285Sbrian  if (log_IsKept(fp->LogLevel)) {
19636285Sbrian    log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n",
19736285Sbrian              fp->link->name, Code2Nam(code), id, State2Nam(fp->state));
19836285Sbrian    switch (code) {
19936285Sbrian      case CODE_CONFIGREQ:
20036285Sbrian      case CODE_CONFIGACK:
20136285Sbrian      case CODE_CONFIGREJ:
20236285Sbrian      case CODE_CONFIGNAK:
20394894Sbrian        (*fp->fn->DecodeConfig)(fp, ptr, ptr + count, MODE_NOP, NULL);
20494894Sbrian        if (count < sizeof(struct fsm_opt_hdr))
20536285Sbrian          log_Printf(fp->LogLevel, "  [EMPTY]\n");
20636285Sbrian        break;
20736285Sbrian    }
20836285Sbrian  }
20936285Sbrian
21028679Sbrian  plen = sizeof(struct fsmheader) + count;
2116059Samurai  lh.code = code;
2126059Samurai  lh.id = id;
2136059Samurai  lh.length = htons(plen);
21454912Sbrian  bp = m_get(plen, mtype);
21530715Sbrian  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
2166059Samurai  if (count)
21730715Sbrian    memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
21836285Sbrian  log_DumpBp(LogDEBUG, "fsm_Output", bp);
21950867Sbrian  link_PushPacket(fp->link, bp, fp->bundle, LINK_QUEUES(fp->link) - 1,
22050867Sbrian                  fp->proto);
22163484Sbrian
22263484Sbrian  if (code == CODE_CONFIGREJ)
22363484Sbrian    lcp_SendIdentification(&fp->link->lcp);
2246059Samurai}
2256059Samurai
22632658Sbrianstatic void
22732658SbrianFsmOpenNow(void *v)
22832658Sbrian{
22932658Sbrian  struct fsm *fp = (struct fsm *)v;
23032658Sbrian
23136285Sbrian  timer_Stop(&fp->OpenTimer);
23232658Sbrian  if (fp->state <= ST_STOPPED) {
23337210Sbrian    if (fp->state != ST_STARTING) {
23437210Sbrian      /*
23537210Sbrian       * In practice, we're only here in ST_STOPPED (when delaying the
23637210Sbrian       * first config request) or ST_CLOSED (when openmode == 0).
23737210Sbrian       *
23837210Sbrian       * The ST_STOPPED bit is breaking the RFC already :-(
23937210Sbrian       *
24037210Sbrian       * According to the RFC (1661) state transition table, a TLS isn't
24137210Sbrian       * required for an Open event when state == Closed, but the RFC
24237210Sbrian       * must be wrong as TLS hasn't yet been called (since the last TLF)
24337210Sbrian       * ie, Initial gets an `Up' event, Closing gets a RTA etc.
24437210Sbrian       */
24537210Sbrian      (*fp->fn->LayerStart)(fp);
24637210Sbrian      (*fp->parent->LayerStart)(fp->parent->object, fp);
24737210Sbrian    }
24844305Sbrian    FsmInitRestartCounter(fp, FSM_REQ_TIMER);
24932658Sbrian    FsmSendConfigReq(fp);
25032658Sbrian    NewState(fp, ST_REQSENT);
25132658Sbrian  }
25232658Sbrian}
25332658Sbrian
2546059Samuraivoid
25546828Sbrianfsm_Open(struct fsm *fp)
2566059Samurai{
2576059Samurai  switch (fp->state) {
25836285Sbrian  case ST_INITIAL:
2596059Samurai    NewState(fp, ST_STARTING);
26036285Sbrian    (*fp->fn->LayerStart)(fp);
26136285Sbrian    (*fp->parent->LayerStart)(fp->parent->object, fp);
2626059Samurai    break;
2636059Samurai  case ST_CLOSED:
2646059Samurai    if (fp->open_mode == OPEN_PASSIVE) {
26537210Sbrian      NewState(fp, ST_STOPPED);		/* XXX: This is a hack ! */
26632658Sbrian    } else if (fp->open_mode > 0) {
26732658Sbrian      if (fp->open_mode > 1)
26836285Sbrian        log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n",
26936285Sbrian                  fp->link->name, fp->open_mode);
27037210Sbrian      NewState(fp, ST_STOPPED);		/* XXX: This is a not-so-bad hack ! */
27136285Sbrian      timer_Stop(&fp->OpenTimer);
27232658Sbrian      fp->OpenTimer.load = fp->open_mode * SECTICKS;
27332658Sbrian      fp->OpenTimer.func = FsmOpenNow;
27432658Sbrian      fp->OpenTimer.arg = (void *)fp;
27536285Sbrian      timer_Start(&fp->OpenTimer);
27632658Sbrian    } else
27732658Sbrian      FsmOpenNow(fp);
2786059Samurai    break;
27928679Sbrian  case ST_STOPPED:		/* XXX: restart option */
2806059Samurai  case ST_REQSENT:
2816059Samurai  case ST_ACKRCVD:
2826059Samurai  case ST_ACKSENT:
28328679Sbrian  case ST_OPENED:		/* XXX: restart option */
2846059Samurai    break;
28528679Sbrian  case ST_CLOSING:		/* XXX: restart option */
28628679Sbrian  case ST_STOPPING:		/* XXX: restart option */
2876059Samurai    NewState(fp, ST_STOPPING);
2886059Samurai    break;
2896059Samurai  }
2906059Samurai}
2916059Samurai
2926059Samuraivoid
29346828Sbrianfsm_Up(struct fsm *fp)
2946059Samurai{
2956059Samurai  switch (fp->state) {
29637210Sbrian  case ST_INITIAL:
29736285Sbrian    log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n",
29836285Sbrian              fp->link->name);
2996059Samurai    NewState(fp, ST_CLOSED);
3006059Samurai    break;
3016059Samurai  case ST_STARTING:
30244305Sbrian    FsmInitRestartCounter(fp, FSM_REQ_TIMER);
3036059Samurai    FsmSendConfigReq(fp);
3046059Samurai    NewState(fp, ST_REQSENT);
3056059Samurai    break;
3066059Samurai  default:
30736285Sbrian    log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n",
30836285Sbrian              fp->link->name, State2Nam(fp->state));
3096059Samurai    break;
3106059Samurai  }
3116059Samurai}
3126059Samurai
3136059Samuraivoid
31436285Sbrianfsm_Down(struct fsm *fp)
3156059Samurai{
3166059Samurai  switch (fp->state) {
31736285Sbrian  case ST_CLOSED:
3186059Samurai    NewState(fp, ST_INITIAL);
3196059Samurai    break;
32036285Sbrian  case ST_CLOSING:
32144359Sbrian    /* This TLF contradicts the RFC (1661), which ``misses it out'' ! */
32236285Sbrian    (*fp->fn->LayerFinish)(fp);
32336285Sbrian    NewState(fp, ST_INITIAL);
32436285Sbrian    (*fp->parent->LayerFinish)(fp->parent->object, fp);
32536285Sbrian    break;
3266059Samurai  case ST_STOPPED:
32736285Sbrian    NewState(fp, ST_STARTING);
32836285Sbrian    (*fp->fn->LayerStart)(fp);
32936285Sbrian    (*fp->parent->LayerStart)(fp->parent->object, fp);
33036285Sbrian    break;
3316059Samurai  case ST_STOPPING:
3326059Samurai  case ST_REQSENT:
3336059Samurai  case ST_ACKRCVD:
3346059Samurai  case ST_ACKSENT:
3356059Samurai    NewState(fp, ST_STARTING);
3366059Samurai    break;
3376059Samurai  case ST_OPENED:
33836285Sbrian    (*fp->fn->LayerDown)(fp);
3396059Samurai    NewState(fp, ST_STARTING);
34036285Sbrian    (*fp->parent->LayerDown)(fp->parent->object, fp);
3416059Samurai    break;
3426059Samurai  }
3436059Samurai}
3446059Samurai
3456059Samuraivoid
34636285Sbrianfsm_Close(struct fsm *fp)
3476059Samurai{
3486059Samurai  switch (fp->state) {
34936285Sbrian  case ST_STARTING:
35036285Sbrian    (*fp->fn->LayerFinish)(fp);
3516059Samurai    NewState(fp, ST_INITIAL);
35236285Sbrian    (*fp->parent->LayerFinish)(fp->parent->object, fp);
3536059Samurai    break;
3546059Samurai  case ST_STOPPED:
3556059Samurai    NewState(fp, ST_CLOSED);
3566059Samurai    break;
3576059Samurai  case ST_STOPPING:
3586059Samurai    NewState(fp, ST_CLOSING);
3596059Samurai    break;
3606059Samurai  case ST_OPENED:
36136285Sbrian    (*fp->fn->LayerDown)(fp);
36271658Sbrian    if (fp->state == ST_OPENED) {
36371658Sbrian      FsmInitRestartCounter(fp, FSM_TRM_TIMER);
36471658Sbrian      FsmSendTerminateReq(fp);
36571658Sbrian      NewState(fp, ST_CLOSING);
36671658Sbrian      (*fp->parent->LayerDown)(fp->parent->object, fp);
36771658Sbrian    }
36836285Sbrian    break;
3696059Samurai  case ST_REQSENT:
3706059Samurai  case ST_ACKRCVD:
3716059Samurai  case ST_ACKSENT:
37244305Sbrian    FsmInitRestartCounter(fp, FSM_TRM_TIMER);
3736059Samurai    FsmSendTerminateReq(fp);
3746059Samurai    NewState(fp, ST_CLOSING);
3756059Samurai    break;
3766059Samurai  }
3776059Samurai}
3786059Samurai
3796059Samurai/*
3806059Samurai *	Send functions
3816059Samurai */
38230715Sbrianstatic void
38346828SbrianFsmSendConfigReq(struct fsm *fp)
3846059Samurai{
38544305Sbrian  if (fp->more.reqs-- > 0 && fp->restart-- > 0) {
38636285Sbrian    (*fp->fn->SendConfigReq)(fp);
38744305Sbrian    timer_Start(&fp->FsmTimer);		/* Start restart timer */
3886059Samurai  } else {
38944305Sbrian    if (fp->more.reqs < 0)
39044305Sbrian      log_Printf(LogPHASE, "%s: Too many %s REQs sent - abandoning "
39144305Sbrian                 "negotiation\n", fp->link->name, fp->name);
39263484Sbrian    lcp_SendIdentification(&fp->link->lcp);
39336285Sbrian    fsm_Close(fp);
3946059Samurai  }
3956059Samurai}
3966059Samurai
39730715Sbrianstatic void
39836285SbrianFsmSendTerminateReq(struct fsm *fp)
3996059Samurai{
40047695Sbrian  fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0, MB_UNKNOWN);
40136285Sbrian  (*fp->fn->SentTerminateReq)(fp);
40236285Sbrian  timer_Start(&fp->FsmTimer);	/* Start restart timer */
4036059Samurai  fp->restart--;		/* Decrement restart counter */
4046059Samurai}
4056059Samurai
4066059Samurai/*
4076059Samurai *	Timeout actions
4086059Samurai */
40930715Sbrianstatic void
41031343SbrianFsmTimeout(void *v)
4116059Samurai{
41231343Sbrian  struct fsm *fp = (struct fsm *)v;
41331343Sbrian
4146059Samurai  if (fp->restart) {
4156059Samurai    switch (fp->state) {
41636285Sbrian    case ST_CLOSING:
41736285Sbrian    case ST_STOPPING:
4186059Samurai      FsmSendTerminateReq(fp);
4196059Samurai      break;
4206059Samurai    case ST_REQSENT:
4216059Samurai    case ST_ACKSENT:
4226059Samurai      FsmSendConfigReq(fp);
4236059Samurai      break;
4246059Samurai    case ST_ACKRCVD:
4256059Samurai      FsmSendConfigReq(fp);
4266059Samurai      NewState(fp, ST_REQSENT);
4276059Samurai      break;
4286059Samurai    }
42936285Sbrian    timer_Start(&fp->FsmTimer);
4306059Samurai  } else {
4316059Samurai    switch (fp->state) {
4326059Samurai    case ST_CLOSING:
43336285Sbrian      (*fp->fn->LayerFinish)(fp);
4346059Samurai      NewState(fp, ST_CLOSED);
43536285Sbrian      (*fp->parent->LayerFinish)(fp->parent->object, fp);
4366059Samurai      break;
4376059Samurai    case ST_STOPPING:
43836285Sbrian      (*fp->fn->LayerFinish)(fp);
4396059Samurai      NewState(fp, ST_STOPPED);
44036285Sbrian      (*fp->parent->LayerFinish)(fp->parent->object, fp);
4416059Samurai      break;
4426059Samurai    case ST_REQSENT:		/* XXX: 3p */
4436059Samurai    case ST_ACKSENT:
4446059Samurai    case ST_ACKRCVD:
44536285Sbrian      (*fp->fn->LayerFinish)(fp);
4466059Samurai      NewState(fp, ST_STOPPED);
44736285Sbrian      (*fp->parent->LayerFinish)(fp->parent->object, fp);
4486059Samurai      break;
4496059Samurai    }
4506059Samurai  }
4516059Samurai}
4526059Samurai
45330715Sbrianstatic void
45444305SbrianFsmInitRestartCounter(struct fsm *fp, int what)
4556059Samurai{
45636285Sbrian  timer_Stop(&fp->FsmTimer);
4576059Samurai  fp->FsmTimer.func = FsmTimeout;
45844305Sbrian  fp->FsmTimer.arg = (void *)fp;
45944305Sbrian  (*fp->fn->InitRestartCounter)(fp, what);
4606059Samurai}
4616059Samurai
4626059Samurai/*
46346828Sbrian * Actions when receive packets
4646059Samurai */
46530715Sbrianstatic void
46636285SbrianFsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
46728679Sbrian/* RCR */
4686059Samurai{
46936285Sbrian  struct fsm_decode dec;
4706735Samurai  int plen, flen;
4716059Samurai  int ackaction = 0;
47294894Sbrian  u_char *cp;
4738857Srgrimes
47494894Sbrian  bp = m_pullup(bp);
47554912Sbrian  plen = m_length(bp);
47631962Sbrian  flen = ntohs(lhp->length) - sizeof *lhp;
4776735Samurai  if (plen < flen) {
47837019Sbrian    log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n",
47994894Sbrian               fp->link->name, plen, flen);
48054912Sbrian    m_freem(bp);
4816059Samurai    return;
4826059Samurai  }
4836059Samurai
48495872Sbrian  /* Some things must be done before we Decode the packet */
48595872Sbrian  switch (fp->state) {
48695872Sbrian  case ST_OPENED:
48795872Sbrian    (*fp->fn->LayerDown)(fp);
48895872Sbrian  }
48995872Sbrian
49094894Sbrian  dec.ackend = dec.ack;
49194894Sbrian  dec.nakend = dec.nak;
49294894Sbrian  dec.rejend = dec.rej;
49394894Sbrian  cp = MBUF_CTOP(bp);
49494894Sbrian  (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_REQ, &dec);
495134789Sbrian  if (flen < (int)sizeof(struct fsm_opt_hdr))
49694894Sbrian    log_Printf(fp->LogLevel, "  [EMPTY]\n");
49794894Sbrian
49894894Sbrian  if (dec.nakend == dec.nak && dec.rejend == dec.rej)
49994894Sbrian    ackaction = 1;
50094894Sbrian
50146828Sbrian  /* Check and process easy case */
5026059Samurai  switch (fp->state) {
5036059Samurai  case ST_INITIAL:
50437320Sbrian    if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) {
50537320Sbrian      /*
50637320Sbrian       * ccp_SetOpenMode() leaves us in initial if we're disabling
50746686Sbrian       * & denying everything.
50837320Sbrian       */
50954912Sbrian      bp = m_prepend(bp, lhp, sizeof *lhp, 2);
51046686Sbrian      bp = proto_Prepend(bp, fp->proto, 0, 0);
51154912Sbrian      bp = m_pullup(bp);
51254912Sbrian      lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->m_len);
51354912Sbrian      m_freem(bp);
51437320Sbrian      return;
51537320Sbrian    }
51637320Sbrian    /* Drop through */
5176059Samurai  case ST_STARTING:
51836285Sbrian    log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n",
51936285Sbrian              fp->link->name, State2Nam(fp->state));
52054912Sbrian    m_freem(bp);
5216059Samurai    return;
5226059Samurai  case ST_CLOSED:
52336285Sbrian    (*fp->fn->SendTerminateAck)(fp, lhp->id);
52454912Sbrian    m_freem(bp);
5256059Samurai    return;
5266059Samurai  case ST_CLOSING:
52736285Sbrian    log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n",
52836285Sbrian              fp->link->name, State2Nam(fp->state));
5296059Samurai  case ST_STOPPING:
53054912Sbrian    m_freem(bp);
5316059Samurai    return;
5326059Samurai  case ST_STOPPED:
53344305Sbrian    FsmInitRestartCounter(fp, FSM_REQ_TIMER);
53495872Sbrian    /* Drop through */
53537995Sbrian  case ST_OPENED:
5366059Samurai    FsmSendConfigReq(fp);
5376059Samurai    break;
5386059Samurai  }
5396059Samurai
54036285Sbrian  if (dec.rejend != dec.rej)
54147695Sbrian    fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej,
54247695Sbrian               MB_UNKNOWN);
54336285Sbrian  if (dec.nakend != dec.nak)
54447695Sbrian    fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak,
54547695Sbrian               MB_UNKNOWN);
5466059Samurai  if (ackaction)
54747695Sbrian    fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack,
54847695Sbrian               MB_UNKNOWN);
5496059Samurai
5506059Samurai  switch (fp->state) {
55144305Sbrian  case ST_STOPPED:
55244305Sbrian      /*
55344305Sbrian       * According to the RFC (1661) state transition table, a TLS isn't
55444305Sbrian       * required for a RCR when state == ST_STOPPED, but the RFC
55544305Sbrian       * must be wrong as TLS hasn't yet been called (since the last TLF)
55644305Sbrian       */
55744305Sbrian    (*fp->fn->LayerStart)(fp);
55844305Sbrian    (*fp->parent->LayerStart)(fp->parent->object, fp);
559102413Scharnier    /* FALLTHROUGH */
56044305Sbrian
56136285Sbrian  case ST_OPENED:
5626059Samurai    if (ackaction)
5636059Samurai      NewState(fp, ST_ACKSENT);
5646059Samurai    else
5656059Samurai      NewState(fp, ST_REQSENT);
56681634Sbrian    (*fp->parent->LayerDown)(fp->parent->object, fp);
5676059Samurai    break;
5686059Samurai  case ST_REQSENT:
5696059Samurai    if (ackaction)
5706059Samurai      NewState(fp, ST_ACKSENT);
5716059Samurai    break;
5726059Samurai  case ST_ACKRCVD:
5736059Samurai    if (ackaction) {
5746059Samurai      NewState(fp, ST_OPENED);
57536285Sbrian      if ((*fp->fn->LayerUp)(fp))
57636285Sbrian        (*fp->parent->LayerUp)(fp->parent->object, fp);
57736285Sbrian      else {
57836285Sbrian        (*fp->fn->LayerDown)(fp);
57944305Sbrian        FsmInitRestartCounter(fp, FSM_TRM_TIMER);
58036285Sbrian        FsmSendTerminateReq(fp);
58136285Sbrian        NewState(fp, ST_CLOSING);
58263484Sbrian        lcp_SendIdentification(&fp->link->lcp);
58336285Sbrian      }
5846059Samurai    }
5856059Samurai    break;
5866059Samurai  case ST_ACKSENT:
5876059Samurai    if (!ackaction)
5886059Samurai      NewState(fp, ST_REQSENT);
5896059Samurai    break;
5906059Samurai  }
59154912Sbrian  m_freem(bp);
59244305Sbrian
59344305Sbrian  if (dec.rejend != dec.rej && --fp->more.rejs <= 0) {
59444305Sbrian    log_Printf(LogPHASE, "%s: Too many %s REJs sent - abandoning negotiation\n",
59544305Sbrian               fp->link->name, fp->name);
59663484Sbrian    lcp_SendIdentification(&fp->link->lcp);
59744305Sbrian    fsm_Close(fp);
59844305Sbrian  }
59944305Sbrian
60044305Sbrian  if (dec.nakend != dec.nak && --fp->more.naks <= 0) {
60144305Sbrian    log_Printf(LogPHASE, "%s: Too many %s NAKs sent - abandoning negotiation\n",
60244305Sbrian               fp->link->name, fp->name);
60363484Sbrian    lcp_SendIdentification(&fp->link->lcp);
60444305Sbrian    fsm_Close(fp);
60544305Sbrian  }
6066059Samurai}
6076059Samurai
60830715Sbrianstatic void
60936285SbrianFsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
61028679Sbrian/* RCA */
6116059Samurai{
61294894Sbrian  struct fsm_decode dec;
61394894Sbrian  int plen, flen;
61494894Sbrian  u_char *cp;
61594894Sbrian
61694894Sbrian  plen = m_length(bp);
61794894Sbrian  flen = ntohs(lhp->length) - sizeof *lhp;
61894894Sbrian  if (plen < flen) {
61994894Sbrian    m_freem(bp);
62094894Sbrian    return;
62194894Sbrian  }
62294894Sbrian
62394894Sbrian  bp = m_pullup(bp);
62494894Sbrian  dec.ackend = dec.ack;
62594894Sbrian  dec.nakend = dec.nak;
62694894Sbrian  dec.rejend = dec.rej;
62794894Sbrian  cp = MBUF_CTOP(bp);
62894894Sbrian  (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_ACK, &dec);
629134789Sbrian  if (flen < (int)sizeof(struct fsm_opt_hdr))
63094894Sbrian    log_Printf(fp->LogLevel, "  [EMPTY]\n");
63194894Sbrian
6326059Samurai  switch (fp->state) {
63328679Sbrian    case ST_CLOSED:
63428679Sbrian    case ST_STOPPED:
63536285Sbrian    (*fp->fn->SendTerminateAck)(fp, lhp->id);
6366059Samurai    break;
6376059Samurai  case ST_CLOSING:
6386059Samurai  case ST_STOPPING:
6396059Samurai    break;
6406059Samurai  case ST_REQSENT:
64144305Sbrian    FsmInitRestartCounter(fp, FSM_REQ_TIMER);
6426059Samurai    NewState(fp, ST_ACKRCVD);
6436059Samurai    break;
6446059Samurai  case ST_ACKRCVD:
6456059Samurai    FsmSendConfigReq(fp);
6466059Samurai    NewState(fp, ST_REQSENT);
6476059Samurai    break;
6486059Samurai  case ST_ACKSENT:
64944305Sbrian    FsmInitRestartCounter(fp, FSM_REQ_TIMER);
6506059Samurai    NewState(fp, ST_OPENED);
65136285Sbrian    if ((*fp->fn->LayerUp)(fp))
65236285Sbrian      (*fp->parent->LayerUp)(fp->parent->object, fp);
65336285Sbrian    else {
65436285Sbrian      (*fp->fn->LayerDown)(fp);
65544305Sbrian      FsmInitRestartCounter(fp, FSM_TRM_TIMER);
65636285Sbrian      FsmSendTerminateReq(fp);
65736285Sbrian      NewState(fp, ST_CLOSING);
65863484Sbrian      lcp_SendIdentification(&fp->link->lcp);
65936285Sbrian    }
6606059Samurai    break;
6616059Samurai  case ST_OPENED:
66236285Sbrian    (*fp->fn->LayerDown)(fp);
6636059Samurai    FsmSendConfigReq(fp);
6646059Samurai    NewState(fp, ST_REQSENT);
66536285Sbrian    (*fp->parent->LayerDown)(fp->parent->object, fp);
6666059Samurai    break;
6676059Samurai  }
66854912Sbrian  m_freem(bp);
6696059Samurai}
6706059Samurai
67130715Sbrianstatic void
67236285SbrianFsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
67328679Sbrian/* RCN */
6746059Samurai{
67536285Sbrian  struct fsm_decode dec;
6766735Samurai  int plen, flen;
67794894Sbrian  u_char *cp;
6788857Srgrimes
67954912Sbrian  plen = m_length(bp);
68031962Sbrian  flen = ntohs(lhp->length) - sizeof *lhp;
6816735Samurai  if (plen < flen) {
68254912Sbrian    m_freem(bp);
6836059Samurai    return;
6846059Samurai  }
6856059Samurai
6866059Samurai  /*
68728679Sbrian   * Check and process easy case
6886059Samurai   */
6896059Samurai  switch (fp->state) {
6906059Samurai  case ST_INITIAL:
6916059Samurai  case ST_STARTING:
69236285Sbrian    log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n",
69336285Sbrian              fp->link->name, State2Nam(fp->state));
69454912Sbrian    m_freem(bp);
6956059Samurai    return;
6966059Samurai  case ST_CLOSED:
6976059Samurai  case ST_STOPPED:
69836285Sbrian    (*fp->fn->SendTerminateAck)(fp, lhp->id);
69954912Sbrian    m_freem(bp);
7006059Samurai    return;
7016059Samurai  case ST_CLOSING:
7026059Samurai  case ST_STOPPING:
70354912Sbrian    m_freem(bp);
7046059Samurai    return;
7056059Samurai  }
7066059Samurai
70754912Sbrian  bp = m_pullup(bp);
70836285Sbrian  dec.ackend = dec.ack;
70936285Sbrian  dec.nakend = dec.nak;
71036285Sbrian  dec.rejend = dec.rej;
71194894Sbrian  cp = MBUF_CTOP(bp);
71294894Sbrian  (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_NAK, &dec);
713134789Sbrian  if (flen < (int)sizeof(struct fsm_opt_hdr))
71436285Sbrian    log_Printf(fp->LogLevel, "  [EMPTY]\n");
7156059Samurai
7166059Samurai  switch (fp->state) {
7176059Samurai  case ST_REQSENT:
7186059Samurai  case ST_ACKSENT:
71944305Sbrian    FsmInitRestartCounter(fp, FSM_REQ_TIMER);
7206059Samurai    FsmSendConfigReq(fp);
7216059Samurai    break;
7226059Samurai  case ST_OPENED:
72336285Sbrian    (*fp->fn->LayerDown)(fp);
72436285Sbrian    FsmSendConfigReq(fp);
72536285Sbrian    NewState(fp, ST_REQSENT);
72636285Sbrian    (*fp->parent->LayerDown)(fp->parent->object, fp);
72736285Sbrian    break;
7286059Samurai  case ST_ACKRCVD:
7296059Samurai    FsmSendConfigReq(fp);
7306059Samurai    NewState(fp, ST_REQSENT);
7316059Samurai    break;
7326059Samurai  }
7336059Samurai
73454912Sbrian  m_freem(bp);
7356059Samurai}
7366059Samurai
73730715Sbrianstatic void
73836285SbrianFsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
73928679Sbrian/* RTR */
7406059Samurai{
7416059Samurai  switch (fp->state) {
74236285Sbrian  case ST_INITIAL:
74336285Sbrian  case ST_STARTING:
74436285Sbrian    log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n",
74536285Sbrian              fp->link->name, State2Nam(fp->state));
7466059Samurai    break;
7476059Samurai  case ST_CLOSED:
7486059Samurai  case ST_STOPPED:
7496059Samurai  case ST_CLOSING:
7506059Samurai  case ST_STOPPING:
7516059Samurai  case ST_REQSENT:
75236285Sbrian    (*fp->fn->SendTerminateAck)(fp, lhp->id);
7536059Samurai    break;
7546059Samurai  case ST_ACKRCVD:
7556059Samurai  case ST_ACKSENT:
75636285Sbrian    (*fp->fn->SendTerminateAck)(fp, lhp->id);
7576059Samurai    NewState(fp, ST_REQSENT);
7586059Samurai    break;
7596059Samurai  case ST_OPENED:
76036285Sbrian    (*fp->fn->LayerDown)(fp);
76136285Sbrian    (*fp->fn->SendTerminateAck)(fp, lhp->id);
76244305Sbrian    FsmInitRestartCounter(fp, FSM_TRM_TIMER);
76344305Sbrian    timer_Start(&fp->FsmTimer);			/* Start restart timer */
76426353Sbrian    fp->restart = 0;
76526353Sbrian    NewState(fp, ST_STOPPING);
76636285Sbrian    (*fp->parent->LayerDown)(fp->parent->object, fp);
76744305Sbrian    /* A delayed ST_STOPPED is now scheduled */
7686059Samurai    break;
7696059Samurai  }
77054912Sbrian  m_freem(bp);
7716059Samurai}
7726059Samurai
77330715Sbrianstatic void
774134789SbrianFsmRecvTermAck(struct fsm *fp, struct fsmheader *lhp __unused, struct mbuf *bp)
77528679Sbrian/* RTA */
7766059Samurai{
7776059Samurai  switch (fp->state) {
77836285Sbrian  case ST_CLOSING:
77936285Sbrian    (*fp->fn->LayerFinish)(fp);
7806059Samurai    NewState(fp, ST_CLOSED);
78136285Sbrian    (*fp->parent->LayerFinish)(fp->parent->object, fp);
7826059Samurai    break;
7836059Samurai  case ST_STOPPING:
78436285Sbrian    (*fp->fn->LayerFinish)(fp);
7856059Samurai    NewState(fp, ST_STOPPED);
78636285Sbrian    (*fp->parent->LayerFinish)(fp->parent->object, fp);
7876059Samurai    break;
7886059Samurai  case ST_ACKRCVD:
7896059Samurai    NewState(fp, ST_REQSENT);
7906059Samurai    break;
7916059Samurai  case ST_OPENED:
79236285Sbrian    (*fp->fn->LayerDown)(fp);
7936059Samurai    FsmSendConfigReq(fp);
7946059Samurai    NewState(fp, ST_REQSENT);
79536285Sbrian    (*fp->parent->LayerDown)(fp->parent->object, fp);
7966059Samurai    break;
7976059Samurai  }
79854912Sbrian  m_freem(bp);
7996059Samurai}
8006059Samurai
80130715Sbrianstatic void
80236285SbrianFsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
80328679Sbrian/* RCJ */
8046059Samurai{
80536285Sbrian  struct fsm_decode dec;
806134789Sbrian  size_t plen;
807134789Sbrian  int flen;
80894894Sbrian  u_char *cp;
8098857Srgrimes
81054912Sbrian  plen = m_length(bp);
81131962Sbrian  flen = ntohs(lhp->length) - sizeof *lhp;
812134789Sbrian  if ((int)plen < flen) {
81354912Sbrian    m_freem(bp);
8146059Samurai    return;
8156059Samurai  }
8166059Samurai
81763484Sbrian  lcp_SendIdentification(&fp->link->lcp);
81863484Sbrian
8196059Samurai  /*
82028679Sbrian   * Check and process easy case
8216059Samurai   */
8226059Samurai  switch (fp->state) {
8236059Samurai  case ST_INITIAL:
8246059Samurai  case ST_STARTING:
82536285Sbrian    log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n",
82636285Sbrian              fp->link->name, State2Nam(fp->state));
82754912Sbrian    m_freem(bp);
8286059Samurai    return;
8296059Samurai  case ST_CLOSED:
8306059Samurai  case ST_STOPPED:
83136285Sbrian    (*fp->fn->SendTerminateAck)(fp, lhp->id);
83254912Sbrian    m_freem(bp);
8336059Samurai    return;
8346059Samurai  case ST_CLOSING:
8356059Samurai  case ST_STOPPING:
83654912Sbrian    m_freem(bp);
8376059Samurai    return;
8386059Samurai  }
8396059Samurai
84054912Sbrian  bp = m_pullup(bp);
84136285Sbrian  dec.ackend = dec.ack;
84236285Sbrian  dec.nakend = dec.nak;
84336285Sbrian  dec.rejend = dec.rej;
84494894Sbrian  cp = MBUF_CTOP(bp);
84594894Sbrian  (*fp->fn->DecodeConfig)(fp, cp, cp + flen, MODE_REJ, &dec);
846134789Sbrian  if (flen < (int)sizeof(struct fsm_opt_hdr))
84736285Sbrian    log_Printf(fp->LogLevel, "  [EMPTY]\n");
8486059Samurai
8496059Samurai  switch (fp->state) {
8506059Samurai  case ST_REQSENT:
8516059Samurai  case ST_ACKSENT:
85244305Sbrian    FsmInitRestartCounter(fp, FSM_REQ_TIMER);
8536059Samurai    FsmSendConfigReq(fp);
8546059Samurai    break;
8556059Samurai  case ST_OPENED:
85636285Sbrian    (*fp->fn->LayerDown)(fp);
85736285Sbrian    FsmSendConfigReq(fp);
85836285Sbrian    NewState(fp, ST_REQSENT);
85936285Sbrian    (*fp->parent->LayerDown)(fp->parent->object, fp);
86036285Sbrian    break;
8616059Samurai  case ST_ACKRCVD:
8626059Samurai    FsmSendConfigReq(fp);
8636059Samurai    NewState(fp, ST_REQSENT);
8646059Samurai    break;
8656059Samurai  }
86654912Sbrian  m_freem(bp);
8676059Samurai}
8686059Samurai
86930715Sbrianstatic void
870134789SbrianFsmRecvCodeRej(struct fsm *fp __unused, struct fsmheader *lhp __unused,
871134789Sbrian	       struct mbuf *bp)
8726059Samurai{
87354912Sbrian  m_freem(bp);
8746059Samurai}
8756059Samurai
87630715Sbrianstatic void
877134789SbrianFsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp __unused, struct mbuf *bp)
8786059Samurai{
87936285Sbrian  struct physical *p = link2physical(fp->link);
88046828Sbrian  u_short proto;
8816059Samurai
88254912Sbrian  if (m_length(bp) < 2) {
88354912Sbrian    m_freem(bp);
88446828Sbrian    return;
88546828Sbrian  }
88646828Sbrian  bp = mbuf_Read(bp, &proto, 2);
88746828Sbrian  proto = ntohs(proto);
88836285Sbrian  log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n",
88936285Sbrian            fp->link->name, proto, hdlc_Protocol2Nam(proto));
8906059Samurai
8916059Samurai  switch (proto) {
8926059Samurai  case PROTO_LQR:
89336285Sbrian    if (p)
89436285Sbrian      lqr_Stop(p, LQM_LQR);
89536285Sbrian    else
89636285Sbrian      log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n",
89736285Sbrian                fp->link->name);
8986059Samurai    break;
8996059Samurai  case PROTO_CCP:
90036285Sbrian    if (fp->proto == PROTO_LCP) {
90136285Sbrian      fp = &fp->link->ccp.fsm;
90244359Sbrian      /* Despite the RFC (1661), don't do an out-of-place TLF */
90344359Sbrian      /* (*fp->fn->LayerFinish)(fp); */
90436285Sbrian      switch (fp->state) {
90536285Sbrian      case ST_CLOSED:
90636285Sbrian      case ST_CLOSING:
90736285Sbrian        NewState(fp, ST_CLOSED);
90893420Sbrian        break;
90936285Sbrian      default:
91036285Sbrian        NewState(fp, ST_STOPPED);
91136285Sbrian        break;
91236285Sbrian      }
91344359Sbrian      /* See above */
91444359Sbrian      /* (*fp->parent->LayerFinish)(fp->parent->object, fp); */
9156059Samurai    }
9166059Samurai    break;
91749599Sbrian  case PROTO_IPCP:
91849599Sbrian    if (fp->proto == PROTO_LCP) {
91949599Sbrian      log_Printf(LogPHASE, "%s: IPCP protocol reject closes IPCP !\n",
92049599Sbrian                fp->link->name);
92149599Sbrian      fsm_Close(&fp->bundle->ncp.ipcp.fsm);
92249599Sbrian    }
92349599Sbrian    break;
92481634Sbrian#ifndef NOINET6
92581634Sbrian  case PROTO_IPV6CP:
92681897Sbrian    if (fp->proto == PROTO_LCP) {
92781634Sbrian      log_Printf(LogPHASE, "%s: IPV6CP protocol reject closes IPV6CP !\n",
92881634Sbrian                fp->link->name);
92981634Sbrian      fsm_Close(&fp->bundle->ncp.ipv6cp.fsm);
93081634Sbrian    }
93181634Sbrian    break;
93281634Sbrian#endif
93336285Sbrian  case PROTO_MP:
93436285Sbrian    if (fp->proto == PROTO_LCP) {
93536285Sbrian      struct lcp *lcp = fsm2lcp(fp);
93636285Sbrian
93736285Sbrian      if (lcp->want_mrru && lcp->his_mrru) {
93836285Sbrian        log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n",
93936285Sbrian                  fp->link->name);
94036285Sbrian        fsm_Close(fp);
94136285Sbrian      }
94236285Sbrian    }
94336285Sbrian    break;
9446059Samurai  }
94554912Sbrian  m_freem(bp);
9466059Samurai}
9476059Samurai
94830715Sbrianstatic void
94936285SbrianFsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
9506059Samurai{
95136285Sbrian  struct lcp *lcp = fsm2lcp(fp);
9526059Samurai  u_char *cp;
95336285Sbrian  u_int32_t magic;
9546059Samurai
95554912Sbrian  bp = m_pullup(bp);
95654912Sbrian  m_settype(bp, MB_ECHOIN);
95752942Sbrian
95852942Sbrian  if (lcp && ntohs(lhp->length) - sizeof *lhp >= 4) {
95936285Sbrian    cp = MBUF_CTOP(bp);
96038814Sbrian    ua_ntohl(cp, &magic);
96136285Sbrian    if (magic != lcp->his_magic) {
96251970Sbrian      log_Printf(fp->LogLevel, "%s: RecvEchoReq: magic 0x%08lx is wrong,"
96351970Sbrian                 " expecting 0x%08lx\n", fp->link->name, (u_long)magic,
96451970Sbrian                 (u_long)lcp->his_magic);
96536285Sbrian      /* XXX: We should send terminate request */
96636285Sbrian    }
96736285Sbrian    if (fp->state == ST_OPENED) {
96838814Sbrian      ua_htonl(&lcp->want_magic, cp);		/* local magic */
96952942Sbrian      fsm_Output(fp, CODE_ECHOREP, lhp->id, cp,
97052942Sbrian                 ntohs(lhp->length) - sizeof *lhp, MB_ECHOOUT);
97136285Sbrian    }
9726059Samurai  }
97354912Sbrian  m_freem(bp);
9746059Samurai}
9756059Samurai
97630715Sbrianstatic void
977134789SbrianFsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp __unused, struct mbuf *bp)
9786059Samurai{
97947169Sbrian  if (fsm2lcp(fp))
98047169Sbrian    bp = lqr_RecvEcho(fp, bp);
9816059Samurai
98254912Sbrian  m_freem(bp);
9836059Samurai}
9846059Samurai
98530715Sbrianstatic void
986134789SbrianFsmRecvDiscReq(struct fsm *fp __unused, struct fsmheader *lhp __unused,
987134789Sbrian	       struct mbuf *bp)
9886059Samurai{
98954912Sbrian  m_freem(bp);
9906059Samurai}
9916059Samurai
99230715Sbrianstatic void
99346828SbrianFsmRecvIdent(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
9946059Samurai{
99563484Sbrian  u_int32_t magic;
99663484Sbrian  u_short len;
99763484Sbrian  u_char *cp;
99863484Sbrian
99963484Sbrian  len = ntohs(lhp->length) - sizeof *lhp;
100063484Sbrian  if (len >= 4) {
100163484Sbrian    bp = m_pullup(m_append(bp, "", 1));
100263484Sbrian    cp = MBUF_CTOP(bp);
100363484Sbrian    ua_ntohl(cp, &magic);
100463484Sbrian    if (magic != fp->link->lcp.his_magic)
100563484Sbrian      log_Printf(fp->LogLevel, "%s: RecvIdent: magic 0x%08lx is wrong,"
100663484Sbrian                 " expecting 0x%08lx\n", fp->link->name, (u_long)magic,
100763484Sbrian                 (u_long)fp->link->lcp.his_magic);
100863484Sbrian    cp[len] = '\0';
100963484Sbrian    lcp_RecvIdentification(&fp->link->lcp, cp + 4);
101063484Sbrian  }
101154912Sbrian  m_freem(bp);
10126059Samurai}
10136059Samurai
101430715Sbrianstatic void
1015134789SbrianFsmRecvTimeRemain(struct fsm *fp __unused, struct fsmheader *lhp __unused,
1016134789Sbrian		  struct mbuf *bp)
10176059Samurai{
101854912Sbrian  m_freem(bp);
10196059Samurai}
10206059Samurai
102130715Sbrianstatic void
102236285SbrianFsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
10236059Samurai{
102478411Sbrian  if ((*fp->fn->RecvResetReq)(fp)) {
102578411Sbrian    /*
102678411Sbrian     * All sendable compressed packets are queued in the first (lowest
102778411Sbrian     * priority) modem output queue.... dump 'em to the priority queue
102878411Sbrian     * so that they arrive at the peer before our ResetAck.
102978411Sbrian     */
103078411Sbrian    link_SequenceQueue(fp->link);
103178411Sbrian    fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0, MB_CCPOUT);
103278411Sbrian  }
103354912Sbrian  m_freem(bp);
10346059Samurai}
10356059Samurai
103630715Sbrianstatic void
103736285SbrianFsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
10386059Samurai{
103936285Sbrian  (*fp->fn->RecvResetAck)(fp, lhp->id);
104054912Sbrian  m_freem(bp);
10416059Samurai}
10426059Samurai
10436059Samuraivoid
104436285Sbrianfsm_Input(struct fsm *fp, struct mbuf *bp)
10456059Samurai{
1046134789Sbrian  size_t len;
104746686Sbrian  struct fsmheader lh;
104831514Sbrian  const struct fsmcodedesc *codep;
10496059Samurai
105054912Sbrian  len = m_length(bp);
10516059Samurai  if (len < sizeof(struct fsmheader)) {
105254912Sbrian    m_freem(bp);
10536059Samurai    return;
10546059Samurai  }
105546686Sbrian  bp = mbuf_Read(bp, &lh, sizeof lh);
105652942Sbrian
105763484Sbrian  if (ntohs(lh.length) > len) {
1058134833Smarcel    log_Printf(LogWARN, "%s: Oops: Got %zu bytes but %d byte payload "
105963484Sbrian               "- dropped\n", fp->link->name, len, (int)ntohs(lh.length));
106063484Sbrian    m_freem(bp);
106163484Sbrian    return;
106260957Sbrian  }
106352942Sbrian
106446686Sbrian  if (lh.code < fp->min_code || lh.code > fp->max_code ||
106546686Sbrian      lh.code > sizeof FsmCodes / sizeof *FsmCodes) {
106636285Sbrian    /*
106736285Sbrian     * Use a private id.  This is really a response-type packet, but we
106836285Sbrian     * MUST send a unique id for each REQ....
106936285Sbrian     */
107036285Sbrian    static u_char id;
107137010Sbrian
107254912Sbrian    bp = m_prepend(bp, &lh, sizeof lh, 0);
107354912Sbrian    bp = m_pullup(bp);
107454912Sbrian    fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->m_len, MB_UNKNOWN);
107554912Sbrian    m_freem(bp);
10766059Samurai    return;
10776059Samurai  }
10786059Samurai
107946686Sbrian  codep = FsmCodes + lh.code - 1;
108046686Sbrian  if (lh.id != fp->reqid && codep->check_reqid &&
108136285Sbrian      Enabled(fp->bundle, OPT_IDCHECK)) {
108236285Sbrian    log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n",
108394894Sbrian               fp->link->name, codep->name, lh.id, fp->reqid);
108436285Sbrian    return;
108536285Sbrian  }
108636285Sbrian
108736285Sbrian  log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n",
108894894Sbrian             fp->link->name, codep->name, lh.id, State2Nam(fp->state));
108936285Sbrian
109046686Sbrian  if (codep->inc_reqid && (lh.id == fp->reqid ||
109136285Sbrian      (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid)))
109236285Sbrian    fp->reqid++;	/* That's the end of that ``exchange''.... */
109336285Sbrian
109446686Sbrian  (*codep->recv)(fp, &lh, bp);
10956059Samurai}
109636285Sbrian
109778411Sbrianint
109836285Sbrianfsm_NullRecvResetReq(struct fsm *fp)
109936285Sbrian{
110036285Sbrian  log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n",
110136285Sbrian            fp->link->name);
110278411Sbrian  return 1;
110336285Sbrian}
110436285Sbrian
110536285Sbrianvoid
1106134789Sbrianfsm_NullRecvResetAck(struct fsm *fp, u_char id __unused)
110736285Sbrian{
110836285Sbrian  log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n",
110936285Sbrian            fp->link->name);
111036285Sbrian}
111137060Sbrian
111237060Sbrianvoid
111337160Sbrianfsm_Reopen(struct fsm *fp)
111437160Sbrian{
111537160Sbrian  if (fp->state == ST_OPENED) {
111637160Sbrian    (*fp->fn->LayerDown)(fp);
111744305Sbrian    FsmInitRestartCounter(fp, FSM_REQ_TIMER);
111837160Sbrian    FsmSendConfigReq(fp);
111937160Sbrian    NewState(fp, ST_REQSENT);
112037160Sbrian    (*fp->parent->LayerDown)(fp->parent->object, fp);
112137160Sbrian  }
112237160Sbrian}
112337160Sbrian
112437160Sbrianvoid
112537060Sbrianfsm2initial(struct fsm *fp)
112637060Sbrian{
112744305Sbrian  timer_Stop(&fp->FsmTimer);
112844305Sbrian  timer_Stop(&fp->OpenTimer);
112944305Sbrian  timer_Stop(&fp->StoppedTimer);
113037060Sbrian  if (fp->state == ST_STOPPED)
113137060Sbrian    fsm_Close(fp);
113237060Sbrian  if (fp->state > ST_INITIAL)
113337060Sbrian    fsm_Down(fp);
113437060Sbrian  if (fp->state > ST_INITIAL)
113537060Sbrian    fsm_Close(fp);
113637060Sbrian}
113794894Sbrian
113894894Sbrianstruct fsm_opt *
113994894Sbrianfsm_readopt(u_char **cp)
114094894Sbrian{
114194894Sbrian  struct fsm_opt *o = (struct fsm_opt *)*cp;
114294894Sbrian
114394894Sbrian  if (o->hdr.len < sizeof(struct fsm_opt_hdr)) {
114494894Sbrian    log_Printf(LogERROR, "Bad option length %d (out of phase?)\n", o->hdr.len);
114594894Sbrian    return NULL;
114694894Sbrian  }
114794894Sbrian
114894894Sbrian  *cp += o->hdr.len;
114994894Sbrian
115094894Sbrian  if (o->hdr.len > sizeof(struct fsm_opt)) {
115198244Sbrian    log_Printf(LogERROR, "Warning: Truncating option length from %d to %d\n",
115298244Sbrian               o->hdr.len, (int)sizeof(struct fsm_opt));
115394894Sbrian    o->hdr.len = sizeof(struct fsm_opt);
115494894Sbrian  }
115594894Sbrian
115694894Sbrian  return o;
115794894Sbrian}
115894894Sbrian
115994894Sbrianstatic int
116094894Sbrianfsm_opt(u_char *opt, int optlen, const struct fsm_opt *o)
116194894Sbrian{
1162134789Sbrian  unsigned cplen = o->hdr.len;
116394894Sbrian
1164134789Sbrian  if (optlen < (int)sizeof(struct fsm_opt_hdr))
116594894Sbrian    optlen = 0;
116694894Sbrian
1167134789Sbrian  if ((int)cplen > optlen) {
116894894Sbrian    log_Printf(LogERROR, "Can't REJ length %d - trunating to %d\n",
116994894Sbrian      cplen, optlen);
117094894Sbrian    cplen = optlen;
117194894Sbrian  }
117294894Sbrian  memcpy(opt, o, cplen);
117394894Sbrian  if (cplen)
117494894Sbrian    opt[1] = cplen;
117594894Sbrian
117694894Sbrian  return cplen;
117794894Sbrian}
117894894Sbrian
117994894Sbrianvoid
118094894Sbrianfsm_rej(struct fsm_decode *dec, const struct fsm_opt *o)
118194894Sbrian{
118294894Sbrian  if (!dec)
118394894Sbrian    return;
118494894Sbrian  dec->rejend += fsm_opt(dec->rejend, FSM_OPTLEN - (dec->rejend - dec->rej), o);
118594894Sbrian}
118694894Sbrian
118794894Sbrianvoid
118894894Sbrianfsm_ack(struct fsm_decode *dec, const struct fsm_opt *o)
118994894Sbrian{
119094894Sbrian  if (!dec)
119194894Sbrian    return;
119294894Sbrian  dec->ackend += fsm_opt(dec->ackend, FSM_OPTLEN - (dec->ackend - dec->ack), o);
119394894Sbrian}
119494894Sbrian
119594894Sbrianvoid
119694894Sbrianfsm_nak(struct fsm_decode *dec, const struct fsm_opt *o)
119794894Sbrian{
119894894Sbrian  if (!dec)
119994894Sbrian    return;
120094894Sbrian  dec->nakend += fsm_opt(dec->nakend, FSM_OPTLEN - (dec->nakend - dec->nak), o);
120194894Sbrian}
120294894Sbrian
120394894Sbrianvoid
120494894Sbrianfsm_opt_normalise(struct fsm_decode *dec)
120594894Sbrian{
120694894Sbrian  if (dec->rejend != dec->rej) {
120794894Sbrian    /* rejects are preferred */
120894894Sbrian    dec->ackend = dec->ack;
120994894Sbrian    dec->nakend = dec->nak;
121094894Sbrian  } else if (dec->nakend != dec->nak)
121194894Sbrian    /* then NAKs */
121294894Sbrian    dec->ackend = dec->ack;
121394894Sbrian}
1214