lcp.c revision 44305
11573Srgrimes/*
21573Srgrimes *	      PPP Link Control Protocol (LCP) Module
31573Srgrimes *
41573Srgrimes *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
51573Srgrimes *
61573Srgrimes *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms are permitted
91573Srgrimes * provided that the above copyright notice and this paragraph are
101573Srgrimes * duplicated in all such forms and that any documentation,
111573Srgrimes * advertising materials, and other materials related to such
121573Srgrimes * distribution and use acknowledge that the software was developed
131573Srgrimes * by the Internet Initiative Japan, Inc.  The name of the
141573Srgrimes * IIJ may not be used to endorse or promote products derived
151573Srgrimes * from this software without specific prior written permission.
161573Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
171573Srgrimes * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
181573Srgrimes * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
191573Srgrimes *
201573Srgrimes * $Id: lcp.c,v 1.68 1999/02/18 00:52:14 brian Exp $
211573Srgrimes *
221573Srgrimes * TODO:
231573Srgrimes *	o Limit data field length by MRU
241573Srgrimes */
251573Srgrimes
261573Srgrimes#include <sys/param.h>
271573Srgrimes#include <netinet/in.h>
281573Srgrimes#include <netinet/in_systm.h>
291573Srgrimes#include <netinet/ip.h>
301573Srgrimes#include <sys/un.h>
311573Srgrimes
321573Srgrimes#include <signal.h>
331573Srgrimes#include <stdio.h>
341573Srgrimes#include <stdlib.h>
351573Srgrimes#include <string.h>
3692986Sobrien#include <termios.h>
3792986Sobrien#include <unistd.h>
381573Srgrimes
3971579Sdeischen#include "ua.h"
401573Srgrimes#include "defs.h"
411573Srgrimes#include "command.h"
4271579Sdeischen#include "mbuf.h"
4371579Sdeischen#include "log.h"
441573Srgrimes#include "timer.h"
451573Srgrimes#include "fsm.h"
4672373Sdeischen#include "iplist.h"
4772373Sdeischen#include "lcp.h"
4871579Sdeischen#include "throughput.h"
4971579Sdeischen#include "lcpproto.h"
5071579Sdeischen#include "descriptor.h"
5171579Sdeischen#include "lqr.h"
5213545Sjulian#include "hdlc.h"
5371579Sdeischen#include "ccp.h"
541573Srgrimes#include "async.h"
5513545Sjulian#include "link.h"
561573Srgrimes#include "physical.h"
571573Srgrimes#include "prompt.h"
5872373Sdeischen#include "slcompress.h"
5935129Sjb#include "ipcp.h"
60131592Scperciva#include "filter.h"
61131592Scperciva#include "mp.h"
62131592Scperciva#include "chat.h"
63131592Scperciva#include "auth.h"
64131592Scperciva#include "chap.h"
65131592Scperciva#include "cbcp.h"
66131592Scperciva#include "datalink.h"
67131592Scperciva#ifndef NORADIUS
68131592Scperciva#include "radius.h"
69131592Scperciva#endif
70131592Scperciva#include "bundle.h"
71131592Scperciva
721573Srgrimes/* for received LQRs */
731573Srgrimesstruct lqrreq {
7413545Sjulian  u_char type;
7571579Sdeischen  u_char length;
7613545Sjulian  u_short proto;		/* Quality protocol */
7735129Sjb  u_int32_t period;		/* Reporting interval */
7813545Sjulian};
791573Srgrimes
801573Srgrimesstatic int LcpLayerUp(struct fsm *);
8171579Sdeischenstatic void LcpLayerDown(struct fsm *);
8271579Sdeischenstatic void LcpLayerStart(struct fsm *);
8371579Sdeischenstatic void LcpLayerFinish(struct fsm *);
8471579Sdeischenstatic void LcpInitRestartCounter(struct fsm *, int);
8513545Sjulianstatic void LcpSendConfigReq(struct fsm *);
8671579Sdeischenstatic void LcpSentTerminateReq(struct fsm *);
871573Srgrimesstatic void LcpSendTerminateAck(struct fsm *, u_char);
8871579Sdeischenstatic void LcpDecodeConfig(struct fsm *, u_char *, int, int,
891573Srgrimes                            struct fsm_decode *);
9071579Sdeischen
9172373Sdeischenstatic struct fsm_callbacks lcp_Callbacks = {
9271579Sdeischen  LcpLayerUp,
9371579Sdeischen  LcpLayerDown,
9471579Sdeischen  LcpLayerStart,
9571579Sdeischen  LcpLayerFinish,
9671579Sdeischen  LcpInitRestartCounter,
9771579Sdeischen  LcpSendConfigReq,
9871579Sdeischen  LcpSentTerminateReq,
9971579Sdeischen  LcpSendTerminateAck,
10071579Sdeischen  LcpDecodeConfig,
10171579Sdeischen  fsm_NullRecvResetReq,
10271579Sdeischen  fsm_NullRecvResetAck
10371579Sdeischen};
10471579Sdeischen
10571579Sdeischenstatic const char *lcp_TimerNames[] =
1061573Srgrimes  {"LCP restart", "LCP openmode", "LCP stopped"};
1071573Srgrimes
1081573Srgrimesstatic const char *cftypes[] = {
1091573Srgrimes  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
1101573Srgrimes  "???",
1111573Srgrimes  "MRU",	/* 1: Maximum-Receive-Unit */
1121573Srgrimes  "ACCMAP",	/* 2: Async-Control-Character-Map */
1131573Srgrimes  "AUTHPROTO",	/* 3: Authentication-Protocol */
1141573Srgrimes  "QUALPROTO",	/* 4: Quality-Protocol */
1151573Srgrimes  "MAGICNUM",	/* 5: Magic-Number */
1161573Srgrimes  "RESERVED",	/* 6: RESERVED */
1171573Srgrimes  "PROTOCOMP",	/* 7: Protocol-Field-Compression */
1181573Srgrimes  "ACFCOMP",	/* 8: Address-and-Control-Field-Compression */
1191573Srgrimes  "FCSALT",	/* 9: FCS-Alternatives */
1201573Srgrimes  "SDP",	/* 10: Self-Describing-Pad */
1211573Srgrimes  "NUMMODE",	/* 11: Numbered-Mode */
1221573Srgrimes  "MULTIPROC",	/* 12: Multi-Link-Procedure */
12382838Sache  "CALLBACK",	/* 13: Callback */
1241573Srgrimes  "CONTIME",	/* 14: Connect-Time */
1251573Srgrimes  "COMPFRAME",	/* 15: Compound-Frames */
1261573Srgrimes  "NDE",	/* 16: Nominal-Data-Encapsulation */
1271573Srgrimes  "MRRU",	/* 17: Multilink-MRRU */
1281573Srgrimes  "SHORTSEQ",	/* 18: Multilink-Short-Sequence-Number-Header */
1291573Srgrimes  "ENDDISC",	/* 19: Multilink-Endpoint-Discriminator */
1301573Srgrimes  "PROPRIETRY",	/* 20: Proprietary */
13172373Sdeischen  "DCEID",	/* 21: DCE-Identifier */
13272373Sdeischen  "MULTIPP",	/* 22: Multi-Link-Plus-Procedure */
13372373Sdeischen  "LDBACP",	/* 23: Link Discriminator for BACP */
13472373Sdeischen};
13572373Sdeischen
13672373Sdeischen#define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
13772373Sdeischen
13872373Sdeischenint
13972373Sdeischenlcp_ReportStatus(struct cmdargs const *arg)
14072373Sdeischen{
14172373Sdeischen  struct link *l;
142  struct lcp *lcp;
143
144  l = command_ChooseLink(arg);
145  lcp = &l->lcp;
146
147  prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, lcp->fsm.name,
148                State2Nam(lcp->fsm.state));
149  prompt_Printf(arg->prompt,
150	        " his side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n"
151	        "           MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n",
152	        lcp->his_mru, (u_long)lcp->his_accmap,
153                lcp->his_protocomp ? "on" : "off",
154                lcp->his_acfcomp ? "on" : "off",
155                (u_long)lcp->his_magic, lcp->his_mrru,
156                lcp->his_shortseq ? "on" : "off", lcp->his_reject);
157  prompt_Printf(arg->prompt,
158	        " my  side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n"
159                "           MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n",
160                lcp->want_mru, (u_long)lcp->want_accmap,
161                lcp->want_protocomp ? "on" : "off",
162                lcp->want_acfcomp ? "on" : "off",
163                (u_long)lcp->want_magic, lcp->want_mrru,
164                lcp->want_shortseq ? "on" : "off", lcp->my_reject);
165
166  prompt_Printf(arg->prompt, "\n Defaults: MRU = %d, ", lcp->cfg.mru);
167  prompt_Printf(arg->prompt, "ACCMAP = %08lx\n", (u_long)lcp->cfg.accmap);
168  prompt_Printf(arg->prompt, "           LQR period = %us, ",
169                lcp->cfg.lqrperiod);
170  prompt_Printf(arg->prompt, "Open Mode = %s",
171                lcp->cfg.openmode == OPEN_PASSIVE ? "passive" : "active");
172  if (lcp->cfg.openmode > 0)
173    prompt_Printf(arg->prompt, " (delay %ds)", lcp->cfg.openmode);
174  prompt_Printf(arg->prompt, "\n           FSM retry = %us, max %u Config"
175                " REQ%s, %u Term REQ%s\n", lcp->cfg.fsm.timeout,
176                lcp->cfg.fsm.maxreq, lcp->cfg.fsm.maxreq == 1 ? "" : "s",
177                lcp->cfg.fsm.maxtrm, lcp->cfg.fsm.maxtrm == 1 ? "" : "s");
178  prompt_Printf(arg->prompt, "\n Negotiation:\n");
179  prompt_Printf(arg->prompt, "           ACFCOMP =   %s\n",
180                command_ShowNegval(lcp->cfg.acfcomp));
181  prompt_Printf(arg->prompt, "           CHAP =      %s\n",
182                command_ShowNegval(lcp->cfg.chap05));
183#ifdef HAVE_DES
184  prompt_Printf(arg->prompt, "           MSCHAP =    %s\n",
185                command_ShowNegval(lcp->cfg.chap80nt));
186  prompt_Printf(arg->prompt, "           LANMan =    %s\n",
187                command_ShowNegval(lcp->cfg.chap80lm));
188#endif
189  prompt_Printf(arg->prompt, "           LQR =       %s\n",
190                command_ShowNegval(lcp->cfg.lqr));
191  prompt_Printf(arg->prompt, "           PAP =       %s\n",
192                command_ShowNegval(lcp->cfg.pap));
193  prompt_Printf(arg->prompt, "           PROTOCOMP = %s\n",
194                command_ShowNegval(lcp->cfg.protocomp));
195
196  return 0;
197}
198
199static u_int32_t
200GenerateMagic(void)
201{
202  /* Generate random number which will be used as magic number */
203  randinit();
204  return random();
205}
206
207void
208lcp_SetupCallbacks(struct lcp *lcp)
209{
210  lcp->fsm.fn = &lcp_Callbacks;
211  lcp->fsm.FsmTimer.name = lcp_TimerNames[0];
212  lcp->fsm.OpenTimer.name = lcp_TimerNames[1];
213  lcp->fsm.StoppedTimer.name = lcp_TimerNames[2];
214}
215
216void
217lcp_Init(struct lcp *lcp, struct bundle *bundle, struct link *l,
218         const struct fsm_parent *parent)
219{
220  /* Initialise ourselves */
221  int mincode = parent ? 1 : LCP_MINMPCODE;
222
223  fsm_Init(&lcp->fsm, "LCP", PROTO_LCP, mincode, LCP_MAXCODE, LogLCP,
224           bundle, l, parent, &lcp_Callbacks, lcp_TimerNames);
225
226  lcp->cfg.mru = DEF_MRU;
227  lcp->cfg.accmap = 0;
228  lcp->cfg.openmode = 1;
229  lcp->cfg.lqrperiod = DEF_LQRPERIOD;
230  lcp->cfg.fsm.timeout = DEF_FSMRETRY;
231  lcp->cfg.fsm.maxreq = DEF_FSMTRIES;
232  lcp->cfg.fsm.maxtrm = DEF_FSMTRIES;
233
234  lcp->cfg.acfcomp = NEG_ENABLED|NEG_ACCEPTED;
235  lcp->cfg.chap05 = NEG_ACCEPTED;
236#ifdef HAVE_DES
237  lcp->cfg.chap80nt = NEG_ACCEPTED;
238  lcp->cfg.chap80lm = NEG_ACCEPTED;
239#endif
240  lcp->cfg.lqr = NEG_ACCEPTED;
241  lcp->cfg.pap = NEG_ACCEPTED;
242  lcp->cfg.protocomp = NEG_ENABLED|NEG_ACCEPTED;
243
244  lcp_Setup(lcp, lcp->cfg.openmode);
245}
246
247void
248lcp_Setup(struct lcp *lcp, int openmode)
249{
250  lcp->fsm.open_mode = openmode;
251
252  lcp->his_mru = lcp->fsm.bundle->cfg.mtu;
253  if (!lcp->his_mru || lcp->his_mru > DEF_MRU)
254    lcp->his_mru = DEF_MRU;
255  lcp->his_mrru = 0;
256  lcp->his_magic = 0;
257  lcp->his_lqrperiod = 0;
258  lcp->his_acfcomp = 0;
259  lcp->his_auth = 0;
260  lcp->his_authtype = 0;
261  lcp->his_callback.opmask = 0;
262  lcp->his_shortseq = 0;
263
264  lcp->want_mru = lcp->cfg.mru;
265  lcp->want_mrru = lcp->fsm.bundle->ncp.mp.cfg.mrru;
266  lcp->want_shortseq = IsEnabled(lcp->fsm.bundle->ncp.mp.cfg.shortseq) ? 1 : 0;
267  lcp->want_acfcomp = IsEnabled(lcp->cfg.acfcomp) ? 1 : 0;
268
269  if (lcp->fsm.parent) {
270    struct physical *p = link2physical(lcp->fsm.link);
271
272    lcp->his_accmap = 0xffffffff;
273    lcp->want_accmap = lcp->cfg.accmap;
274    lcp->his_protocomp = 0;
275    lcp->want_protocomp = IsEnabled(lcp->cfg.protocomp) ? 1 : 0;
276    lcp->want_magic = GenerateMagic();
277
278    if (IsEnabled(lcp->cfg.chap05)) {
279      lcp->want_auth = PROTO_CHAP;
280      lcp->want_authtype = 0x05;
281#ifdef HAVE_DES
282    } else if (IsEnabled(lcp->cfg.chap80nt) ||
283               IsEnabled(lcp->cfg.chap80lm)) {
284      lcp->want_auth = PROTO_CHAP;
285      lcp->want_authtype = 0x80;
286#endif
287    } else if (IsEnabled(lcp->cfg.pap)) {
288      lcp->want_auth = PROTO_PAP;
289      lcp->want_authtype = 0;
290    } else {
291      lcp->want_auth = 0;
292      lcp->want_authtype = 0;
293    }
294
295    if (p->type != PHYS_DIRECT)
296      memcpy(&lcp->want_callback, &p->dl->cfg.callback, sizeof(struct callback));
297    else
298      lcp->want_callback.opmask = 0;
299    lcp->want_lqrperiod = IsEnabled(lcp->cfg.lqr) ?
300                          lcp->cfg.lqrperiod * 100 : 0;
301  } else {
302    lcp->his_accmap = lcp->want_accmap = 0;
303    lcp->his_protocomp = lcp->want_protocomp = 1;
304    lcp->want_magic = 0;
305    lcp->want_auth = 0;
306    lcp->want_authtype = 0;
307    lcp->want_callback.opmask = 0;
308    lcp->want_lqrperiod = 0;
309  }
310
311  lcp->his_reject = lcp->my_reject = 0;
312  lcp->auth_iwait = lcp->auth_ineed = 0;
313  lcp->LcpFailedMagic = 0;
314}
315
316static void
317LcpInitRestartCounter(struct fsm *fp, int what)
318{
319  /* Set fsm timer load */
320  struct lcp *lcp = fsm2lcp(fp);
321
322  fp->FsmTimer.load = lcp->cfg.fsm.timeout * SECTICKS;
323  switch (what) {
324    case FSM_REQ_TIMER:
325      fp->restart = lcp->cfg.fsm.maxreq;
326      break;
327    case FSM_TRM_TIMER:
328      fp->restart = lcp->cfg.fsm.maxtrm;
329      break;
330    default:
331      fp->restart = 1;
332      break;
333  }
334}
335
336static void
337LcpSendConfigReq(struct fsm *fp)
338{
339  /* Send config REQ please */
340  struct physical *p = link2physical(fp->link);
341  struct lcp *lcp = fsm2lcp(fp);
342  u_char buff[200];
343  struct lcp_opt *o;
344  struct mp *mp;
345  u_int16_t proto;
346
347  if (!p) {
348    log_Printf(LogERROR, "%s: LcpSendConfigReq: Not a physical link !\n",
349              fp->link->name);
350    return;
351  }
352
353  o = (struct lcp_opt *)buff;
354  if (!physical_IsSync(p)) {
355    if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP))
356      INC_LCP_OPT(TY_ACFCOMP, 2, o);
357
358    if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP))
359      INC_LCP_OPT(TY_PROTOCOMP, 2, o);
360
361    if (!REJECTED(lcp, TY_ACCMAP)) {
362      ua_htonl(&lcp->want_accmap, o->data);
363      INC_LCP_OPT(TY_ACCMAP, 6, o);
364    }
365  }
366
367  if (!REJECTED(lcp, TY_MRU)) {
368    ua_htons(&lcp->want_mru, o->data);
369    INC_LCP_OPT(TY_MRU, 4, o);
370  }
371
372  if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM)) {
373    ua_htonl(&lcp->want_magic, o->data);
374    INC_LCP_OPT(TY_MAGICNUM, 6, o);
375  }
376
377  if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) {
378    proto = PROTO_LQR;
379    ua_htons(&proto, o->data);
380    ua_htonl(&lcp->want_lqrperiod, o->data + 2);
381    INC_LCP_OPT(TY_QUALPROTO, 8, o);
382  }
383
384  switch (lcp->want_auth) {
385  case PROTO_PAP:
386    proto = PROTO_PAP;
387    ua_htons(&proto, o->data);
388    INC_LCP_OPT(TY_AUTHPROTO, 4, o);
389    break;
390
391  case PROTO_CHAP:
392    proto = PROTO_CHAP;
393    ua_htons(&proto, o->data);
394    o->data[2] = lcp->want_authtype;
395    INC_LCP_OPT(TY_AUTHPROTO, 5, o);
396    break;
397  }
398
399  if (!REJECTED(lcp, TY_CALLBACK)) {
400    if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) {
401      *o->data = CALLBACK_AUTH;
402      INC_LCP_OPT(TY_CALLBACK, 3, o);
403    } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) {
404      *o->data = CALLBACK_CBCP;
405      INC_LCP_OPT(TY_CALLBACK, 3, o);
406    } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164)) {
407      int sz = strlen(lcp->want_callback.msg);
408
409      if (sz > sizeof o->data - 1) {
410        sz = sizeof o->data - 1;
411        log_Printf(LogWARN, "Truncating E164 data to %d octets (oops!)\n", sz);
412      }
413      *o->data = CALLBACK_E164;
414      memcpy(o->data + 1, lcp->want_callback.msg, sz);
415      INC_LCP_OPT(TY_CALLBACK, sz + 3, o);
416    }
417  }
418
419  if (lcp->want_mrru && !REJECTED(lcp, TY_MRRU)) {
420    ua_htons(&lcp->want_mrru, o->data);
421    INC_LCP_OPT(TY_MRRU, 4, o);
422
423    if (lcp->want_shortseq && !REJECTED(lcp, TY_SHORTSEQ))
424      INC_LCP_OPT(TY_SHORTSEQ, 2, o);
425  }
426
427  mp = &lcp->fsm.bundle->ncp.mp;
428  if (mp->cfg.enddisc.class != 0 && !REJECTED(lcp, TY_ENDDISC)) {
429    *o->data = mp->cfg.enddisc.class;
430    memcpy(o->data+1, mp->cfg.enddisc.address, mp->cfg.enddisc.len);
431    INC_LCP_OPT(TY_ENDDISC, mp->cfg.enddisc.len + 3, o);
432  }
433
434  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff);
435}
436
437void
438lcp_SendProtoRej(struct lcp *lcp, u_char *option, int count)
439{
440  /* Don't understand `option' */
441  fsm_Output(&lcp->fsm, CODE_PROTOREJ, lcp->fsm.reqid, option, count);
442}
443
444static void
445LcpSentTerminateReq(struct fsm *fp)
446{
447  /* Term REQ just sent by FSM */
448}
449
450static void
451LcpSendTerminateAck(struct fsm *fp, u_char id)
452{
453  /* Send Term ACK please */
454  struct physical *p = link2physical(fp->link);
455
456  if (p && p->dl->state == DATALINK_CBCP)
457    cbcp_ReceiveTerminateReq(p);
458
459  fsm_Output(fp, CODE_TERMACK, id, NULL, 0);
460}
461
462static void
463LcpLayerStart(struct fsm *fp)
464{
465  /* We're about to start up ! */
466  struct lcp *lcp = fsm2lcp(fp);
467
468  log_Printf(LogLCP, "%s: LayerStart\n", fp->link->name);
469  lcp->LcpFailedMagic = 0;
470  fp->more.reqs = fp->more.naks = fp->more.rejs = lcp->cfg.fsm.maxreq * 3;
471}
472
473static void
474LcpLayerFinish(struct fsm *fp)
475{
476  /* We're now down */
477  log_Printf(LogLCP, "%s: LayerFinish\n", fp->link->name);
478}
479
480static int
481LcpLayerUp(struct fsm *fp)
482{
483  /* We're now up */
484  struct physical *p = link2physical(fp->link);
485  struct lcp *lcp = fsm2lcp(fp);
486
487  log_Printf(LogLCP, "%s: LayerUp\n", fp->link->name);
488  async_SetLinkParams(&p->async, lcp);
489  lqr_Start(lcp);
490  hdlc_StartTimer(&p->hdlc);
491  fp->more.reqs = fp->more.naks = fp->more.rejs = lcp->cfg.fsm.maxreq * 3;
492
493  return 1;
494}
495
496static void
497LcpLayerDown(struct fsm *fp)
498{
499  /* About to come down */
500  struct physical *p = link2physical(fp->link);
501
502  log_Printf(LogLCP, "%s: LayerDown\n", fp->link->name);
503  hdlc_StopTimer(&p->hdlc);
504  lqr_StopTimer(p);
505  lcp_Setup(fsm2lcp(fp), 0);
506}
507
508static int
509E164ok(struct callback *cb, char *req, int sz)
510{
511  char list[sizeof cb->msg], *next;
512  int len;
513
514  if (!strcmp(cb->msg, "*"))
515    return 1;
516
517  strncpy(list, cb->msg, sizeof list - 1);
518  list[sizeof list - 1] = '\0';
519  for (next = strtok(list, ","); next; next = strtok(NULL, ",")) {
520    len = strlen(next);
521    if (sz == len && !memcmp(list, req, sz))
522      return 1;
523  }
524  return 0;
525}
526
527static void
528LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
529                struct fsm_decode *dec)
530{
531  /* Deal with incoming PROTO_LCP */
532  struct lcp *lcp = fsm2lcp(fp);
533  int type, length, sz, pos, op, callback_req;
534  u_int32_t magic, accmap;
535  u_short mtu, mru, proto;
536  struct lqrreq *req;
537  char request[20], desc[22];
538  struct mp *mp;
539  struct physical *p = link2physical(fp->link);
540
541  callback_req = 0;
542
543  while (plen >= sizeof(struct fsmconfig)) {
544    type = *cp;
545    length = cp[1];
546
547    if (type < 0 || type >= NCFTYPES)
548      snprintf(request, sizeof request, " <%d>[%d]", type, length);
549    else
550      snprintf(request, sizeof request, " %s[%d]", cftypes[type], length);
551
552    if (length < 2) {
553      log_Printf(LogLCP, "%s:%s: Bad LCP length\n", fp->link->name, request);
554      break;
555    }
556
557    switch (type) {
558    case TY_MRRU:
559      mp = &lcp->fsm.bundle->ncp.mp;
560      ua_ntohs(cp + 2, &mru);
561      log_Printf(LogLCP, "%s %u\n", request, mru);
562
563      switch (mode_type) {
564      case MODE_REQ:
565        if (mp->cfg.mrru) {
566          if (REJECTED(lcp, TY_MRRU))
567            /* Ignore his previous reject so that we REQ next time */
568	    lcp->his_reject &= ~(1 << type);
569
570          mtu = lcp->fsm.bundle->cfg.mtu;
571          if (mru < MIN_MRU || mru < mtu) {
572            /* Push him up to MTU or MIN_MRU */
573            lcp->his_mrru = mru < mtu ? mtu : MIN_MRU;
574	    memcpy(dec->nakend, cp, 2);
575            ua_htons(&lcp->his_mrru, dec->nakend + 2);
576	    dec->nakend += 4;
577	  } else {
578            lcp->his_mrru = mtu ? mtu : mru;
579	    memcpy(dec->ackend, cp, 4);
580	    dec->ackend += 4;
581	  }
582	  break;
583        } else
584	  goto reqreject;
585        break;
586      case MODE_NAK:
587        if (mp->cfg.mrru) {
588          if (REJECTED(lcp, TY_MRRU))
589            /* Must have changed his mind ! */
590	    lcp->his_reject &= ~(1 << type);
591
592          if (mru > MAX_MRU)
593            lcp->want_mrru = MAX_MRU;
594          else if (mru < MIN_MRU)
595            lcp->want_mrru = MIN_MRU;
596          else
597            lcp->want_mrru = mru;
598        }
599        /* else we honour our config and don't send the suggested REQ */
600        break;
601      case MODE_REJ:
602	lcp->his_reject |= (1 << type);
603        lcp->want_mrru = 0;		/* Ah well, no multilink :-( */
604	break;
605      }
606      break;
607
608    case TY_MRU:
609      ua_ntohs(cp + 2, &mru);
610      log_Printf(LogLCP, "%s %d\n", request, mru);
611
612      switch (mode_type) {
613      case MODE_REQ:
614        mtu = lcp->fsm.bundle->cfg.mtu;
615        if (mru < MIN_MRU || (!lcp->want_mrru && mru < mtu)) {
616          /* Push him up to MTU or MIN_MRU */
617          lcp->his_mru = mru < mtu ? mtu : MIN_MRU;
618          memcpy(dec->nakend, cp, 2);
619          ua_htons(&lcp->his_mru, dec->nakend + 2);
620          dec->nakend += 4;
621        } else {
622          lcp->his_mru = mtu ? mtu : mru;
623          memcpy(dec->ackend, cp, 4);
624          dec->ackend += 4;
625        }
626	break;
627      case MODE_NAK:
628        if (mru > MAX_MRU)
629          lcp->want_mru = MAX_MRU;
630        else if (mru < MIN_MRU)
631          lcp->want_mru = MIN_MRU;
632        else
633          lcp->want_mru = mru;
634	break;
635      case MODE_REJ:
636	lcp->his_reject |= (1 << type);
637	break;
638      }
639      break;
640
641    case TY_ACCMAP:
642      ua_ntohl(cp + 2, &accmap);
643      log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)accmap);
644
645      switch (mode_type) {
646      case MODE_REQ:
647	lcp->his_accmap = accmap;
648	memcpy(dec->ackend, cp, 6);
649	dec->ackend += 6;
650	break;
651      case MODE_NAK:
652	lcp->want_accmap = accmap;
653	break;
654      case MODE_REJ:
655	lcp->his_reject |= (1 << type);
656	break;
657      }
658      break;
659
660    case TY_AUTHPROTO:
661      ua_ntohs(cp + 2, &proto);
662      log_Printf(LogLCP, "%s 0x%04x (%s)\n", request, proto,
663                 Auth2Nam(proto, length > 4 ? cp[4] : 0));
664
665      switch (mode_type) {
666      case MODE_REQ:
667	switch (proto) {
668	case PROTO_PAP:
669	  if (length != 4) {
670	    log_Printf(LogLCP, " Bad length!\n");
671	    goto reqreject;
672	  }
673	  if (IsAccepted(lcp->cfg.pap)) {
674	    lcp->his_auth = proto;
675	    lcp->his_authtype = 0;
676	    memcpy(dec->ackend, cp, length);
677	    dec->ackend += length;
678	  } else if (IsAccepted(lcp->cfg.chap05)) {
679	    *dec->nakend++ = *cp;
680	    *dec->nakend++ = 5;
681	    *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
682	    *dec->nakend++ = (unsigned char) PROTO_CHAP;
683	    *dec->nakend++ = 0x05;
684#ifdef HAVE_DES
685	  } else if (IsAccepted(lcp->cfg.chap80nt) ||
686	             IsAccepted(lcp->cfg.chap80lm)) {
687	    *dec->nakend++ = *cp;
688	    *dec->nakend++ = 5;
689	    *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
690	    *dec->nakend++ = (unsigned char) PROTO_CHAP;
691	    *dec->nakend++ = 0x80;
692#endif
693	  } else
694	    goto reqreject;
695	  break;
696
697	case PROTO_CHAP:
698	  if (length != 5) {
699	    log_Printf(LogLCP, " Bad length!\n");
700	    goto reqreject;
701	  }
702          if ((cp[4] == 0x05 && IsAccepted(lcp->cfg.chap05))
703#ifdef HAVE_DES
704              || (cp[4] == 0x80 && (IsAccepted(lcp->cfg.chap80nt) ||
705                                   (IsAccepted(lcp->cfg.chap80lm))))
706#endif
707             ) {
708	    lcp->his_auth = proto;
709	    lcp->his_authtype = cp[4];
710	    memcpy(dec->ackend, cp, length);
711	    dec->ackend += length;
712	  } else {
713#ifndef HAVE_DES
714            if (cp[4] == 0x80)
715              log_Printf(LogWARN, "CHAP 0x80 not available without DES\n");
716            else
717#endif
718            if (cp[4] != 0x05)
719              log_Printf(LogWARN, "%s not supported\n",
720                         Auth2Nam(PROTO_CHAP, cp[4]));
721
722            if (IsAccepted(lcp->cfg.chap05)) {
723	      *dec->nakend++ = *cp;
724	      *dec->nakend++ = 5;
725	      *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
726	      *dec->nakend++ = (unsigned char) PROTO_CHAP;
727	      *dec->nakend++ = 0x05;
728#ifdef HAVE_DES
729            } else if (IsAccepted(lcp->cfg.chap80nt) ||
730                       IsAccepted(lcp->cfg.chap80lm)) {
731	      *dec->nakend++ = *cp;
732	      *dec->nakend++ = 5;
733	      *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
734	      *dec->nakend++ = (unsigned char) PROTO_CHAP;
735	      *dec->nakend++ = 0x80;
736#endif
737            } else if (IsAccepted(lcp->cfg.pap)) {
738	      *dec->nakend++ = *cp;
739	      *dec->nakend++ = 4;
740	      *dec->nakend++ = (unsigned char) (PROTO_PAP >> 8);
741	      *dec->nakend++ = (unsigned char) PROTO_PAP;
742	    } else
743	      goto reqreject;
744          }
745	  break;
746
747	default:
748          log_Printf(LogLCP, "%s 0x%04x - not recognised, NAK\n",
749                    request, proto);
750	  memcpy(dec->nakend, cp, length);
751	  dec->nakend += length;
752	  break;
753	}
754	break;
755      case MODE_NAK:
756	switch (proto) {
757	case PROTO_PAP:
758          if (IsEnabled(lcp->cfg.pap)) {
759            lcp->want_auth = PROTO_PAP;
760            lcp->want_authtype = 0;
761          } else {
762            log_Printf(LogLCP, "Peer will only send PAP (not enabled)\n");
763	    lcp->his_reject |= (1 << type);
764          }
765          break;
766	case PROTO_CHAP:
767          if (cp[4] == 0x05 && IsEnabled(lcp->cfg.chap05)) {
768            lcp->want_auth = PROTO_CHAP;
769            lcp->want_authtype = 0x05;
770#ifdef HAVE_DES
771          } else if (cp[4] == 0x80 && (IsEnabled(lcp->cfg.chap80nt) ||
772                                       IsEnabled(lcp->cfg.chap80lm))) {
773            lcp->want_auth = PROTO_CHAP;
774            lcp->want_authtype = 0x80;
775#endif
776          } else {
777#ifndef HAVE_DES
778            if (cp[4] == 0x80)
779              log_Printf(LogLCP, "Peer will only send MSCHAP (not available"
780                         " without DES)\n");
781            else
782#endif
783            log_Printf(LogLCP, "Peer will only send %s (not %s)\n",
784                       Auth2Nam(PROTO_CHAP, cp[4]),
785#ifdef HAVE_DES
786                       cp[4] == 0x80 ? "configured" :
787#endif
788                       "supported");
789	    lcp->his_reject |= (1 << type);
790          }
791          break;
792        default:
793          /* We've been NAK'd with something we don't understand :-( */
794	  lcp->his_reject |= (1 << type);
795          break;
796        }
797	break;
798      case MODE_REJ:
799	lcp->his_reject |= (1 << type);
800	break;
801      }
802      break;
803
804    case TY_QUALPROTO:
805      req = (struct lqrreq *)cp;
806      log_Printf(LogLCP, "%s proto %x, interval %lums\n",
807                request, ntohs(req->proto), (u_long)ntohl(req->period) * 10);
808      switch (mode_type) {
809      case MODE_REQ:
810	if (ntohs(req->proto) != PROTO_LQR || !IsAccepted(lcp->cfg.lqr))
811	  goto reqreject;
812	else {
813	  lcp->his_lqrperiod = ntohl(req->period);
814	  if (lcp->his_lqrperiod < MIN_LQRPERIOD * 100)
815	    lcp->his_lqrperiod = MIN_LQRPERIOD * 100;
816	  req->period = htonl(lcp->his_lqrperiod);
817	  memcpy(dec->ackend, cp, length);
818	  dec->ackend += length;
819	}
820	break;
821      case MODE_NAK:
822	break;
823      case MODE_REJ:
824	lcp->his_reject |= (1 << type);
825	break;
826      }
827      break;
828
829    case TY_MAGICNUM:
830      ua_ntohl(cp + 2, &magic);
831      log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)magic);
832
833      switch (mode_type) {
834      case MODE_REQ:
835	if (lcp->want_magic) {
836	  /* Validate magic number */
837	  if (magic == lcp->want_magic) {
838	    log_Printf(LogLCP, "Magic is same (%08lx) - %d times\n",
839                      (u_long)magic, ++lcp->LcpFailedMagic);
840	    lcp->want_magic = GenerateMagic();
841	    memcpy(dec->nakend, cp, 6);
842	    dec->nakend += 6;
843            ualarm(TICKUNIT * (4 + 4 * lcp->LcpFailedMagic), 0);
844            sigpause(0);
845	  } else {
846	    lcp->his_magic = magic;
847	    memcpy(dec->ackend, cp, length);
848	    dec->ackend += length;
849            lcp->LcpFailedMagic = 0;
850	  }
851	} else {
852	  goto reqreject;
853	}
854	break;
855      case MODE_NAK:
856	log_Printf(LogLCP, " Magic 0x%08lx is NAKed!\n", (u_long)magic);
857	lcp->want_magic = GenerateMagic();
858	break;
859      case MODE_REJ:
860	log_Printf(LogLCP, " Magic 0x%08x is REJected!\n", magic);
861	lcp->want_magic = 0;
862	lcp->his_reject |= (1 << type);
863	break;
864      }
865      break;
866
867    case TY_PROTOCOMP:
868      log_Printf(LogLCP, "%s\n", request);
869
870      switch (mode_type) {
871      case MODE_REQ:
872	if (IsAccepted(lcp->cfg.protocomp)) {
873	  lcp->his_protocomp = 1;
874	  memcpy(dec->ackend, cp, 2);
875	  dec->ackend += 2;
876	} else {
877#ifdef OLDMST
878	  /*
879	   * MorningStar before v1.3 needs NAK
880	   */
881	  memcpy(dec->nakend, cp, 2);
882	  dec->nakend += 2;
883#else
884	  goto reqreject;
885#endif
886	}
887	break;
888      case MODE_NAK:
889      case MODE_REJ:
890	lcp->want_protocomp = 0;
891	lcp->his_reject |= (1 << type);
892	break;
893      }
894      break;
895
896    case TY_ACFCOMP:
897      log_Printf(LogLCP, "%s\n", request);
898      switch (mode_type) {
899      case MODE_REQ:
900	if (IsAccepted(lcp->cfg.acfcomp)) {
901	  lcp->his_acfcomp = 1;
902	  memcpy(dec->ackend, cp, 2);
903	  dec->ackend += 2;
904	} else {
905#ifdef OLDMST
906	  /*
907	   * MorningStar before v1.3 needs NAK
908	   */
909	  memcpy(dec->nakend, cp, 2);
910	  dec->nakend += 2;
911#else
912	  goto reqreject;
913#endif
914	}
915	break;
916      case MODE_NAK:
917      case MODE_REJ:
918	lcp->want_acfcomp = 0;
919	lcp->his_reject |= (1 << type);
920	break;
921      }
922      break;
923
924    case TY_SDP:
925      log_Printf(LogLCP, "%s\n", request);
926      switch (mode_type) {
927      case MODE_REQ:
928      case MODE_NAK:
929      case MODE_REJ:
930	break;
931      }
932      break;
933
934    case TY_CALLBACK:
935      if (length == 2)
936        op = CALLBACK_NONE;
937      else
938        op = (int)cp[2];
939      sz = length - 3;
940      switch (op) {
941        case CALLBACK_AUTH:
942          log_Printf(LogLCP, "%s Auth\n", request);
943          break;
944        case CALLBACK_DIALSTRING:
945          log_Printf(LogLCP, "%s Dialstring %.*s\n", request, sz, cp + 3);
946          break;
947        case CALLBACK_LOCATION:
948          log_Printf(LogLCP, "%s Location %.*s\n", request, sz, cp + 3);
949          break;
950        case CALLBACK_E164:
951          log_Printf(LogLCP, "%s E.164 (%.*s)\n", request, sz, cp + 3);
952          break;
953        case CALLBACK_NAME:
954          log_Printf(LogLCP, "%s Name %.*s\n", request, sz, cp + 3);
955          break;
956        case CALLBACK_CBCP:
957          log_Printf(LogLCP, "%s CBCP\n", request);
958          break;
959        default:
960          log_Printf(LogLCP, "%s ???\n", request);
961          break;
962      }
963
964      switch (mode_type) {
965      case MODE_REQ:
966        callback_req = 1;
967        if (p->type != PHYS_DIRECT)
968	  goto reqreject;
969        if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(op)) &&
970            (op != CALLBACK_AUTH || p->link.lcp.auth_ineed) &&
971            (op != CALLBACK_E164 ||
972             E164ok(&p->dl->cfg.callback, cp + 3, sz))) {
973	  lcp->his_callback.opmask = CALLBACK_BIT(op);
974          if (sz > sizeof lcp->his_callback.msg - 1) {
975            sz = sizeof lcp->his_callback.msg - 1;
976            log_Printf(LogWARN, "Truncating option arg to %d octets\n", sz);
977          }
978	  memcpy(lcp->his_callback.msg, cp + 3, sz);
979	  lcp->his_callback.msg[sz] = '\0';
980	  memcpy(dec->ackend, cp, sz + 3);
981	  dec->ackend += sz + 3;
982        } else if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) &&
983                    p->link.lcp.auth_ineed) {
984          *dec->nakend++ = *cp;
985          *dec->nakend++ = 3;
986          *dec->nakend++ = CALLBACK_AUTH;
987        } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) {
988          *dec->nakend++ = *cp;
989          *dec->nakend++ = 3;
990          *dec->nakend++ = CALLBACK_CBCP;
991        } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) {
992          *dec->nakend++ = *cp;
993          *dec->nakend++ = 3;
994          *dec->nakend++ = CALLBACK_E164;
995        } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) {
996          log_Printf(LogWARN, "Cannot insist on auth callback without"
997                     " PAP or CHAP enabled !\n");
998          *dec->nakend++ = *cp;
999          *dec->nakend++ = 2;
1000        } else
1001	  goto reqreject;
1002        break;
1003      case MODE_NAK:
1004        /* We don't do what he NAKs with, we do things in our preferred order */
1005        if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH))
1006          lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_AUTH);
1007        else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP))
1008          lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_CBCP);
1009        else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164))
1010          lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_E164);
1011        if (lcp->want_callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) {
1012          log_Printf(LogPHASE, "Peer NAKd all callbacks, trying none\n");
1013          lcp->want_callback.opmask = 0;
1014        } else if (!lcp->want_callback.opmask) {
1015          log_Printf(LogPHASE, "Peer NAKd last configured callback\n");
1016          fsm_Close(&lcp->fsm);
1017        }
1018        break;
1019      case MODE_REJ:
1020        if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) {
1021	  lcp->his_reject |= (1 << type);
1022          lcp->want_callback.opmask = 0;
1023        } else {
1024          log_Printf(LogPHASE, "Peer rejected *required* callback\n");
1025          fsm_Close(&lcp->fsm);
1026        }
1027	break;
1028      }
1029      break;
1030
1031    case TY_SHORTSEQ:
1032      mp = &lcp->fsm.bundle->ncp.mp;
1033      log_Printf(LogLCP, "%s\n", request);
1034
1035      switch (mode_type) {
1036      case MODE_REQ:
1037        if (lcp->want_mrru && IsAccepted(mp->cfg.shortseq)) {
1038          lcp->his_shortseq = 1;
1039	  memcpy(dec->ackend, cp, length);
1040	  dec->ackend += length;
1041        } else
1042	  goto reqreject;
1043        break;
1044      case MODE_NAK:
1045        /*
1046         * He's trying to get us to ask for short sequence numbers.
1047         * We ignore the NAK and honour our configuration file instead.
1048         */
1049        break;
1050      case MODE_REJ:
1051	lcp->his_reject |= (1 << type);
1052        lcp->want_shortseq = 0;		/* For when we hit MP */
1053	break;
1054      }
1055      break;
1056
1057    case TY_ENDDISC:
1058      log_Printf(LogLCP, "%s %s\n", request,
1059                mp_Enddisc(cp[2], cp + 3, length - 3));
1060      switch (mode_type) {
1061      case MODE_REQ:
1062        if (!p) {
1063          log_Printf(LogLCP, " ENDDISC rejected - not a physical link\n");
1064	  goto reqreject;
1065        } else if (length-3 < sizeof p->dl->peer.enddisc.address &&
1066                   cp[2] <= MAX_ENDDISC_CLASS) {
1067          p->dl->peer.enddisc.class = cp[2];
1068          p->dl->peer.enddisc.len = length-3;
1069          memcpy(p->dl->peer.enddisc.address, cp + 3, length - 3);
1070          p->dl->peer.enddisc.address[length - 3] = '\0';
1071          /* XXX: If mp->active, compare and NAK with mp->peer ? */
1072	  memcpy(dec->ackend, cp, length);
1073	  dec->ackend += length;
1074        } else {
1075          if (cp[2] > MAX_ENDDISC_CLASS)
1076            log_Printf(LogLCP, " ENDDISC rejected - unrecognised class %d\n",
1077                      cp[2]);
1078          else
1079            log_Printf(LogLCP, " ENDDISC rejected - local max length is %ld\n",
1080                      (long)(sizeof p->dl->peer.enddisc.address - 1));
1081	  goto reqreject;
1082        }
1083	break;
1084
1085      case MODE_NAK:	/* Treat this as a REJ, we don't vary our disc */
1086      case MODE_REJ:
1087	lcp->his_reject |= (1 << type);
1088	break;
1089      }
1090      break;
1091
1092    default:
1093      sz = (sizeof desc - 2) / 2;
1094      if (sz > length - 2)
1095        sz = length - 2;
1096      pos = 0;
1097      desc[0] = sz ? ' ' : '\0';
1098      for (pos = 0; sz--; pos++)
1099        sprintf(desc+(pos<<1)+1, "%02x", cp[pos+2]);
1100
1101      log_Printf(LogLCP, "%s%s\n", request, desc);
1102
1103      if (mode_type == MODE_REQ) {
1104reqreject:
1105        if (length > sizeof dec->rej - (dec->rejend - dec->rej)) {
1106          length = sizeof dec->rej - (dec->rejend - dec->rej);
1107          log_Printf(LogLCP, "Can't REJ length %d - trunating to %d\n",
1108		    cp[1], length);
1109        }
1110	memcpy(dec->rejend, cp, length);
1111	dec->rejend += length;
1112	lcp->my_reject |= (1 << type);
1113        if (length != cp[1])
1114          length = 0;		/* force our way out of the loop */
1115      }
1116      break;
1117    }
1118    plen -= length;
1119    cp += length;
1120  }
1121
1122  if (mode_type != MODE_NOP) {
1123    if (mode_type == MODE_REQ && p && p->type == PHYS_DIRECT &&
1124        p->dl->cfg.callback.opmask && !callback_req &&
1125        !(p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))) {
1126      /* We *REQUIRE* that the peer requests callback */
1127      *dec->nakend++ = TY_CALLBACK;
1128      *dec->nakend++ = 3;
1129      if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) &&
1130          p->link.lcp.auth_ineed)
1131        *dec->nakend++ = CALLBACK_AUTH;
1132      else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP))
1133        *dec->nakend++ = CALLBACK_CBCP;
1134      else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164))
1135        *dec->nakend++ = CALLBACK_E164;
1136      else {
1137        log_Printf(LogWARN, "Cannot insist on auth callback without"
1138                   " PAP or CHAP enabled !\n");
1139        dec->nakend[-1] = 2;	/* XXX: Silly ! */
1140      }
1141    }
1142    if (dec->rejend != dec->rej) {
1143      /* rejects are preferred */
1144      dec->ackend = dec->ack;
1145      dec->nakend = dec->nak;
1146    } else if (dec->nakend != dec->nak)
1147      /* then NAKs */
1148      dec->ackend = dec->ack;
1149  }
1150}
1151
1152void
1153lcp_Input(struct lcp *lcp, struct mbuf *bp)
1154{
1155  /* Got PROTO_LCP from link */
1156  fsm_Input(&lcp->fsm, bp);
1157}
1158