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: releng/11.0/usr.sbin/ppp/lcp.c 162062 2006-09-06 06:23:55Z brian $
296059Samurai */
3036285Sbrian
3143313Sbrian#include <sys/param.h>
3229043Sbrian#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
3829700Sbrian#include <signal.h>
39102500Sbrian#include <stdarg.h>
4030715Sbrian#include <stdio.h>
4130715Sbrian#include <stdlib.h>
4237210Sbrian#include <string.h>
4330715Sbrian#include <termios.h>
4430715Sbrian#include <unistd.h>
4530715Sbrian
4646686Sbrian#include "layer.h"
4738814Sbrian#include "ua.h"
4837009Sbrian#include "defs.h"
4931343Sbrian#include "command.h"
5030715Sbrian#include "mbuf.h"
5130715Sbrian#include "log.h"
5230715Sbrian#include "timer.h"
536059Samurai#include "fsm.h"
5436285Sbrian#include "iplist.h"
5536285Sbrian#include "throughput.h"
5646686Sbrian#include "proto.h"
5736285Sbrian#include "descriptor.h"
5836285Sbrian#include "lqr.h"
596059Samurai#include "hdlc.h"
6063484Sbrian#include "lcp.h"
6113389Sphk#include "ccp.h"
6236285Sbrian#include "async.h"
6336285Sbrian#include "link.h"
6436285Sbrian#include "physical.h"
6536285Sbrian#include "prompt.h"
6636285Sbrian#include "slcompress.h"
6781634Sbrian#include "ncpaddr.h"
6836285Sbrian#include "ipcp.h"
6936285Sbrian#include "filter.h"
7036285Sbrian#include "mp.h"
7136285Sbrian#include "chat.h"
726735Samurai#include "auth.h"
7330715Sbrian#include "chap.h"
7438174Sbrian#include "cbcp.h"
7536285Sbrian#include "datalink.h"
7643313Sbrian#ifndef NORADIUS
7743313Sbrian#include "radius.h"
7843313Sbrian#endif
7981634Sbrian#include "ipv6cp.h"
8081634Sbrian#include "ncp.h"
8136285Sbrian#include "bundle.h"
826059Samurai
8331514Sbrian/* for received LQRs */
8431514Sbrianstruct lqrreq {
8594894Sbrian  struct fsm_opt_hdr hdr;
8631514Sbrian  u_short proto;		/* Quality protocol */
8737210Sbrian  u_int32_t period;		/* Reporting interval */
8831514Sbrian};
8931514Sbrian
9036285Sbrianstatic int LcpLayerUp(struct fsm *);
9126516Sbrianstatic void LcpLayerDown(struct fsm *);
9226516Sbrianstatic void LcpLayerStart(struct fsm *);
9326516Sbrianstatic void LcpLayerFinish(struct fsm *);
9444305Sbrianstatic void LcpInitRestartCounter(struct fsm *, int);
9536285Sbrianstatic void LcpSendConfigReq(struct fsm *);
9636285Sbrianstatic void LcpSentTerminateReq(struct fsm *);
9736285Sbrianstatic void LcpSendTerminateAck(struct fsm *, u_char);
9894894Sbrianstatic void LcpDecodeConfig(struct fsm *, u_char *, u_char *, int,
9936285Sbrian                            struct fsm_decode *);
1006059Samurai
10136285Sbrianstatic struct fsm_callbacks lcp_Callbacks = {
10236285Sbrian  LcpLayerUp,
10336285Sbrian  LcpLayerDown,
10436285Sbrian  LcpLayerStart,
10536285Sbrian  LcpLayerFinish,
10636285Sbrian  LcpInitRestartCounter,
10736285Sbrian  LcpSendConfigReq,
10836285Sbrian  LcpSentTerminateReq,
10936285Sbrian  LcpSendTerminateAck,
11036285Sbrian  LcpDecodeConfig,
11136285Sbrian  fsm_NullRecvResetReq,
11236285Sbrian  fsm_NullRecvResetAck
11336285Sbrian};
11436285Sbrian
11555146Sbrianstatic const char * const lcp_TimerNames[] =
11636285Sbrian  {"LCP restart", "LCP openmode", "LCP stopped"};
11736285Sbrian
11858034Sbrianstatic const char *
119134789Sbrianprotoname(unsigned proto)
12058034Sbrian{
12158034Sbrian  static const char * const cftypes[] = {
12258034Sbrian    /* Check out the latest ``Assigned numbers'' rfc (1700) */
12358034Sbrian    NULL,
12458034Sbrian    "MRU",		/* 1: Maximum-Receive-Unit */
12558034Sbrian    "ACCMAP",		/* 2: Async-Control-Character-Map */
12658034Sbrian    "AUTHPROTO",	/* 3: Authentication-Protocol */
12758034Sbrian    "QUALPROTO",	/* 4: Quality-Protocol */
12858034Sbrian    "MAGICNUM",		/* 5: Magic-Number */
12958034Sbrian    "RESERVED",		/* 6: RESERVED */
13058034Sbrian    "PROTOCOMP",	/* 7: Protocol-Field-Compression */
13158034Sbrian    "ACFCOMP",		/* 8: Address-and-Control-Field-Compression */
13258034Sbrian    "FCSALT",		/* 9: FCS-Alternatives */
13358034Sbrian    "SDP",		/* 10: Self-Describing-Pad */
13458034Sbrian    "NUMMODE",		/* 11: Numbered-Mode */
13558034Sbrian    "MULTIPROC",	/* 12: Multi-Link-Procedure */
13658034Sbrian    "CALLBACK",		/* 13: Callback */
13758034Sbrian    "CONTIME",		/* 14: Connect-Time */
13858034Sbrian    "COMPFRAME",	/* 15: Compound-Frames */
13958034Sbrian    "NDE",		/* 16: Nominal-Data-Encapsulation */
14058034Sbrian    "MRRU",		/* 17: Multilink-MRRU */
14158034Sbrian    "SHORTSEQ",		/* 18: Multilink-Short-Sequence-Number-Header */
14258034Sbrian    "ENDDISC",		/* 19: Multilink-Endpoint-Discriminator */
14358034Sbrian    "PROPRIETRY",	/* 20: Proprietary */
14458034Sbrian    "DCEID",		/* 21: DCE-Identifier */
14558034Sbrian    "MULTIPP",		/* 22: Multi-Link-Plus-Procedure */
14658034Sbrian    "LDBACP",		/* 23: Link Discriminator for BACP */
14758034Sbrian  };
1486059Samurai
149134789Sbrian  if (proto > sizeof cftypes / sizeof *cftypes || cftypes[proto] == NULL)
15058034Sbrian    return HexStr(proto, NULL, 0);
15131171Sbrian
15258034Sbrian  return cftypes[proto];
15358034Sbrian}
15458034Sbrian
15536285Sbrianint
15636285Sbrianlcp_ReportStatus(struct cmdargs const *arg)
1576059Samurai{
15836285Sbrian  struct link *l;
15936285Sbrian  struct lcp *lcp;
1606059Samurai
16137210Sbrian  l = command_ChooseLink(arg);
16236285Sbrian  lcp = &l->lcp;
1636059Samurai
16436285Sbrian  prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, lcp->fsm.name,
16536285Sbrian                State2Nam(lcp->fsm.state));
16636285Sbrian  prompt_Printf(arg->prompt,
16794894Sbrian                " his side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n"
16894894Sbrian                "           MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n",
16994894Sbrian                lcp->his_mru, (u_long)lcp->his_accmap,
17036285Sbrian                lcp->his_protocomp ? "on" : "off",
17136285Sbrian                lcp->his_acfcomp ? "on" : "off",
17236285Sbrian                (u_long)lcp->his_magic, lcp->his_mrru,
17336285Sbrian                lcp->his_shortseq ? "on" : "off", lcp->his_reject);
17436285Sbrian  prompt_Printf(arg->prompt,
17594894Sbrian                " my  side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n"
17636285Sbrian                "           MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n",
17736285Sbrian                lcp->want_mru, (u_long)lcp->want_accmap,
17836285Sbrian                lcp->want_protocomp ? "on" : "off",
17936285Sbrian                lcp->want_acfcomp ? "on" : "off",
18036285Sbrian                (u_long)lcp->want_magic, lcp->want_mrru,
18136285Sbrian                lcp->want_shortseq ? "on" : "off", lcp->my_reject);
1826059Samurai
18380385Sbrian  if (lcp->cfg.mru)
18480385Sbrian    prompt_Printf(arg->prompt, "\n Defaults: MRU = %d (max %d), ",
18580385Sbrian                  lcp->cfg.mru, lcp->cfg.max_mru);
18680385Sbrian  else
18780385Sbrian    prompt_Printf(arg->prompt, "\n Defaults: MRU = any (max %d), ",
18880385Sbrian                  lcp->cfg.max_mru);
18978410Sbrian  if (lcp->cfg.mtu)
19078410Sbrian    prompt_Printf(arg->prompt, "MTU = %d (max %d), ",
19178410Sbrian                  lcp->cfg.mtu, lcp->cfg.max_mtu);
19278410Sbrian  else
19378410Sbrian    prompt_Printf(arg->prompt, "MTU = any (max %d), ", lcp->cfg.max_mtu);
19436285Sbrian  prompt_Printf(arg->prompt, "ACCMAP = %08lx\n", (u_long)lcp->cfg.accmap);
19536285Sbrian  prompt_Printf(arg->prompt, "           LQR period = %us, ",
19636285Sbrian                lcp->cfg.lqrperiod);
19736285Sbrian  prompt_Printf(arg->prompt, "Open Mode = %s",
19836285Sbrian                lcp->cfg.openmode == OPEN_PASSIVE ? "passive" : "active");
19936285Sbrian  if (lcp->cfg.openmode > 0)
20036285Sbrian    prompt_Printf(arg->prompt, " (delay %ds)", lcp->cfg.openmode);
20144305Sbrian  prompt_Printf(arg->prompt, "\n           FSM retry = %us, max %u Config"
20244305Sbrian                " REQ%s, %u Term REQ%s\n", lcp->cfg.fsm.timeout,
20344305Sbrian                lcp->cfg.fsm.maxreq, lcp->cfg.fsm.maxreq == 1 ? "" : "s",
20444305Sbrian                lcp->cfg.fsm.maxtrm, lcp->cfg.fsm.maxtrm == 1 ? "" : "s");
20563484Sbrian  prompt_Printf(arg->prompt, "    Ident: %s\n", lcp->cfg.ident);
20636285Sbrian  prompt_Printf(arg->prompt, "\n Negotiation:\n");
20736285Sbrian  prompt_Printf(arg->prompt, "           ACFCOMP =   %s\n",
20836285Sbrian                command_ShowNegval(lcp->cfg.acfcomp));
20936285Sbrian  prompt_Printf(arg->prompt, "           CHAP =      %s\n",
21044106Sbrian                command_ShowNegval(lcp->cfg.chap05));
21193418Sbrian#ifndef NODES
21269357Sbrian  prompt_Printf(arg->prompt, "           CHAP80 =    %s\n",
21344106Sbrian                command_ShowNegval(lcp->cfg.chap80nt));
21444106Sbrian  prompt_Printf(arg->prompt, "           LANMan =    %s\n",
21544106Sbrian                command_ShowNegval(lcp->cfg.chap80lm));
21667910Sbrian  prompt_Printf(arg->prompt, "           CHAP81 =    %s\n",
21767910Sbrian                command_ShowNegval(lcp->cfg.chap81));
21844106Sbrian#endif
21936285Sbrian  prompt_Printf(arg->prompt, "           LQR =       %s\n",
22036285Sbrian                command_ShowNegval(lcp->cfg.lqr));
221138799Sbrian  prompt_Printf(arg->prompt, "           LCP ECHO =  %s\n",
222138799Sbrian                lcp->cfg.echo ? "enabled" : "disabled");
22336285Sbrian  prompt_Printf(arg->prompt, "           PAP =       %s\n",
22436285Sbrian                command_ShowNegval(lcp->cfg.pap));
22536285Sbrian  prompt_Printf(arg->prompt, "           PROTOCOMP = %s\n",
22636285Sbrian                command_ShowNegval(lcp->cfg.protocomp));
22726516Sbrian
22826516Sbrian  return 0;
2296059Samurai}
2306059Samurai
23132439Sbrianstatic u_int32_t
23231343SbrianGenerateMagic(void)
2336059Samurai{
23436285Sbrian  /* Generate random number which will be used as magic number */
23530715Sbrian  randinit();
23636285Sbrian  return random();
2376059Samurai}
2386059Samurai
2396059Samuraivoid
24036285Sbrianlcp_SetupCallbacks(struct lcp *lcp)
2416059Samurai{
24236285Sbrian  lcp->fsm.fn = &lcp_Callbacks;
24336285Sbrian  lcp->fsm.FsmTimer.name = lcp_TimerNames[0];
24436285Sbrian  lcp->fsm.OpenTimer.name = lcp_TimerNames[1];
24536285Sbrian  lcp->fsm.StoppedTimer.name = lcp_TimerNames[2];
2466059Samurai}
2476059Samurai
24836285Sbrianvoid
24936285Sbrianlcp_Init(struct lcp *lcp, struct bundle *bundle, struct link *l,
25036285Sbrian         const struct fsm_parent *parent)
2516059Samurai{
25236285Sbrian  /* Initialise ourselves */
25336285Sbrian  int mincode = parent ? 1 : LCP_MINMPCODE;
2546059Samurai
25544305Sbrian  fsm_Init(&lcp->fsm, "LCP", PROTO_LCP, mincode, LCP_MAXCODE, LogLCP,
25636285Sbrian           bundle, l, parent, &lcp_Callbacks, lcp_TimerNames);
2576059Samurai
25880385Sbrian  lcp->cfg.mru = 0;
25978410Sbrian  lcp->cfg.max_mru = MAX_MRU;
26078410Sbrian  lcp->cfg.mtu = 0;
26178410Sbrian  lcp->cfg.max_mtu = MAX_MTU;
26236285Sbrian  lcp->cfg.accmap = 0;
26336285Sbrian  lcp->cfg.openmode = 1;
26436285Sbrian  lcp->cfg.lqrperiod = DEF_LQRPERIOD;
26544305Sbrian  lcp->cfg.fsm.timeout = DEF_FSMRETRY;
26644305Sbrian  lcp->cfg.fsm.maxreq = DEF_FSMTRIES;
26744305Sbrian  lcp->cfg.fsm.maxtrm = DEF_FSMTRIES;
26831514Sbrian
26936285Sbrian  lcp->cfg.acfcomp = NEG_ENABLED|NEG_ACCEPTED;
27044106Sbrian  lcp->cfg.chap05 = NEG_ACCEPTED;
27193418Sbrian#ifndef NODES
27244106Sbrian  lcp->cfg.chap80nt = NEG_ACCEPTED;
27379164Sbrian  lcp->cfg.chap80lm = 0;
27468906Sbrian  lcp->cfg.chap81 = NEG_ACCEPTED;
27544106Sbrian#endif
27636285Sbrian  lcp->cfg.lqr = NEG_ACCEPTED;
277138799Sbrian  lcp->cfg.echo = 0;
27836285Sbrian  lcp->cfg.pap = NEG_ACCEPTED;
27936285Sbrian  lcp->cfg.protocomp = NEG_ENABLED|NEG_ACCEPTED;
28063484Sbrian  *lcp->cfg.ident = '\0';
28136285Sbrian
28236285Sbrian  lcp_Setup(lcp, lcp->cfg.openmode);
2836059Samurai}
2846059Samurai
28536285Sbrianvoid
28636285Sbrianlcp_Setup(struct lcp *lcp, int openmode)
28736285Sbrian{
28878410Sbrian  struct physical *p = link2physical(lcp->fsm.link);
28978410Sbrian
29036285Sbrian  lcp->fsm.open_mode = openmode;
29131514Sbrian
29278410Sbrian  lcp->his_mru = DEF_MRU;
29336285Sbrian  lcp->his_mrru = 0;
29436285Sbrian  lcp->his_magic = 0;
29536285Sbrian  lcp->his_lqrperiod = 0;
29636285Sbrian  lcp->his_acfcomp = 0;
29736285Sbrian  lcp->his_auth = 0;
29844106Sbrian  lcp->his_authtype = 0;
29938174Sbrian  lcp->his_callback.opmask = 0;
30036285Sbrian  lcp->his_shortseq = 0;
30185094Sbrian  lcp->mru_req = 0;
30231514Sbrian
30380385Sbrian  if ((lcp->want_mru = lcp->cfg.mru) == 0)
30480385Sbrian    lcp->want_mru = DEF_MRU;
30536285Sbrian  lcp->want_mrru = lcp->fsm.bundle->ncp.mp.cfg.mrru;
30636285Sbrian  lcp->want_shortseq = IsEnabled(lcp->fsm.bundle->ncp.mp.cfg.shortseq) ? 1 : 0;
30736285Sbrian  lcp->want_acfcomp = IsEnabled(lcp->cfg.acfcomp) ? 1 : 0;
30831514Sbrian
30936285Sbrian  if (lcp->fsm.parent) {
31036285Sbrian    lcp->his_accmap = 0xffffffff;
31136285Sbrian    lcp->want_accmap = lcp->cfg.accmap;
31236285Sbrian    lcp->his_protocomp = 0;
31336285Sbrian    lcp->want_protocomp = IsEnabled(lcp->cfg.protocomp) ? 1 : 0;
31436285Sbrian    lcp->want_magic = GenerateMagic();
31544106Sbrian
31644106Sbrian    if (IsEnabled(lcp->cfg.chap05)) {
31744106Sbrian      lcp->want_auth = PROTO_CHAP;
31844106Sbrian      lcp->want_authtype = 0x05;
31993418Sbrian#ifndef NODES
32044106Sbrian    } else if (IsEnabled(lcp->cfg.chap80nt) ||
32144106Sbrian               IsEnabled(lcp->cfg.chap80lm)) {
32244106Sbrian      lcp->want_auth = PROTO_CHAP;
32344106Sbrian      lcp->want_authtype = 0x80;
32467910Sbrian    } else if (IsEnabled(lcp->cfg.chap81)) {
32567910Sbrian      lcp->want_auth = PROTO_CHAP;
32667910Sbrian      lcp->want_authtype = 0x81;
32744106Sbrian#endif
32844106Sbrian    } else if (IsEnabled(lcp->cfg.pap)) {
32944106Sbrian      lcp->want_auth = PROTO_PAP;
33044106Sbrian      lcp->want_authtype = 0;
33144106Sbrian    } else {
33244106Sbrian      lcp->want_auth = 0;
33344106Sbrian      lcp->want_authtype = 0;
33444106Sbrian    }
33544106Sbrian
33638174Sbrian    if (p->type != PHYS_DIRECT)
33767912Sbrian      memcpy(&lcp->want_callback, &p->dl->cfg.callback,
33867912Sbrian             sizeof(struct callback));
33938174Sbrian    else
34038174Sbrian      lcp->want_callback.opmask = 0;
34136285Sbrian    lcp->want_lqrperiod = IsEnabled(lcp->cfg.lqr) ?
34236285Sbrian                          lcp->cfg.lqrperiod * 100 : 0;
34336285Sbrian  } else {
34436285Sbrian    lcp->his_accmap = lcp->want_accmap = 0;
34536285Sbrian    lcp->his_protocomp = lcp->want_protocomp = 1;
34636285Sbrian    lcp->want_magic = 0;
34736285Sbrian    lcp->want_auth = 0;
34844106Sbrian    lcp->want_authtype = 0;
34938174Sbrian    lcp->want_callback.opmask = 0;
35036285Sbrian    lcp->want_lqrperiod = 0;
35136285Sbrian  }
35231514Sbrian
35336285Sbrian  lcp->his_reject = lcp->my_reject = 0;
35436285Sbrian  lcp->auth_iwait = lcp->auth_ineed = 0;
35536285Sbrian  lcp->LcpFailedMagic = 0;
35636285Sbrian}
35731514Sbrian
35836285Sbrianstatic void
35944305SbrianLcpInitRestartCounter(struct fsm *fp, int what)
36036285Sbrian{
36136285Sbrian  /* Set fsm timer load */
36236285Sbrian  struct lcp *lcp = fsm2lcp(fp);
36331514Sbrian
36444305Sbrian  fp->FsmTimer.load = lcp->cfg.fsm.timeout * SECTICKS;
36544305Sbrian  switch (what) {
36644305Sbrian    case FSM_REQ_TIMER:
36744305Sbrian      fp->restart = lcp->cfg.fsm.maxreq;
36844305Sbrian      break;
36944305Sbrian    case FSM_TRM_TIMER:
37044305Sbrian      fp->restart = lcp->cfg.fsm.maxtrm;
37144305Sbrian      break;
37244305Sbrian    default:
37344305Sbrian      fp->restart = 1;
37444305Sbrian      break;
37544305Sbrian  }
37636285Sbrian}
37736285Sbrian
3786059Samuraistatic void
37936285SbrianLcpSendConfigReq(struct fsm *fp)
3806059Samurai{
38136285Sbrian  /* Send config REQ please */
38236285Sbrian  struct physical *p = link2physical(fp->link);
38336285Sbrian  struct lcp *lcp = fsm2lcp(fp);
38436285Sbrian  u_char buff[200];
38594894Sbrian  struct fsm_opt *o;
38636285Sbrian  struct mp *mp;
38738814Sbrian  u_int16_t proto;
38879811Sbrian  u_short maxmru;
3896059Samurai
39036285Sbrian  if (!p) {
39136285Sbrian    log_Printf(LogERROR, "%s: LcpSendConfigReq: Not a physical link !\n",
39236285Sbrian              fp->link->name);
39336285Sbrian    return;
39436285Sbrian  }
39536285Sbrian
39694894Sbrian  o = (struct fsm_opt *)buff;
39736285Sbrian  if (!physical_IsSync(p)) {
39831514Sbrian    if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP))
39994894Sbrian      INC_FSM_OPT(TY_ACFCOMP, 2, o);
40031514Sbrian
40131514Sbrian    if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP))
40294894Sbrian      INC_FSM_OPT(TY_PROTOCOMP, 2, o);
40331514Sbrian
40436285Sbrian    if (!REJECTED(lcp, TY_ACCMAP)) {
40538814Sbrian      ua_htonl(&lcp->want_accmap, o->data);
40694894Sbrian      INC_FSM_OPT(TY_ACCMAP, 6, o);
40736285Sbrian    }
4086059Samurai  }
40931514Sbrian
41079811Sbrian  maxmru = p ? physical_DeviceMTU(p) : 0;
41179811Sbrian  if (lcp->cfg.max_mru && (!maxmru || maxmru > lcp->cfg.max_mru))
41279811Sbrian    maxmru = lcp->cfg.max_mru;
41379811Sbrian  if (maxmru && lcp->want_mru > maxmru) {
41479811Sbrian    log_Printf(LogWARN, "%s: Reducing configured MRU from %u to %u\n",
41579811Sbrian               fp->link->name, lcp->want_mru, maxmru);
41679811Sbrian    lcp->want_mru = maxmru;
41779811Sbrian  }
41880655Sbrian  if (!REJECTED(lcp, TY_MRU)) {
41938814Sbrian    ua_htons(&lcp->want_mru, o->data);
42094894Sbrian    INC_FSM_OPT(TY_MRU, 4, o);
42136285Sbrian  }
42231514Sbrian
42336285Sbrian  if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM)) {
42438814Sbrian    ua_htonl(&lcp->want_magic, o->data);
42594894Sbrian    INC_FSM_OPT(TY_MAGICNUM, 6, o);
42636285Sbrian  }
42731514Sbrian
42836285Sbrian  if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) {
42938814Sbrian    proto = PROTO_LQR;
43038814Sbrian    ua_htons(&proto, o->data);
43138814Sbrian    ua_htonl(&lcp->want_lqrperiod, o->data + 2);
43294894Sbrian    INC_FSM_OPT(TY_QUALPROTO, 8, o);
43336285Sbrian  }
43431514Sbrian
4356059Samurai  switch (lcp->want_auth) {
4366059Samurai  case PROTO_PAP:
43738814Sbrian    proto = PROTO_PAP;
43838814Sbrian    ua_htons(&proto, o->data);
43994894Sbrian    INC_FSM_OPT(TY_AUTHPROTO, 4, o);
4406059Samurai    break;
44131514Sbrian
4426059Samurai  case PROTO_CHAP:
44338814Sbrian    proto = PROTO_CHAP;
44438814Sbrian    ua_htons(&proto, o->data);
44544106Sbrian    o->data[2] = lcp->want_authtype;
44694894Sbrian    INC_FSM_OPT(TY_AUTHPROTO, 5, o);
4476059Samurai    break;
4486059Samurai  }
4496059Samurai
45038174Sbrian  if (!REJECTED(lcp, TY_CALLBACK)) {
45138174Sbrian    if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) {
45238174Sbrian      *o->data = CALLBACK_AUTH;
45394894Sbrian      INC_FSM_OPT(TY_CALLBACK, 3, o);
45438174Sbrian    } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) {
45538174Sbrian      *o->data = CALLBACK_CBCP;
45694894Sbrian      INC_FSM_OPT(TY_CALLBACK, 3, o);
45738174Sbrian    } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164)) {
458134789Sbrian      size_t sz = strlen(lcp->want_callback.msg);
45938174Sbrian
46038174Sbrian      if (sz > sizeof o->data - 1) {
46138174Sbrian        sz = sizeof o->data - 1;
462134833Smarcel        log_Printf(LogWARN, "Truncating E164 data to %zu octets (oops!)\n",
463134833Smarcel	    sz);
46438174Sbrian      }
46538174Sbrian      *o->data = CALLBACK_E164;
46638174Sbrian      memcpy(o->data + 1, lcp->want_callback.msg, sz);
46794894Sbrian      INC_FSM_OPT(TY_CALLBACK, sz + 3, o);
46838174Sbrian    }
46938174Sbrian  }
47038174Sbrian
47136285Sbrian  if (lcp->want_mrru && !REJECTED(lcp, TY_MRRU)) {
47238814Sbrian    ua_htons(&lcp->want_mrru, o->data);
47394894Sbrian    INC_FSM_OPT(TY_MRRU, 4, o);
4746059Samurai
47536285Sbrian    if (lcp->want_shortseq && !REJECTED(lcp, TY_SHORTSEQ))
47694894Sbrian      INC_FSM_OPT(TY_SHORTSEQ, 2, o);
47736285Sbrian  }
4786059Samurai
47936285Sbrian  mp = &lcp->fsm.bundle->ncp.mp;
48047858Sbrian  if (mp->cfg.enddisc.class != 0 && IsEnabled(mp->cfg.negenddisc) &&
48147858Sbrian      !REJECTED(lcp, TY_ENDDISC)) {
48236285Sbrian    *o->data = mp->cfg.enddisc.class;
48336285Sbrian    memcpy(o->data+1, mp->cfg.enddisc.address, mp->cfg.enddisc.len);
48494894Sbrian    INC_FSM_OPT(TY_ENDDISC, mp->cfg.enddisc.len + 3, o);
48536285Sbrian  }
4866059Samurai
48747695Sbrian  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
48847695Sbrian             MB_LCPOUT);
4896059Samurai}
4906059Samurai
49136285Sbrianvoid
49236285Sbrianlcp_SendProtoRej(struct lcp *lcp, u_char *option, int count)
4936059Samurai{
49436285Sbrian  /* Don't understand `option' */
49547695Sbrian  fsm_Output(&lcp->fsm, CODE_PROTOREJ, lcp->fsm.reqid, option, count,
49647695Sbrian             MB_LCPOUT);
4976059Samurai}
4986059Samurai
49963484Sbrianint
50063484Sbrianlcp_SendIdentification(struct lcp *lcp)
50163484Sbrian{
50263484Sbrian  static u_char id;		/* Use a private id */
50363484Sbrian  u_char msg[DEF_MRU - 3];
50463484Sbrian  const char *argv[2];
50563484Sbrian  char *exp[2];
50663484Sbrian
50763484Sbrian  if (*lcp->cfg.ident == '\0')
50863484Sbrian    return 0;
50963484Sbrian
51063484Sbrian  argv[0] = lcp->cfg.ident;
51163484Sbrian  argv[1] = NULL;
51263484Sbrian
51363484Sbrian  command_Expand(exp, 1, argv, lcp->fsm.bundle, 1, getpid());
51463484Sbrian
51563484Sbrian  ua_htonl(&lcp->want_magic, msg);
51663484Sbrian  strncpy(msg + 4, exp[0], sizeof msg - 5);
51763484Sbrian  msg[sizeof msg - 1] = '\0';
51863484Sbrian
51963484Sbrian  fsm_Output(&lcp->fsm, CODE_IDENT, id++, msg, 4 + strlen(msg + 4), MB_LCPOUT);
52094894Sbrian  log_Printf(LogLCP, " MAGICNUM %08x\n", lcp->want_magic);
52194894Sbrian  log_Printf(LogLCP, " TEXT %s\n", msg + 4);
52263484Sbrian
52385991Sbrian  command_Free(1, exp);
52463484Sbrian  return 1;
52563484Sbrian}
52663484Sbrian
52763484Sbrianvoid
52863484Sbrianlcp_RecvIdentification(struct lcp *lcp, char *data)
52963484Sbrian{
53094894Sbrian  log_Printf(LogLCP, " MAGICNUM %08x\n", lcp->his_magic);
53194894Sbrian  log_Printf(LogLCP, " TEXT %s\n", data);
53263484Sbrian}
53363484Sbrian
5346059Samuraistatic void
535134789SbrianLcpSentTerminateReq(struct fsm *fp __unused)
5366735Samurai{
53736285Sbrian  /* Term REQ just sent by FSM */
5386735Samurai}
5396735Samurai
5406735Samuraistatic void
54136285SbrianLcpSendTerminateAck(struct fsm *fp, u_char id)
5426059Samurai{
54336285Sbrian  /* Send Term ACK please */
54438174Sbrian  struct physical *p = link2physical(fp->link);
54538174Sbrian
54638174Sbrian  if (p && p->dl->state == DATALINK_CBCP)
54738174Sbrian    cbcp_ReceiveTerminateReq(p);
54838174Sbrian
54947695Sbrian  fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_LCPOUT);
5506059Samurai}
5516059Samurai
5526059Samuraistatic void
55336285SbrianLcpLayerStart(struct fsm *fp)
5546059Samurai{
55536285Sbrian  /* We're about to start up ! */
55636285Sbrian  struct lcp *lcp = fsm2lcp(fp);
5576059Samurai
55837210Sbrian  log_Printf(LogLCP, "%s: LayerStart\n", fp->link->name);
55936285Sbrian  lcp->LcpFailedMagic = 0;
56044305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = lcp->cfg.fsm.maxreq * 3;
56185094Sbrian  lcp->mru_req = 0;
5626059Samurai}
5636059Samurai
5646059Samuraistatic void
56536285SbrianLcpLayerFinish(struct fsm *fp)
5666059Samurai{
56736285Sbrian  /* We're now down */
56837210Sbrian  log_Printf(LogLCP, "%s: LayerFinish\n", fp->link->name);
5696059Samurai}
5706059Samurai
57136285Sbrianstatic int
57236285SbrianLcpLayerUp(struct fsm *fp)
5736059Samurai{
57436285Sbrian  /* We're now up */
57536285Sbrian  struct physical *p = link2physical(fp->link);
57636285Sbrian  struct lcp *lcp = fsm2lcp(fp);
5776059Samurai
57837210Sbrian  log_Printf(LogLCP, "%s: LayerUp\n", fp->link->name);
57993418Sbrian  physical_SetAsyncParams(p, lcp->want_accmap, lcp->his_accmap);
58036285Sbrian  lqr_Start(lcp);
58136285Sbrian  hdlc_StartTimer(&p->hdlc);
58244305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = lcp->cfg.fsm.maxreq * 3;
58344305Sbrian
58463484Sbrian  lcp_SendIdentification(lcp);
58563484Sbrian
58636285Sbrian  return 1;
5876059Samurai}
5886059Samurai
58936285Sbrianstatic void
59036285SbrianLcpLayerDown(struct fsm *fp)
5916059Samurai{
59236285Sbrian  /* About to come down */
59336285Sbrian  struct physical *p = link2physical(fp->link);
5946059Samurai
59537210Sbrian  log_Printf(LogLCP, "%s: LayerDown\n", fp->link->name);
59636285Sbrian  hdlc_StopTimer(&p->hdlc);
59736285Sbrian  lqr_StopTimer(p);
59837160Sbrian  lcp_Setup(fsm2lcp(fp), 0);
5996059Samurai}
6006059Samurai
60138174Sbrianstatic int
60238174SbrianE164ok(struct callback *cb, char *req, int sz)
60338174Sbrian{
60438174Sbrian  char list[sizeof cb->msg], *next;
60538174Sbrian  int len;
60638174Sbrian
60738174Sbrian  if (!strcmp(cb->msg, "*"))
60838174Sbrian    return 1;
60938174Sbrian
61038174Sbrian  strncpy(list, cb->msg, sizeof list - 1);
61138174Sbrian  list[sizeof list - 1] = '\0';
61238174Sbrian  for (next = strtok(list, ","); next; next = strtok(NULL, ",")) {
61338174Sbrian    len = strlen(next);
61438174Sbrian    if (sz == len && !memcmp(list, req, sz))
61538174Sbrian      return 1;
61638174Sbrian  }
61738174Sbrian  return 0;
61838174Sbrian}
61938174Sbrian
62094894Sbrianstatic int
62194894Sbrianlcp_auth_nak(struct lcp *lcp, struct fsm_decode *dec)
62294894Sbrian{
62394894Sbrian  struct fsm_opt nak;
62494894Sbrian
62594894Sbrian  nak.hdr.id = TY_AUTHPROTO;
62694894Sbrian
62794894Sbrian  if (IsAccepted(lcp->cfg.pap)) {
62894894Sbrian    nak.hdr.len = 4;
62994894Sbrian    nak.data[0] = (unsigned char)(PROTO_PAP >> 8);
63094894Sbrian    nak.data[1] = (unsigned char)PROTO_PAP;
63194894Sbrian    fsm_nak(dec, &nak);
63294894Sbrian    return 1;
63394894Sbrian  }
63494894Sbrian
63594894Sbrian  nak.hdr.len = 5;
63694894Sbrian  nak.data[0] = (unsigned char)(PROTO_CHAP >> 8);
63794894Sbrian  nak.data[1] = (unsigned char)PROTO_CHAP;
63894894Sbrian
63994894Sbrian  if (IsAccepted(lcp->cfg.chap05)) {
64094894Sbrian    nak.data[2] = 0x05;
64194894Sbrian    fsm_nak(dec, &nak);
64294894Sbrian#ifndef NODES
64394894Sbrian  } else if (IsAccepted(lcp->cfg.chap80nt) ||
64494894Sbrian             IsAccepted(lcp->cfg.chap80lm)) {
64594894Sbrian    nak.data[2] = 0x80;
64694894Sbrian    fsm_nak(dec, &nak);
64794894Sbrian  } else if (IsAccepted(lcp->cfg.chap81)) {
64894894Sbrian    nak.data[2] = 0x81;
64994894Sbrian    fsm_nak(dec, &nak);
65094894Sbrian#endif
65194894Sbrian  } else {
65294894Sbrian    return 0;
65394894Sbrian  }
65494894Sbrian
65594894Sbrian  return 1;
65694894Sbrian}
65794894Sbrian
6586059Samuraistatic void
65994894SbrianLcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
66036285Sbrian                struct fsm_decode *dec)
6616059Samurai{
66236285Sbrian  /* Deal with incoming PROTO_LCP */
66336285Sbrian  struct lcp *lcp = fsm2lcp(fp);
664134789Sbrian  int pos, op, callback_req, chap_type;
665134789Sbrian  size_t sz;
66636285Sbrian  u_int32_t magic, accmap;
66779811Sbrian  u_short mru, phmtu, maxmtu, maxmru, wantmtu, wantmru, proto;
668139973Sbrian  struct lqrreq req;
66931514Sbrian  char request[20], desc[22];
67036285Sbrian  struct mp *mp;
67136285Sbrian  struct physical *p = link2physical(fp->link);
67294894Sbrian  struct fsm_opt *opt, nak;
6736059Samurai
674134789Sbrian  sz = 0;
675134789Sbrian  op = callback_req = 0;
67638174Sbrian
677134789Sbrian  while (end - cp >= (int)sizeof(opt->hdr)) {
67894894Sbrian    if ((opt = fsm_readopt(&cp)) == NULL)
67994894Sbrian      break;
68031514Sbrian
68194894Sbrian    snprintf(request, sizeof request, " %s[%d]", protoname(opt->hdr.id),
68294894Sbrian             opt->hdr.len);
6836059Samurai
68494894Sbrian    switch (opt->hdr.id) {
68536285Sbrian    case TY_MRRU:
68636285Sbrian      mp = &lcp->fsm.bundle->ncp.mp;
68794894Sbrian      ua_ntohs(opt->data, &mru);
68836285Sbrian      log_Printf(LogLCP, "%s %u\n", request, mru);
68936285Sbrian
69036285Sbrian      switch (mode_type) {
69136285Sbrian      case MODE_REQ:
69236285Sbrian        if (mp->cfg.mrru) {
69336285Sbrian          if (REJECTED(lcp, TY_MRRU))
69436285Sbrian            /* Ignore his previous reject so that we REQ next time */
69594894Sbrian            lcp->his_reject &= ~(1 << opt->hdr.id);
69636285Sbrian
69778410Sbrian          if (mru > MAX_MRU) {
69878410Sbrian            /* Push him down to MAX_MRU */
69978410Sbrian            lcp->his_mrru = MAX_MRU;
70094894Sbrian            nak.hdr.id = TY_MRRU;
70194894Sbrian            nak.hdr.len = 4;
70294894Sbrian            ua_htons(&lcp->his_mrru, nak.data);
70394894Sbrian            fsm_nak(dec, &nak);
70478410Sbrian          } else if (mru < MIN_MRU) {
70562041Sbrian            /* Push him up to MIN_MRU */
70662041Sbrian            lcp->his_mrru = MIN_MRU;
70794894Sbrian            nak.hdr.id = TY_MRRU;
70894894Sbrian            nak.hdr.len = 4;
70994894Sbrian            ua_htons(&lcp->his_mrru, nak.data);
71094894Sbrian            fsm_nak(dec, &nak);
71194894Sbrian          } else {
71262041Sbrian            lcp->his_mrru = mru;
71394894Sbrian            fsm_ack(dec, opt);
71494894Sbrian          }
71594894Sbrian          break;
71694894Sbrian        } else {
71794894Sbrian          fsm_rej(dec, opt);
71894894Sbrian          lcp->my_reject |= (1 << opt->hdr.id);
71994894Sbrian        }
72036285Sbrian        break;
72136285Sbrian      case MODE_NAK:
72236285Sbrian        if (mp->cfg.mrru) {
72336285Sbrian          if (REJECTED(lcp, TY_MRRU))
72436285Sbrian            /* Must have changed his mind ! */
72594894Sbrian            lcp->his_reject &= ~(1 << opt->hdr.id);
72636285Sbrian
72736285Sbrian          if (mru > MAX_MRU)
72836285Sbrian            lcp->want_mrru = MAX_MRU;
72936285Sbrian          else if (mru < MIN_MRU)
73036285Sbrian            lcp->want_mrru = MIN_MRU;
73136285Sbrian          else
73236285Sbrian            lcp->want_mrru = mru;
73336285Sbrian        }
73436285Sbrian        /* else we honour our config and don't send the suggested REQ */
73536285Sbrian        break;
73636285Sbrian      case MODE_REJ:
73794894Sbrian        lcp->his_reject |= (1 << opt->hdr.id);
73836285Sbrian        lcp->want_mrru = 0;		/* Ah well, no multilink :-( */
73994894Sbrian        break;
74036285Sbrian      }
74136285Sbrian      break;
74236285Sbrian
7436059Samurai    case TY_MRU:
74485094Sbrian      lcp->mru_req = 1;
74594894Sbrian      ua_ntohs(opt->data, &mru);
74636285Sbrian      log_Printf(LogLCP, "%s %d\n", request, mru);
7476059Samurai
74831034Sbrian      switch (mode_type) {
7496059Samurai      case MODE_REQ:
75079811Sbrian        maxmtu = p ? physical_DeviceMTU(p) : 0;
75179811Sbrian        if (lcp->cfg.max_mtu && (!maxmtu || maxmtu > lcp->cfg.max_mtu))
75279811Sbrian          maxmtu = lcp->cfg.max_mtu;
75380385Sbrian        wantmtu = lcp->cfg.mtu;
75479811Sbrian        if (maxmtu && wantmtu > maxmtu) {
75579811Sbrian          log_Printf(LogWARN, "%s: Reducing configured MTU from %u to %u\n",
75679811Sbrian                     fp->link->name, wantmtu, maxmtu);
75779811Sbrian          wantmtu = maxmtu;
75879811Sbrian        }
75979811Sbrian
76079811Sbrian        if (maxmtu && mru > maxmtu) {
76179811Sbrian          lcp->his_mru = maxmtu;
76294894Sbrian          nak.hdr.id = TY_MRU;
76394894Sbrian          nak.hdr.len = 4;
76494894Sbrian          ua_htons(&lcp->his_mru, nak.data);
76594894Sbrian          fsm_nak(dec, &nak);
76680385Sbrian        } else if (wantmtu && mru < wantmtu) {
76736285Sbrian          /* Push him up to MTU or MIN_MRU */
76879811Sbrian          lcp->his_mru = wantmtu;
76994894Sbrian          nak.hdr.id = TY_MRU;
77094894Sbrian          nak.hdr.len = 4;
77194894Sbrian          ua_htons(&lcp->his_mru, nak.data);
77294894Sbrian          fsm_nak(dec, &nak);
77336285Sbrian        } else {
77480385Sbrian          lcp->his_mru = mru;
77594894Sbrian          fsm_ack(dec, opt);
77636285Sbrian        }
77794894Sbrian        break;
7786059Samurai      case MODE_NAK:
77979811Sbrian        maxmru = p ? physical_DeviceMTU(p) : 0;
78079811Sbrian        if (lcp->cfg.max_mru && (!maxmru || maxmru > lcp->cfg.max_mru))
78179811Sbrian          maxmru = lcp->cfg.max_mru;
78279811Sbrian        wantmru = lcp->cfg.mru > maxmru ? maxmru : lcp->cfg.mru;
78379811Sbrian
78480385Sbrian        if (wantmru && mru > wantmru)
78579811Sbrian          lcp->want_mru = wantmru;
78680385Sbrian        else if (mru > maxmru)
78780385Sbrian          lcp->want_mru = maxmru;
78879811Sbrian        else if (mru < MIN_MRU)
78936285Sbrian          lcp->want_mru = MIN_MRU;
79036285Sbrian        else
79136285Sbrian          lcp->want_mru = mru;
79294894Sbrian        break;
7936059Samurai      case MODE_REJ:
79494894Sbrian        lcp->his_reject |= (1 << opt->hdr.id);
795162062Sbrian        /* Set the MTU to what we want anyway - the peer won't care! */
796162062Sbrian        if (lcp->his_mru > lcp->want_mru)
797162062Sbrian          lcp->his_mru = lcp->want_mru;
79894894Sbrian        break;
7996059Samurai      }
8006059Samurai      break;
80131514Sbrian
8026059Samurai    case TY_ACCMAP:
80394894Sbrian      ua_ntohl(opt->data, &accmap);
80436285Sbrian      log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)accmap);
8056059Samurai
80631034Sbrian      switch (mode_type) {
8076059Samurai      case MODE_REQ:
80894894Sbrian        lcp->his_accmap = accmap;
80994894Sbrian        fsm_ack(dec, opt);
81094894Sbrian        break;
8116059Samurai      case MODE_NAK:
81294894Sbrian        lcp->want_accmap = accmap;
81394894Sbrian        break;
8146059Samurai      case MODE_REJ:
81594894Sbrian        lcp->his_reject |= (1 << opt->hdr.id);
81694894Sbrian        break;
8176059Samurai      }
8186059Samurai      break;
81931514Sbrian
8206059Samurai    case TY_AUTHPROTO:
82194894Sbrian      ua_ntohs(opt->data, &proto);
82294894Sbrian      chap_type = opt->hdr.len == 5 ? opt->data[2] : 0;
82394894Sbrian
82444106Sbrian      log_Printf(LogLCP, "%s 0x%04x (%s)\n", request, proto,
82594894Sbrian                 Auth2Nam(proto, chap_type));
8266059Samurai
82731034Sbrian      switch (mode_type) {
8286059Samurai      case MODE_REQ:
82994894Sbrian        switch (proto) {
83094894Sbrian        case PROTO_PAP:
83194894Sbrian          if (opt->hdr.len == 4 && IsAccepted(lcp->cfg.pap)) {
83294894Sbrian            lcp->his_auth = proto;
83394894Sbrian            lcp->his_authtype = 0;
83494894Sbrian            fsm_ack(dec, opt);
83594894Sbrian          } else if (!lcp_auth_nak(lcp, dec)) {
83694894Sbrian            lcp->my_reject |= (1 << opt->hdr.id);
83794894Sbrian            fsm_rej(dec, opt);
83894894Sbrian          }
83994894Sbrian          break;
84031514Sbrian
84194894Sbrian        case PROTO_CHAP:
84294894Sbrian          if ((chap_type == 0x05 && IsAccepted(lcp->cfg.chap05))
84393418Sbrian#ifndef NODES
84494894Sbrian              || (chap_type == 0x80 && (IsAccepted(lcp->cfg.chap80nt) ||
84544106Sbrian                                   (IsAccepted(lcp->cfg.chap80lm))))
84694894Sbrian              || (chap_type == 0x81 && IsAccepted(lcp->cfg.chap81))
84729840Sbrian#endif
84844106Sbrian             ) {
84994894Sbrian            lcp->his_auth = proto;
85094894Sbrian            lcp->his_authtype = chap_type;
85194894Sbrian            fsm_ack(dec, opt);
85294894Sbrian          } else {
85394894Sbrian#ifdef NODES
85494894Sbrian            if (chap_type == 0x80) {
85544106Sbrian              log_Printf(LogWARN, "CHAP 0x80 not available without DES\n");
85694894Sbrian            } else if (chap_type == 0x81) {
85767910Sbrian              log_Printf(LogWARN, "CHAP 0x81 not available without DES\n");
85867910Sbrian            } else
85940480Sbrian#endif
86094894Sbrian            if (chap_type != 0x05)
86144106Sbrian              log_Printf(LogWARN, "%s not supported\n",
86294894Sbrian                         Auth2Nam(PROTO_CHAP, chap_type));
86344106Sbrian
86494894Sbrian            if (!lcp_auth_nak(lcp, dec)) {
86594894Sbrian              lcp->my_reject |= (1 << opt->hdr.id);
86694894Sbrian              fsm_rej(dec, opt);
86794894Sbrian            }
86840480Sbrian          }
86994894Sbrian          break;
87031514Sbrian
87194894Sbrian        default:
87294894Sbrian          log_Printf(LogLCP, "%s 0x%04x - not recognised\n",
87331616Sbrian                    request, proto);
87494894Sbrian          if (!lcp_auth_nak(lcp, dec)) {
87594894Sbrian            lcp->my_reject |= (1 << opt->hdr.id);
87694894Sbrian            fsm_rej(dec, opt);
87794894Sbrian          }
87894894Sbrian          break;
87994894Sbrian        }
88094894Sbrian        break;
88194894Sbrian
8826059Samurai      case MODE_NAK:
88394894Sbrian        switch (proto) {
88494894Sbrian        case PROTO_PAP:
88544106Sbrian          if (IsEnabled(lcp->cfg.pap)) {
88636285Sbrian            lcp->want_auth = PROTO_PAP;
88744106Sbrian            lcp->want_authtype = 0;
88844106Sbrian          } else {
88936285Sbrian            log_Printf(LogLCP, "Peer will only send PAP (not enabled)\n");
89094894Sbrian            lcp->his_reject |= (1 << opt->hdr.id);
89131616Sbrian          }
89231616Sbrian          break;
89394894Sbrian        case PROTO_CHAP:
89494894Sbrian          if (chap_type == 0x05 && IsEnabled(lcp->cfg.chap05)) {
89536285Sbrian            lcp->want_auth = PROTO_CHAP;
89644106Sbrian            lcp->want_authtype = 0x05;
89793418Sbrian#ifndef NODES
89894894Sbrian          } else if (chap_type == 0x80 && (IsEnabled(lcp->cfg.chap80nt) ||
89994894Sbrian                                           IsEnabled(lcp->cfg.chap80lm))) {
90044106Sbrian            lcp->want_auth = PROTO_CHAP;
90144106Sbrian            lcp->want_authtype = 0x80;
90294894Sbrian          } else if (chap_type == 0x81 && IsEnabled(lcp->cfg.chap81)) {
90367910Sbrian            lcp->want_auth = PROTO_CHAP;
90467910Sbrian            lcp->want_authtype = 0x81;
90544106Sbrian#endif
90644106Sbrian          } else {
90794894Sbrian#ifdef NODES
90894894Sbrian            if (chap_type == 0x80) {
90944106Sbrian              log_Printf(LogLCP, "Peer will only send MSCHAP (not available"
91044106Sbrian                         " without DES)\n");
91194894Sbrian            } else if (chap_type == 0x81) {
91267910Sbrian              log_Printf(LogLCP, "Peer will only send MSCHAPV2 (not available"
91367910Sbrian                         " without DES)\n");
91467910Sbrian            } else
91544106Sbrian#endif
91644305Sbrian            log_Printf(LogLCP, "Peer will only send %s (not %s)\n",
91794894Sbrian                       Auth2Nam(PROTO_CHAP, chap_type),
91893418Sbrian#ifndef NODES
91994894Sbrian                       (chap_type == 0x80 || chap_type == 0x81) ? "configured" :
92044305Sbrian#endif
92144305Sbrian                       "supported");
92294894Sbrian            lcp->his_reject |= (1 << opt->hdr.id);
92331616Sbrian          }
92431616Sbrian          break;
92531616Sbrian        default:
92631616Sbrian          /* We've been NAK'd with something we don't understand :-( */
92794894Sbrian          lcp->his_reject |= (1 << opt->hdr.id);
92831616Sbrian          break;
92931616Sbrian        }
93094894Sbrian        break;
93194894Sbrian
9326059Samurai      case MODE_REJ:
93394894Sbrian        lcp->his_reject |= (1 << opt->hdr.id);
93494894Sbrian        break;
9356059Samurai      }
9366059Samurai      break;
93731514Sbrian
9386059Samurai    case TY_QUALPROTO:
939139973Sbrian      memcpy(&req, opt, sizeof req);
94037210Sbrian      log_Printf(LogLCP, "%s proto %x, interval %lums\n",
941139973Sbrian                request, ntohs(req.proto), (u_long)ntohl(req.period) * 10);
94231034Sbrian      switch (mode_type) {
9436059Samurai      case MODE_REQ:
944139973Sbrian        if (ntohs(req.proto) != PROTO_LQR || !IsAccepted(lcp->cfg.lqr)) {
94594894Sbrian          fsm_rej(dec, opt);
94694894Sbrian          lcp->my_reject |= (1 << opt->hdr.id);
94794894Sbrian        } else {
948139973Sbrian          lcp->his_lqrperiod = ntohl(req.period);
94994894Sbrian          if (lcp->his_lqrperiod < MIN_LQRPERIOD * 100)
95094894Sbrian            lcp->his_lqrperiod = MIN_LQRPERIOD * 100;
951139973Sbrian          req.period = htonl(lcp->his_lqrperiod);
95294894Sbrian          fsm_ack(dec, opt);
95394894Sbrian        }
95494894Sbrian        break;
9556059Samurai      case MODE_NAK:
956139973Sbrian        lcp->want_lqrperiod = ntohl(req.period);
95794894Sbrian        break;
9586059Samurai      case MODE_REJ:
95994894Sbrian        lcp->his_reject |= (1 << opt->hdr.id);
96094894Sbrian        break;
9616059Samurai      }
9626059Samurai      break;
96331514Sbrian
9646059Samurai    case TY_MAGICNUM:
96594894Sbrian      ua_ntohl(opt->data, &magic);
96636285Sbrian      log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)magic);
9676059Samurai
96831034Sbrian      switch (mode_type) {
9696059Samurai      case MODE_REQ:
97094894Sbrian        if (lcp->want_magic) {
97194894Sbrian          /* Validate magic number */
97294894Sbrian          if (magic == lcp->want_magic) {
97394894Sbrian            sigset_t emptyset;
97483404Sbrian
97594894Sbrian            log_Printf(LogLCP, "Magic is same (%08lx) - %d times\n",
97636285Sbrian                      (u_long)magic, ++lcp->LcpFailedMagic);
97794894Sbrian            lcp->want_magic = GenerateMagic();
97894894Sbrian            fsm_nak(dec, opt);
97936285Sbrian            ualarm(TICKUNIT * (4 + 4 * lcp->LcpFailedMagic), 0);
98094894Sbrian            sigemptyset(&emptyset);
98194894Sbrian            sigsuspend(&emptyset);
98294894Sbrian          } else {
98394894Sbrian            lcp->his_magic = magic;
98436285Sbrian            lcp->LcpFailedMagic = 0;
98594894Sbrian            fsm_ack(dec, opt);
98694894Sbrian          }
98794894Sbrian        } else {
98894894Sbrian          lcp->my_reject |= (1 << opt->hdr.id);
98994894Sbrian          fsm_rej(dec, opt);
99094894Sbrian        }
99194894Sbrian        break;
9926059Samurai      case MODE_NAK:
99394894Sbrian        log_Printf(LogLCP, " Magic 0x%08lx is NAKed!\n", (u_long)magic);
99494894Sbrian        lcp->want_magic = GenerateMagic();
99594894Sbrian        break;
9966059Samurai      case MODE_REJ:
99794894Sbrian        log_Printf(LogLCP, " Magic 0x%08x is REJected!\n", magic);
99894894Sbrian        lcp->want_magic = 0;
99994894Sbrian        lcp->his_reject |= (1 << opt->hdr.id);
100094894Sbrian        break;
10016059Samurai      }
10026059Samurai      break;
100331514Sbrian
10046059Samurai    case TY_PROTOCOMP:
100536285Sbrian      log_Printf(LogLCP, "%s\n", request);
10066059Samurai
100731034Sbrian      switch (mode_type) {
10086059Samurai      case MODE_REQ:
100994894Sbrian        if (IsAccepted(lcp->cfg.protocomp)) {
101094894Sbrian          lcp->his_protocomp = 1;
101194894Sbrian          fsm_ack(dec, opt);
101294894Sbrian        } else {
10136059Samurai#ifdef OLDMST
101494894Sbrian          /* MorningStar before v1.3 needs NAK */
101594894Sbrian          fsm_nak(dec, opt);
10166059Samurai#else
101794894Sbrian          fsm_rej(dec, opt);
101894894Sbrian          lcp->my_reject |= (1 << opt->hdr.id);
10196059Samurai#endif
102094894Sbrian        }
102194894Sbrian        break;
10226059Samurai      case MODE_NAK:
10236059Samurai      case MODE_REJ:
102494894Sbrian        lcp->want_protocomp = 0;
102594894Sbrian        lcp->his_reject |= (1 << opt->hdr.id);
102694894Sbrian        break;
10276059Samurai      }
10286059Samurai      break;
102931514Sbrian
10306059Samurai    case TY_ACFCOMP:
103136285Sbrian      log_Printf(LogLCP, "%s\n", request);
103231034Sbrian      switch (mode_type) {
10336059Samurai      case MODE_REQ:
103494894Sbrian        if (IsAccepted(lcp->cfg.acfcomp)) {
103594894Sbrian          lcp->his_acfcomp = 1;
103694894Sbrian          fsm_ack(dec, opt);
103794894Sbrian        } else {
10386059Samurai#ifdef OLDMST
103994894Sbrian          /* MorningStar before v1.3 needs NAK */
104094894Sbrian          fsm_nak(dec, opt);
10416059Samurai#else
104294894Sbrian          fsm_rej(dec, opt);
104394894Sbrian          lcp->my_reject |= (1 << opt->hdr.id);
10446059Samurai#endif
104594894Sbrian        }
104694894Sbrian        break;
10476059Samurai      case MODE_NAK:
10486059Samurai      case MODE_REJ:
104994894Sbrian        lcp->want_acfcomp = 0;
105094894Sbrian        lcp->his_reject |= (1 << opt->hdr.id);
105194894Sbrian        break;
10526059Samurai      }
10536059Samurai      break;
105431514Sbrian
10556059Samurai    case TY_SDP:
105636285Sbrian      log_Printf(LogLCP, "%s\n", request);
105731034Sbrian      switch (mode_type) {
10586059Samurai      case MODE_REQ:
10596059Samurai      case MODE_NAK:
10606059Samurai      case MODE_REJ:
106194894Sbrian        break;
10626059Samurai      }
10636059Samurai      break;
106431514Sbrian
106538174Sbrian    case TY_CALLBACK:
1066134789Sbrian      if (opt->hdr.len == 2) {
106738174Sbrian        op = CALLBACK_NONE;
1068134789Sbrian        sz = 0;
1069134789Sbrian      } else {
107094894Sbrian        op = (int)opt->data[0];
1071134789Sbrian        sz = opt->hdr.len - 3;
1072134789Sbrian      }
107338174Sbrian      switch (op) {
107438174Sbrian        case CALLBACK_AUTH:
107538174Sbrian          log_Printf(LogLCP, "%s Auth\n", request);
107638174Sbrian          break;
107738174Sbrian        case CALLBACK_DIALSTRING:
1078134833Smarcel		log_Printf(LogLCP, "%s Dialstring %.*s\n", request, (int)sz,
107994894Sbrian                     opt->data + 1);
108038174Sbrian          break;
108138174Sbrian        case CALLBACK_LOCATION:
1082134833Smarcel		log_Printf(LogLCP, "%s Location %.*s\n", request, (int)sz,
1083134833Smarcel		    opt->data + 1);
108438174Sbrian          break;
108538174Sbrian        case CALLBACK_E164:
1086134833Smarcel		log_Printf(LogLCP, "%s E.164 (%.*s)\n", request, (int)sz,
1087134833Smarcel		    opt->data + 1);
108838174Sbrian          break;
108938174Sbrian        case CALLBACK_NAME:
1090134833Smarcel		log_Printf(LogLCP, "%s Name %.*s\n", request, (int)sz,
1091134833Smarcel		    opt->data + 1);
109238174Sbrian          break;
109338174Sbrian        case CALLBACK_CBCP:
109438174Sbrian          log_Printf(LogLCP, "%s CBCP\n", request);
109538174Sbrian          break;
109638174Sbrian        default:
109738174Sbrian          log_Printf(LogLCP, "%s ???\n", request);
109838174Sbrian          break;
109938174Sbrian      }
110038174Sbrian
110138174Sbrian      switch (mode_type) {
110238174Sbrian      case MODE_REQ:
110338174Sbrian        callback_req = 1;
110494894Sbrian        if (p->type != PHYS_DIRECT) {
110594894Sbrian          fsm_rej(dec, opt);
110694894Sbrian          lcp->my_reject |= (1 << opt->hdr.id);
110794894Sbrian        }
110894894Sbrian        nak.hdr.id = opt->hdr.id;
110994894Sbrian        nak.hdr.len = 3;
111038174Sbrian        if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(op)) &&
111185095Sbrian            (op != CALLBACK_AUTH || p->link.lcp.want_auth) &&
111238174Sbrian            (op != CALLBACK_E164 ||
111394894Sbrian             E164ok(&p->dl->cfg.callback, opt->data + 1, sz))) {
111494894Sbrian          lcp->his_callback.opmask = CALLBACK_BIT(op);
111538174Sbrian          if (sz > sizeof lcp->his_callback.msg - 1) {
111638174Sbrian            sz = sizeof lcp->his_callback.msg - 1;
1117134833Smarcel            log_Printf(LogWARN, "Truncating option arg to %zu octets\n", sz);
111838174Sbrian          }
111994894Sbrian          memcpy(lcp->his_callback.msg, opt->data + 1, sz);
112094894Sbrian          lcp->his_callback.msg[sz] = '\0';
112194894Sbrian          fsm_ack(dec, opt);
112238174Sbrian        } else if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) &&
112338174Sbrian                    p->link.lcp.auth_ineed) {
112494894Sbrian          nak.data[0] = CALLBACK_AUTH;
112594894Sbrian          fsm_nak(dec, &nak);
112638174Sbrian        } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) {
112794894Sbrian          nak.data[0] = CALLBACK_CBCP;
112894894Sbrian          fsm_nak(dec, &nak);
112938174Sbrian        } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) {
113094894Sbrian          nak.data[0] = CALLBACK_E164;
113194894Sbrian          fsm_nak(dec, &nak);
113238174Sbrian        } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) {
113338174Sbrian          log_Printf(LogWARN, "Cannot insist on auth callback without"
113438174Sbrian                     " PAP or CHAP enabled !\n");
113594894Sbrian          nak.data[0] = 2;
113694894Sbrian          fsm_nak(dec, &nak);
113794894Sbrian        } else {
113894894Sbrian          lcp->my_reject |= (1 << opt->hdr.id);
113994894Sbrian          fsm_rej(dec, opt);
114094894Sbrian        }
114138174Sbrian        break;
114238174Sbrian      case MODE_NAK:
114342600Sbrian        /* We don't do what he NAKs with, we do things in our preferred order */
114438174Sbrian        if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH))
114538174Sbrian          lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_AUTH);
114638174Sbrian        else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP))
114738174Sbrian          lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_CBCP);
114838174Sbrian        else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164))
114938174Sbrian          lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_E164);
115038174Sbrian        if (lcp->want_callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) {
115138174Sbrian          log_Printf(LogPHASE, "Peer NAKd all callbacks, trying none\n");
115238174Sbrian          lcp->want_callback.opmask = 0;
115338174Sbrian        } else if (!lcp->want_callback.opmask) {
115438174Sbrian          log_Printf(LogPHASE, "Peer NAKd last configured callback\n");
115538174Sbrian          fsm_Close(&lcp->fsm);
115638174Sbrian        }
115738174Sbrian        break;
115838174Sbrian      case MODE_REJ:
115938174Sbrian        if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) {
116094894Sbrian          lcp->his_reject |= (1 << opt->hdr.id);
116138174Sbrian          lcp->want_callback.opmask = 0;
116238174Sbrian        } else {
116338174Sbrian          log_Printf(LogPHASE, "Peer rejected *required* callback\n");
116438174Sbrian          fsm_Close(&lcp->fsm);
116538174Sbrian        }
116694894Sbrian        break;
116738174Sbrian      }
116838174Sbrian      break;
116938174Sbrian
117036285Sbrian    case TY_SHORTSEQ:
117136285Sbrian      mp = &lcp->fsm.bundle->ncp.mp;
117236285Sbrian      log_Printf(LogLCP, "%s\n", request);
117336285Sbrian
117436285Sbrian      switch (mode_type) {
117536285Sbrian      case MODE_REQ:
117636285Sbrian        if (lcp->want_mrru && IsAccepted(mp->cfg.shortseq)) {
117736285Sbrian          lcp->his_shortseq = 1;
117894894Sbrian          fsm_ack(dec, opt);
117994894Sbrian        } else {
118094894Sbrian          fsm_rej(dec, opt);
118194894Sbrian          lcp->my_reject |= (1 << opt->hdr.id);
118294894Sbrian        }
118336285Sbrian        break;
118436285Sbrian      case MODE_NAK:
118536285Sbrian        /*
118636285Sbrian         * He's trying to get us to ask for short sequence numbers.
118736285Sbrian         * We ignore the NAK and honour our configuration file instead.
118836285Sbrian         */
118936285Sbrian        break;
119036285Sbrian      case MODE_REJ:
119194894Sbrian        lcp->his_reject |= (1 << opt->hdr.id);
119236285Sbrian        lcp->want_shortseq = 0;		/* For when we hit MP */
119394894Sbrian        break;
119436285Sbrian      }
119536285Sbrian      break;
119636285Sbrian
119736285Sbrian    case TY_ENDDISC:
119847859Sbrian      mp = &lcp->fsm.bundle->ncp.mp;
119936285Sbrian      log_Printf(LogLCP, "%s %s\n", request,
120094894Sbrian                 mp_Enddisc(opt->data[0], opt->data + 1, opt->hdr.len - 3));
120136285Sbrian      switch (mode_type) {
120236285Sbrian      case MODE_REQ:
120336285Sbrian        if (!p) {
120436285Sbrian          log_Printf(LogLCP, " ENDDISC rejected - not a physical link\n");
120594894Sbrian          fsm_rej(dec, opt);
120694894Sbrian          lcp->my_reject |= (1 << opt->hdr.id);
120794894Sbrian        } else if (!IsAccepted(mp->cfg.negenddisc)) {
120894894Sbrian          lcp->my_reject |= (1 << opt->hdr.id);
120994894Sbrian          fsm_rej(dec, opt);
1210134789Sbrian        } else if (opt->hdr.len < sizeof p->dl->peer.enddisc.address + 3 &&
121194894Sbrian                   opt->data[0] <= MAX_ENDDISC_CLASS) {
121294894Sbrian          p->dl->peer.enddisc.class = opt->data[0];
121394894Sbrian          p->dl->peer.enddisc.len = opt->hdr.len - 3;
121494894Sbrian          memcpy(p->dl->peer.enddisc.address, opt->data + 1, opt->hdr.len - 3);
121594894Sbrian          p->dl->peer.enddisc.address[opt->hdr.len - 3] = '\0';
121636285Sbrian          /* XXX: If mp->active, compare and NAK with mp->peer ? */
121794894Sbrian          fsm_ack(dec, opt);
121836285Sbrian        } else {
121994894Sbrian          if (opt->data[0] > MAX_ENDDISC_CLASS)
122036285Sbrian            log_Printf(LogLCP, " ENDDISC rejected - unrecognised class %d\n",
122194894Sbrian                      opt->data[0]);
122236285Sbrian          else
122337210Sbrian            log_Printf(LogLCP, " ENDDISC rejected - local max length is %ld\n",
122437210Sbrian                      (long)(sizeof p->dl->peer.enddisc.address - 1));
122594894Sbrian          fsm_rej(dec, opt);
122694894Sbrian          lcp->my_reject |= (1 << opt->hdr.id);
122736285Sbrian        }
122894894Sbrian        break;
122936285Sbrian
123047858Sbrian      case MODE_NAK:	/* Treat this as a REJ, we don't vary our disc (yet) */
123136285Sbrian      case MODE_REJ:
123294894Sbrian        lcp->his_reject |= (1 << opt->hdr.id);
123394894Sbrian        break;
123436285Sbrian      }
123536285Sbrian      break;
123698243Sbrian
12376059Samurai    default:
123831962Sbrian      sz = (sizeof desc - 2) / 2;
1239134789Sbrian      if (sz + 2 > opt->hdr.len)
124094894Sbrian        sz = opt->hdr.len - 2;
124131514Sbrian      pos = 0;
124231514Sbrian      desc[0] = sz ? ' ' : '\0';
124331514Sbrian      for (pos = 0; sz--; pos++)
124494894Sbrian        sprintf(desc+(pos<<1)+1, "%02x", opt->data[pos]);
124531514Sbrian
124636285Sbrian      log_Printf(LogLCP, "%s%s\n", request, desc);
124731514Sbrian
124831034Sbrian      if (mode_type == MODE_REQ) {
124994894Sbrian        fsm_rej(dec, opt);
125094894Sbrian        lcp->my_reject |= (1 << opt->hdr.id);
12516735Samurai      }
12526059Samurai      break;
12536059Samurai    }
12546059Samurai  }
125536285Sbrian
125636285Sbrian  if (mode_type != MODE_NOP) {
125738174Sbrian    if (mode_type == MODE_REQ && p && p->type == PHYS_DIRECT &&
125838174Sbrian        p->dl->cfg.callback.opmask && !callback_req &&
125938174Sbrian        !(p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))) {
126038174Sbrian      /* We *REQUIRE* that the peer requests callback */
126194894Sbrian      nak.hdr.id = TY_CALLBACK;
126294894Sbrian      nak.hdr.len = 3;
126338174Sbrian      if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) &&
126485095Sbrian          p->link.lcp.want_auth)
126594894Sbrian        nak.data[0] = CALLBACK_AUTH;
126638174Sbrian      else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP))
126794894Sbrian        nak.data[0] = CALLBACK_CBCP;
126838174Sbrian      else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164))
126994894Sbrian        nak.data[0] = CALLBACK_E164;
127038174Sbrian      else {
127138174Sbrian        log_Printf(LogWARN, "Cannot insist on auth callback without"
127238174Sbrian                   " PAP or CHAP enabled !\n");
127394894Sbrian        nak.hdr.len = 2;	/* XXX: Silly ! */
127438174Sbrian      }
127594894Sbrian      fsm_nak(dec, &nak);
127638174Sbrian    }
127785094Sbrian    if (mode_type == MODE_REQ && !lcp->mru_req) {
127878410Sbrian      mru = DEF_MRU;
127978410Sbrian      phmtu = p ? physical_DeviceMTU(p) : 0;
128078410Sbrian      if (phmtu && mru > phmtu)
128178410Sbrian        mru = phmtu;
128278410Sbrian      if (mru > lcp->cfg.max_mtu)
128378410Sbrian        mru = lcp->cfg.max_mtu;
128478410Sbrian      if (mru < DEF_MRU) {
128578410Sbrian        /* Don't let the peer use the default MRU */
128678410Sbrian        lcp->his_mru = lcp->cfg.mtu && lcp->cfg.mtu < mru ? lcp->cfg.mtu : mru;
128794894Sbrian        nak.hdr.id = TY_MRU;
128894894Sbrian        nak.hdr.len = 4;
128994894Sbrian        ua_htons(&lcp->his_mru, nak.data);
129094894Sbrian        fsm_nak(dec, &nak);
129185094Sbrian        lcp->mru_req = 1;	/* Don't keep NAK'ing this */
129278410Sbrian      }
129378410Sbrian    }
129494894Sbrian    fsm_opt_normalise(dec);
129536285Sbrian  }
12966059Samurai}
12976059Samurai
129846686Sbrianextern struct mbuf *
1299134789Sbrianlcp_Input(struct bundle *bundle __unused, struct link *l, struct mbuf *bp)
13006059Samurai{
130136285Sbrian  /* Got PROTO_LCP from link */
130254912Sbrian  m_settype(bp, MB_LCPIN);
130346686Sbrian  fsm_Input(&l->lcp.fsm, bp);
130446686Sbrian  return NULL;
13056059Samurai}
1306