lcp.c revision 33063
1/*
2 *	      PPP Link Control Protocol (LCP) Module
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc.  The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id: lcp.c,v 1.55 1998/01/21 02:15:18 brian Exp $
21 *
22 * TODO:
23 *      o Validate magic number received from peer.
24 *	o Limit data field length by MRU
25 */
26#include <sys/param.h>
27#include <sys/time.h>
28#include <sys/socket.h>
29#include <net/if.h>
30#include <net/if_tun.h>
31#include <netinet/in.h>
32#include <arpa/inet.h>
33
34#include <signal.h>
35#include <stdarg.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <sys/time.h>
40#include <termios.h>
41#include <unistd.h>
42
43#include "command.h"
44#include "mbuf.h"
45#include "log.h"
46#include "defs.h"
47#include "timer.h"
48#include "fsm.h"
49#include "lcp.h"
50#include "ipcp.h"
51#include "lcpproto.h"
52#include "os.h"
53#include "hdlc.h"
54#include "ccp.h"
55#include "lqr.h"
56#include "phase.h"
57#include "loadalias.h"
58#include "vars.h"
59#include "auth.h"
60#include "pap.h"
61#include "chap.h"
62#include "async.h"
63#include "main.h"
64#include "ip.h"
65#include "modem.h"
66#include "tun.h"
67
68/* for received LQRs */
69struct lqrreq {
70  u_char type;
71  u_char length;
72  u_short proto;		/* Quality protocol */
73  u_long period;		/* Reporting interval */
74};
75
76struct lcpstate LcpInfo;
77
78static void LcpSendConfigReq(struct fsm *);
79static void LcpSendTerminateReq(struct fsm *);
80static void LcpSendTerminateAck(struct fsm *);
81static void LcpDecodeConfig(u_char *, int, int);
82static void LcpInitRestartCounter(struct fsm *);
83static void LcpLayerUp(struct fsm *);
84static void LcpLayerDown(struct fsm *);
85static void LcpLayerStart(struct fsm *);
86static void LcpLayerFinish(struct fsm *);
87
88static const char *cftypes[] = {
89  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
90  "???",
91  "MRU",	/* 1: Maximum-Receive-Unit */
92  "ACCMAP",	/* 2: Async-Control-Character-Map */
93  "AUTHPROTO",	/* 3: Authentication-Protocol */
94  "QUALPROTO",	/* 4: Quality-Protocol */
95  "MAGICNUM",	/* 5: Magic-Number */
96  "RESERVED",	/* 6: RESERVED */
97  "PROTOCOMP",	/* 7: Protocol-Field-Compression */
98  "ACFCOMP",	/* 8: Address-and-Control-Field-Compression */
99  "FCSALT",	/* 9: FCS-Alternatives */
100  "SDP",	/* 10: Self-Describing-Pad */
101  "NUMMODE",	/* 11: Numbered-Mode */
102  "MULTIPROC",	/* 12: Multi-Link-Procedure */
103  "CALLBACK",	/* 13: Callback */
104  "CONTIME",	/* 14: Connect-Time */
105  "COMPFRAME",	/* 15: Compound-Frames */
106  "NDE",	/* 16: Nominal-Data-Encapsulation */
107  "MULTIMRRU",	/* 17: Multilink-MRRU */
108  "MULTISSNH",	/* 18: Multilink-Short-Sequence-Number-Header */
109  "MULTIED",	/* 19: Multilink-Endpoint-Descriminator */
110  "PROPRIETRY",	/* 20: Proprietary */
111  "DCEID",	/* 21: DCE-Identifier */
112  "MULTIPP",	/* 22: Multi-Link-Plus-Procedure */
113  "LDBACP",	/* 23: Link Discriminator for BACP */
114};
115
116#define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
117
118struct fsm LcpFsm = {
119  "LCP",			/* Name of protocol */
120  PROTO_LCP,			/* Protocol Number */
121  LCP_MAXCODE,
122  1,				/* Open mode delay */
123  ST_INITIAL,			/* State of machine */
124  0, 0, 0,
125  {0, 0, 0, NULL, NULL, NULL},	/* FSM timer */
126  {0, 0, 0, NULL, NULL, NULL},	/* Open timer */
127  {0, 0, 0, NULL, NULL, NULL},	/* Stopped timer */
128  LogLCP,
129
130  LcpLayerUp,
131  LcpLayerDown,
132  LcpLayerStart,
133  LcpLayerFinish,
134  LcpInitRestartCounter,
135  LcpSendConfigReq,
136  LcpSendTerminateReq,
137  LcpSendTerminateAck,
138  LcpDecodeConfig,
139};
140
141static struct pppTimer LcpReportTimer;
142static int LcpFailedMagic;
143
144static void
145LcpReportTime(void *data)
146{
147  if (LogIsKept(LogDEBUG)) {
148    time_t t;
149
150    time(&t);
151    LogPrintf(LogDEBUG, "LcpReportTime: %s\n", ctime(&t));
152  }
153  StopTimer(&LcpReportTimer);
154  LcpReportTimer.state = TIMER_STOPPED;
155  StartTimer(&LcpReportTimer);
156  HdlcErrorCheck();
157}
158
159int
160ReportLcpStatus(struct cmdargs const *arg)
161{
162  struct lcpstate *lcp = &LcpInfo;
163  struct fsm *fp = &LcpFsm;
164
165  if (!VarTerm)
166    return 1;
167
168  fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]);
169  fprintf(VarTerm,
170	  " his side: MRU %d, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d,\n"
171	  "           MAGIC %08lx, REJECT %04x\n",
172	  lcp->his_mru, (u_long)lcp->his_accmap, lcp->his_protocomp,
173          lcp->his_acfcomp, (u_long)lcp->his_magic, lcp->his_reject);
174  fprintf(VarTerm,
175	  " my  side: MRU %d, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d,\n"
176          "           MAGIC %08lx, REJECT %04x\n",
177          lcp->want_mru, (u_long)lcp->want_accmap, lcp->want_protocomp,
178          lcp->want_acfcomp, (u_long)lcp->want_magic, lcp->my_reject);
179  fprintf(VarTerm, "\nDefaults:   MRU = %d, ACCMAP = %08lx\t",
180          VarMRU, (u_long)VarAccmap);
181  fprintf(VarTerm, "Open Mode: %s",
182          (VarOpenMode == OPEN_PASSIVE) ? "passive" : "active");
183  if (VarOpenMode > 0)
184    fprintf(VarTerm, " (delay %d)", VarOpenMode);
185  fputc('\n', VarTerm);
186  return 0;
187}
188
189/*
190 * Generate random number which will be used as magic number.
191 */
192static u_int32_t
193GenerateMagic(void)
194{
195  randinit();
196  return (random());
197}
198
199void
200LcpInit()
201{
202  struct lcpstate *lcp = &LcpInfo;
203
204  FsmInit(&LcpFsm);
205  HdlcInit();
206
207  memset(lcp, '\0', sizeof(struct lcpstate));
208  lcp->want_mru = VarMRU;
209  lcp->his_mru = DEF_MRU;
210  lcp->his_accmap = 0xffffffff;
211  lcp->want_accmap = VarAccmap;
212  lcp->want_magic = GenerateMagic();
213  lcp->want_auth = lcp->his_auth = 0;
214  if (Enabled(ConfChap))
215    lcp->want_auth = PROTO_CHAP;
216  else if (Enabled(ConfPap))
217    lcp->want_auth = PROTO_PAP;
218  if (Enabled(ConfLqr))
219    lcp->want_lqrperiod = VarLqrTimeout * 100;
220  if (Enabled(ConfAcfcomp))
221    lcp->want_acfcomp = 1;
222  if (Enabled(ConfProtocomp))
223    lcp->want_protocomp = 1;
224  LcpFsm.maxconfig = 10;
225}
226
227static void
228LcpInitRestartCounter(struct fsm * fp)
229{
230  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
231  fp->restart = 5;
232}
233
234int
235LcpPutConf(int log, u_char *tgt, const struct lcp_opt *o, const char *nm,
236           const char *arg, ...)
237{
238  va_list ap;
239  char buf[30];
240
241  va_start(ap, arg);
242  memcpy(tgt, o, o->len);
243  if (arg == NULL || *arg == '\0')
244    LogPrintf(log, " %s[%d]\n", nm, o->len);
245  else {
246    vsnprintf(buf, sizeof buf, arg, ap);
247    LogPrintf(log, " %s[%d] %s\n", nm, o->len, buf);
248  }
249  va_end(ap);
250
251  return o->len;
252}
253
254#define PUTN(ty)						\
255do {								\
256  o.id = ty;							\
257  o.len = 2;							\
258  cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], NULL);	\
259} while (0)
260
261#define PUTHEX32(ty, arg)					\
262do {								\
263  o.id = ty;							\
264  o.len = 6;							\
265  *(u_long *)o.data = htonl(arg);				\
266  cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], "0x%08lx", (u_long)arg);\
267} while (0)
268
269#define PUTACCMAP(arg) PUTHEX32(TY_ACCMAP, arg)
270#define PUTMAGIC(arg) PUTHEX32(TY_MAGICNUM, arg)
271
272#define PUTMRU(arg)						\
273do {								\
274  o.id = TY_MRU;						\
275  o.len = 4;							\
276  *(u_short *)o.data = htons(arg);				\
277  cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], "%u", arg);	\
278} while (0)
279
280#define PUTLQR(period)						\
281do {								\
282  o.id = TY_QUALPROTO;						\
283  o.len = 8;							\
284  *(u_short *)o.data = htons(PROTO_LQR);			\
285  *(u_long *)(o.data+2) = htonl(period);			\
286  cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id],		\
287                   "period %ld", (u_long)period);		\
288} while (0)
289
290#define PUTPAP()						\
291do {								\
292  o.id = TY_AUTHPROTO;						\
293  o.len = 4;							\
294  *(u_short *)o.data = htons(PROTO_PAP);			\
295  cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id],		\
296		   "0x%04x (PAP)", PROTO_PAP);			\
297} while (0)
298
299#define PUTCHAP(val)						\
300do {								\
301  o.id = TY_AUTHPROTO;						\
302  o.len = 5;							\
303  *(u_short *)o.data = htons(PROTO_CHAP);			\
304  o.data[2] = val;						\
305  cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id],		\
306		   "0x%04x (CHAP 0x%02x)", PROTO_CHAP, val);	\
307} while (0)
308
309#define PUTMD5CHAP() PUTCHAP(0x05)
310#define PUTMSCHAP()  PUTCHAP(0x80)
311
312static void
313LcpSendConfigReq(struct fsm * fp)
314{
315  u_char *cp;
316  struct lcpstate *lcp = &LcpInfo;
317  struct lcp_opt o;
318
319  LogPrintf(LogLCP, "LcpSendConfigReq\n");
320  cp = ReqBuff;
321  if (!DEV_IS_SYNC) {
322    if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP))
323      PUTN(TY_ACFCOMP);
324
325    if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP))
326      PUTN(TY_PROTOCOMP);
327
328    if (!REJECTED(lcp, TY_ACCMAP))
329      PUTACCMAP(lcp->want_accmap);
330  }
331
332  if (!REJECTED(lcp, TY_MRU))
333    PUTMRU(lcp->want_mru);
334
335  if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM))
336    PUTMAGIC(lcp->want_magic);
337
338  if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO))
339    PUTLQR(lcp->want_lqrperiod);
340
341  switch (lcp->want_auth) {
342  case PROTO_PAP:
343    PUTPAP();
344    break;
345
346  case PROTO_CHAP:
347#ifdef HAVE_DES
348    if (VarMSChap)
349      PUTMSCHAP();			/* Use MSChap */
350    else
351#endif
352      PUTMD5CHAP();			/* Use MD5 */
353    break;
354  }
355  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
356}
357
358void
359LcpSendProtoRej(u_char * option, int count)
360{
361  struct fsm *fp = &LcpFsm;
362
363  LogPrintf(LogLCP, "LcpSendProtoRej\n");
364  FsmOutput(fp, CODE_PROTOREJ, fp->reqid, option, count);
365}
366
367static void
368LcpSendTerminateReq(struct fsm * fp)
369{
370  /* Most thins are done in fsm layer. Nothing to to. */
371}
372
373static void
374LcpSendTerminateAck(struct fsm * fp)
375{
376  LogPrintf(LogLCP, "LcpSendTerminateAck.\n");
377  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
378}
379
380static void
381LcpLayerStart(struct fsm * fp)
382{
383  LogPrintf(LogLCP, "LcpLayerStart\n");
384  NewPhase(PHASE_ESTABLISH);
385}
386
387static void
388StopAllTimers(void)
389{
390  StopTimer(&LcpReportTimer);
391  StopIdleTimer();
392  StopTimer(&AuthPapInfo.authtimer);
393  StopTimer(&AuthChapInfo.authtimer);
394  StopLqrTimer();
395}
396
397static void
398LcpLayerFinish(struct fsm * fp)
399{
400  LogPrintf(LogLCP, "LcpLayerFinish\n");
401  HangupModem(0);
402  StopAllTimers();
403  /* We're down at last.  Lets tell background and direct mode to get out */
404  NewPhase(PHASE_DEAD);
405  LcpInit();
406  IpcpInit();
407  CcpInit();
408  Prompt();
409}
410
411static void
412LcpLayerUp(struct fsm * fp)
413{
414  LogPrintf(LogLCP, "LcpLayerUp\n");
415  tun_configure(LcpInfo.his_mru, ModemSpeed());
416  SetLinkParams(&LcpInfo);
417
418  NewPhase(PHASE_AUTHENTICATE);
419
420  StartLqm();
421  StopTimer(&LcpReportTimer);
422  LcpReportTimer.state = TIMER_STOPPED;
423  LcpReportTimer.load = 60 * SECTICKS;
424  LcpReportTimer.func = LcpReportTime;
425  StartTimer(&LcpReportTimer);
426}
427
428static void
429LcpLayerDown(struct fsm * fp)
430{
431  StopAllTimers();
432  OsLinkdown();
433  LogPrintf(LogLCP, "LcpLayerDown\n");
434  /*
435   * OsLinkdown() brings CCP & IPCP down, then waits 'till we go from
436   * STOPPING to STOPPED.  At this point, the FSM gives us a LayerFinish
437   */
438}
439
440void
441LcpUp()
442{
443  FsmUp(&LcpFsm);
444  LcpFailedMagic = 0;
445}
446
447void
448LcpDown()
449{				/* Sudden death */
450  LcpFailedMagic = 0;
451  FsmDown(&LcpFsm);
452  /* FsmDown() results in a LcpLayerDown() if we're currently open. */
453  LcpLayerFinish(&LcpFsm);
454}
455
456void
457LcpOpen(int open_mode)
458{
459  LcpFsm.open_mode = open_mode;
460  LcpFailedMagic = 0;
461  FsmOpen(&LcpFsm);
462}
463
464void
465LcpClose()
466{
467  NewPhase(PHASE_TERMINATE);
468  OsInterfaceDown(0);
469  FsmClose(&LcpFsm);
470  LcpFailedMagic = 0;
471}
472
473/*
474 *	XXX: Should validate option length
475 */
476static void
477LcpDecodeConfig(u_char *cp, int plen, int mode_type)
478{
479  int type, length, sz, pos;
480  u_int32_t *lp, magic, accmap;
481  u_short mtu, mru, *sp, proto;
482  struct lqrreq *req;
483  char request[20], desc[22];
484
485  ackp = AckBuff;
486  nakp = NakBuff;
487  rejp = RejBuff;
488
489  while (plen >= sizeof(struct fsmconfig)) {
490    type = *cp;
491    length = cp[1];
492
493    if (type < 0 || type >= NCFTYPES)
494      snprintf(request, sizeof request, " <%d>[%d]", type, length);
495    else
496      snprintf(request, sizeof request, " %s[%d]", cftypes[type], length);
497
498    switch (type) {
499    case TY_MRU:
500      sp = (u_short *) (cp + 2);
501      mru = htons(*sp);
502      LogPrintf(LogLCP, "%s %d\n", request, mru);
503
504      switch (mode_type) {
505      case MODE_REQ:
506        mtu = VarPrefMTU;
507        if (mtu == 0)
508          mtu = MAX_MTU;
509	if (mru > mtu) {
510	  *sp = htons(mtu);
511	  memcpy(nakp, cp, 4);
512	  nakp += 4;
513	} else if (mru < MIN_MRU) {
514	  *sp = htons(MIN_MRU);
515	  memcpy(nakp, cp, 4);
516	  nakp += 4;
517	} else {
518	  LcpInfo.his_mru = mru;
519	  memcpy(ackp, cp, 4);
520	  ackp += 4;
521	}
522	break;
523      case MODE_NAK:
524	if (mru >= MIN_MRU || mru <= MAX_MRU)
525	  LcpInfo.want_mru = mru;
526	break;
527      case MODE_REJ:
528	LcpInfo.his_reject |= (1 << type);
529	break;
530      }
531      break;
532
533    case TY_ACCMAP:
534      lp = (u_int32_t *) (cp + 2);
535      accmap = htonl(*lp);
536      LogPrintf(LogLCP, "%s 0x%08lx\n", request, (u_long)accmap);
537
538      switch (mode_type) {
539      case MODE_REQ:
540	LcpInfo.his_accmap = accmap;
541	memcpy(ackp, cp, 6);
542	ackp += 6;
543	break;
544      case MODE_NAK:
545	LcpInfo.want_accmap = accmap;
546	break;
547      case MODE_REJ:
548	LcpInfo.his_reject |= (1 << type);
549	break;
550      }
551      break;
552
553    case TY_AUTHPROTO:
554      sp = (u_short *) (cp + 2);
555      proto = ntohs(*sp);
556      switch (proto) {
557      case PROTO_PAP:
558        LogPrintf(LogLCP, "%s 0x%04x (PAP)\n", request, proto);
559        break;
560      case PROTO_CHAP:
561        LogPrintf(LogLCP, "%s 0x%04x (CHAP 0x%02x)\n", request, proto, cp[4]);
562        break;
563      default:
564        LogPrintf(LogLCP, "%s 0x%04x\n", request, proto);
565        break;
566      }
567
568      switch (mode_type) {
569      case MODE_REQ:
570	switch (proto) {
571	case PROTO_PAP:
572	  if (length != 4) {
573	    LogPrintf(LogLCP, " Bad length!\n");
574	    goto reqreject;
575	  }
576	  if (Acceptable(ConfPap)) {
577	    LcpInfo.his_auth = proto;
578	    memcpy(ackp, cp, length);
579	    ackp += length;
580	  } else if (Acceptable(ConfChap)) {
581	    *nakp++ = *cp;
582	    *nakp++ = 5;
583	    *nakp++ = (unsigned char) (PROTO_CHAP >> 8);
584	    *nakp++ = (unsigned char) PROTO_CHAP;
585#ifdef HAVE_DES
586            if (VarMSChap)
587              *nakp++ = 0x80;
588            else
589#endif
590	      *nakp++ = 5;
591	  } else
592	    goto reqreject;
593	  break;
594
595	case PROTO_CHAP:
596	  if (length < 5) {
597	    LogPrintf(LogLCP, " Bad length!\n");
598	    goto reqreject;
599	  }
600#ifdef HAVE_DES
601          if (Acceptable(ConfChap) && (cp[4] == 5 || cp[4] == 0x80))
602#else
603          if (Acceptable(ConfChap) && cp[4] == 5)
604#endif
605	  {
606	    LcpInfo.his_auth = proto;
607	    memcpy(ackp, cp, length);
608	    ackp += length;
609#ifdef HAVE_DES
610            VarMSChap = cp[4] == 0x80;
611#endif
612	  } else if (Acceptable(ConfPap)) {
613	    *nakp++ = *cp;
614	    *nakp++ = 4;
615	    *nakp++ = (unsigned char) (PROTO_PAP >> 8);
616	    *nakp++ = (unsigned char) PROTO_PAP;
617	  } else
618	    goto reqreject;
619	  break;
620
621	default:
622          LogPrintf(LogLCP, "%s 0x%04x - not recognised, NAK\n",
623                    request, proto);
624	  memcpy(nakp, cp, length);
625	  nakp += length;
626	  break;
627	}
628	break;
629      case MODE_NAK:
630	switch (proto) {
631	case PROTO_PAP:
632          if (Enabled(ConfPap))
633            LcpInfo.want_auth = PROTO_PAP;
634          else {
635            LogPrintf(LogLCP, "Peer will only send PAP (not enabled)\n");
636	    LcpInfo.his_reject |= (1 << type);
637          }
638          break;
639	case PROTO_CHAP:
640          if (Enabled(ConfChap))
641            LcpInfo.want_auth = PROTO_CHAP;
642          else {
643            LogPrintf(LogLCP, "Peer will only send CHAP (not enabled)\n");
644	    LcpInfo.his_reject |= (1 << type);
645          }
646          break;
647        default:
648          /* We've been NAK'd with something we don't understand :-( */
649	  LcpInfo.his_reject |= (1 << type);
650          break;
651        }
652	break;
653      case MODE_REJ:
654	LcpInfo.his_reject |= (1 << type);
655	break;
656      }
657      break;
658
659    case TY_QUALPROTO:
660      req = (struct lqrreq *) cp;
661      LogPrintf(LogLCP, "%s proto %x, interval %dms\n",
662                request, ntohs(req->proto), ntohl(req->period) * 10);
663      switch (mode_type) {
664      case MODE_REQ:
665	if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr))
666	  goto reqreject;
667	else {
668	  LcpInfo.his_lqrperiod = ntohl(req->period);
669	  if (LcpInfo.his_lqrperiod < 500)
670	    LcpInfo.his_lqrperiod = 500;
671	  req->period = htonl(LcpInfo.his_lqrperiod);
672	  memcpy(ackp, cp, length);
673	  ackp += length;
674	}
675	break;
676      case MODE_NAK:
677	break;
678      case MODE_REJ:
679	LcpInfo.his_reject |= (1 << type);
680	break;
681      }
682      break;
683
684    case TY_MAGICNUM:
685      lp = (u_int32_t *) (cp + 2);
686      magic = ntohl(*lp);
687      LogPrintf(LogLCP, "%s 0x%08lx\n", request, (u_long)magic);
688
689      switch (mode_type) {
690      case MODE_REQ:
691	if (LcpInfo.want_magic) {
692	  /* Validate magic number */
693	  if (magic == LcpInfo.want_magic) {
694	    LogPrintf(LogLCP, "Magic is same (%08lx) - %d times\n",
695                      (u_long)magic, ++LcpFailedMagic);
696	    LcpInfo.want_magic = GenerateMagic();
697	    memcpy(nakp, cp, 6);
698	    nakp += 6;
699            ualarm(TICKUNIT * (4 + 4 * LcpFailedMagic), 0);
700            sigpause(0);
701	  } else {
702	    LcpInfo.his_magic = magic;
703	    memcpy(ackp, cp, length);
704	    ackp += length;
705            LcpFailedMagic = 0;
706	  }
707	} else {
708	  LcpInfo.my_reject |= (1 << type);
709	  goto reqreject;
710	}
711	break;
712      case MODE_NAK:
713	LogPrintf(LogLCP, " Magic 0x%08lx is NAKed!\n", (u_long)magic);
714	LcpInfo.want_magic = GenerateMagic();
715	break;
716      case MODE_REJ:
717	LogPrintf(LogLCP, " Magic 0x%08x is REJected!\n", magic);
718	LcpInfo.want_magic = 0;
719	LcpInfo.his_reject |= (1 << type);
720	break;
721      }
722      break;
723
724    case TY_PROTOCOMP:
725      LogPrintf(LogLCP, "%s\n", request);
726
727      switch (mode_type) {
728      case MODE_REQ:
729	if (Acceptable(ConfProtocomp)) {
730	  LcpInfo.his_protocomp = 1;
731	  memcpy(ackp, cp, 2);
732	  ackp += 2;
733	} else {
734#ifdef OLDMST
735	  /*
736	   * MorningStar before v1.3 needs NAK
737	   */
738	  memcpy(nakp, cp, 2);
739	  nakp += 2;
740#else
741	  memcpy(rejp, cp, 2);
742	  rejp += 2;
743	  LcpInfo.my_reject |= (1 << type);
744#endif
745	}
746	break;
747      case MODE_NAK:
748      case MODE_REJ:
749	LcpInfo.want_protocomp = 0;
750	LcpInfo.his_reject |= (1 << type);
751	break;
752      }
753      break;
754
755    case TY_ACFCOMP:
756      LogPrintf(LogLCP, "%s\n", request);
757      switch (mode_type) {
758      case MODE_REQ:
759	if (Acceptable(ConfAcfcomp)) {
760	  LcpInfo.his_acfcomp = 1;
761	  memcpy(ackp, cp, 2);
762	  ackp += 2;
763	} else {
764#ifdef OLDMST
765	  /*
766	   * MorningStar before v1.3 needs NAK
767	   */
768	  memcpy(nakp, cp, 2);
769	  nakp += 2;
770#else
771	  memcpy(rejp, cp, 2);
772	  rejp += 2;
773	  LcpInfo.my_reject |= (1 << type);
774#endif
775	}
776	break;
777      case MODE_NAK:
778      case MODE_REJ:
779	LcpInfo.want_acfcomp = 0;
780	LcpInfo.his_reject |= (1 << type);
781	break;
782      }
783      break;
784
785    case TY_SDP:
786      LogPrintf(LogLCP, "%s\n", request);
787      switch (mode_type) {
788      case MODE_REQ:
789      case MODE_NAK:
790      case MODE_REJ:
791	break;
792      }
793      break;
794
795    default:
796      sz = (sizeof desc - 2) / 2;
797      if (sz > length - 2)
798        sz = length - 2;
799      pos = 0;
800      desc[0] = sz ? ' ' : '\0';
801      for (pos = 0; sz--; pos++)
802        sprintf(desc+(pos<<1)+1, "%02x", cp[pos+2]);
803
804      LogPrintf(LogLCP, "%s%s\n", request, desc);
805
806      if (mode_type == MODE_REQ) {
807reqreject:
808        if (length > sizeof RejBuff - (rejp - RejBuff)) {
809          length = sizeof RejBuff - (rejp - RejBuff);
810          LogPrintf(LogLCP, "Can't REJ length %d - trunating to %d\n",
811		    cp[1], length);
812        }
813	memcpy(rejp, cp, length);
814	rejp += length;
815	LcpInfo.my_reject |= (1 << type);
816        if (length != cp[1])
817          return;
818      }
819      break;
820    }
821    /* to avoid inf. loop */
822    if (length == 0) {
823      LogPrintf(LogLCP, "LCP size zero\n");
824      break;
825    }
826    plen -= length;
827    cp += length;
828  }
829}
830
831void
832LcpInput(struct mbuf * bp)
833{
834  FsmInput(&LcpFsm, bp);
835}
836