xref: /freebsd/usr.sbin/ppp/lcp.c (revision 0de89efe5c443f213c7ea28773ef2dc6cf3af2ed)
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.36 1997/09/27 19:41:40 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/time.h>
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <signal.h>
31 #include "fsm.h"
32 #include "lcp.h"
33 #include "ipcp.h"
34 #include "lcpproto.h"
35 #include "os.h"
36 #include "hdlc.h"
37 #include "ccp.h"
38 #include "lqr.h"
39 #include "phase.h"
40 #include "loadalias.h"
41 #include "vars.h"
42 #include "auth.h"
43 #include "timeout.h"
44 
45 extern void IpcpUp();
46 extern void IpcpOpen();
47 extern void SetLinkParams(struct lcpstate *);
48 extern void Prompt();
49 extern void Cleanup();
50 extern struct pppTimer IpcpReportTimer;
51 extern int randinit;
52 
53 struct lcpstate LcpInfo;
54 
55 static void LcpSendConfigReq(struct fsm *);
56 static void LcpSendTerminateReq(struct fsm * fp);
57 static void LcpSendTerminateAck(struct fsm * fp);
58 static void LcpDecodeConfig(u_char * cp, int flen, int mode);
59 static void LcpInitRestartCounter(struct fsm *);
60 static void LcpLayerUp(struct fsm *);
61 static void LcpLayerDown(struct fsm *);
62 static void LcpLayerStart(struct fsm *);
63 static void LcpLayerFinish(struct fsm *);
64 
65 extern int ModemSpeed();
66 
67 #define	REJECTED(p, x)	(p->his_reject & (1<<x))
68 
69 static char *cftypes[] = {
70   "???", "MRU", "ACCMAP", "AUTHPROTO", "QUALPROTO", "MAGICNUM",
71   "RESERVED", "PROTOCOMP", "ACFCOMP", "FCSALT", "SDP",
72 };
73 
74 struct fsm LcpFsm = {
75   "LCP",			/* Name of protocol */
76   PROTO_LCP,			/* Protocol Number */
77   LCP_MAXCODE,
78   OPEN_ACTIVE,
79   ST_INITIAL,			/* State of machine */
80   0, 0, 0,
81   0,
82   {0, 0, 0, NULL, NULL, NULL},
83   {0, 0, 0, NULL, NULL, NULL},
84   LogLCP,
85 
86   LcpLayerUp,
87   LcpLayerDown,
88   LcpLayerStart,
89   LcpLayerFinish,
90   LcpInitRestartCounter,
91   LcpSendConfigReq,
92   LcpSendTerminateReq,
93   LcpSendTerminateAck,
94   LcpDecodeConfig,
95 };
96 
97 static struct pppTimer LcpReportTimer;
98 static int LcpFailedMagic;
99 
100 char *PhaseNames[] = {
101   "Dead", "Establish", "Authenticate", "Network", "Terminate"
102 };
103 
104 void
105 NewPhase(int new)
106 {
107   struct lcpstate *lcp = &LcpInfo;
108 
109   phase = new;
110   LogPrintf(LogPHASE, "NewPhase: %s\n", PhaseNames[phase]);
111   switch (phase) {
112   case PHASE_AUTHENTICATE:
113     lcp->auth_ineed = lcp->want_auth;
114     lcp->auth_iwait = lcp->his_auth;
115     if (lcp->his_auth || lcp->want_auth) {
116       LogPrintf(LogPHASE, " his = %x, mine = %x\n", lcp->his_auth, lcp->want_auth);
117       if (lcp->his_auth == PROTO_PAP)
118 	StartAuthChallenge(&AuthPapInfo);
119       if (lcp->want_auth == PROTO_CHAP)
120 	StartAuthChallenge(&AuthChapInfo);
121     } else
122       NewPhase(PHASE_NETWORK);
123     break;
124   case PHASE_NETWORK:
125     IpcpUp();
126     IpcpOpen();
127     CcpUp();
128     CcpOpen();
129     break;
130   case PHASE_DEAD:
131     if (mode & MODE_DIRECT)
132       Cleanup(EX_DEAD);
133     if (mode & MODE_BACKGROUND && reconnectState != RECON_TRUE)
134       Cleanup(EX_DEAD);
135     break;
136   }
137 }
138 
139 static void
140 LcpReportTime()
141 {
142   if (LogIsKept(LogDEBUG)) {
143     time_t t;
144 
145     time(&t);
146     LogPrintf(LogDEBUG, "LcpReportTime: %s\n", ctime(&t));
147   }
148   StopTimer(&LcpReportTimer);
149   LcpReportTimer.state = TIMER_STOPPED;
150   StartTimer(&LcpReportTimer);
151   HdlcErrorCheck();
152 }
153 
154 int
155 ReportLcpStatus()
156 {
157   struct lcpstate *lcp = &LcpInfo;
158   struct fsm *fp = &LcpFsm;
159 
160   if (!VarTerm)
161     return 1;
162 
163   fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]);
164   fprintf(VarTerm,
165 	  " his side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n"
166 	  "           REJECT %04lx\n",
167 	lcp->his_mru, lcp->his_accmap, lcp->his_protocomp, lcp->his_acfcomp,
168 	  lcp->his_magic, lcp->his_reject);
169   fprintf(VarTerm,
170 	  " my  side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n"
171 	  "           REJECT %04lx\n",
172     lcp->want_mru, lcp->want_accmap, lcp->want_protocomp, lcp->want_acfcomp,
173 	  lcp->want_magic, lcp->my_reject);
174   fprintf(VarTerm, "\nDefaults:   MRU = %ld, ACCMAP = %08x\t", VarMRU, VarAccmap);
175   fprintf(VarTerm, "Open Mode: %s\n", (VarOpenMode == OPEN_ACTIVE) ? "active" : "passive");
176   return 0;
177 }
178 
179 /*
180  * Generate random number which will be used as magic number.
181  */
182 u_long
183 GenerateMagic()
184 {
185   if (!randinit) {
186     randinit = 1;
187     srandomdev();
188   }
189   return (random());
190 }
191 
192 void
193 LcpInit()
194 {
195   struct lcpstate *lcp = &LcpInfo;
196 
197   FsmInit(&LcpFsm);
198   HdlcInit();
199 
200   bzero(lcp, sizeof(struct lcpstate));
201   lcp->want_mru = VarMRU;
202   lcp->his_mru = DEF_MRU;
203   lcp->his_accmap = 0xffffffff;
204   lcp->want_accmap = VarAccmap;
205   lcp->want_magic = GenerateMagic();
206   lcp->want_auth = lcp->his_auth = 0;
207   if (Enabled(ConfChap))
208     lcp->want_auth = PROTO_CHAP;
209   else if (Enabled(ConfPap))
210     lcp->want_auth = PROTO_PAP;
211   if (Enabled(ConfLqr))
212     lcp->want_lqrperiod = VarLqrTimeout * 100;
213   if (Enabled(ConfAcfcomp))
214     lcp->want_acfcomp = 1;
215   if (Enabled(ConfProtocomp))
216     lcp->want_protocomp = 1;
217   LcpFsm.maxconfig = 10;
218 }
219 
220 static void
221 LcpInitRestartCounter(struct fsm * fp)
222 {
223   fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
224   fp->restart = 5;
225 }
226 
227 void
228 PutConfValue(u_char ** cpp, char **types, u_char type, int len, u_long val)
229 {
230   u_char *cp;
231   struct in_addr ina;
232 
233   cp = *cpp;
234   *cp++ = type;
235   *cp++ = len;
236   if (len == 6) {
237     if (type == TY_IPADDR) {
238       ina.s_addr = htonl(val);
239       LogPrintf(LogLCP, " %s [%d] %s\n",
240 		types[type], len, inet_ntoa(ina));
241     } else {
242       LogPrintf(LogLCP, " %s [%d] %08x\n", types[type], len, val);
243     }
244     *cp++ = (val >> 24) & 0377;
245     *cp++ = (val >> 16) & 0377;
246   } else
247     LogPrintf(LogLCP, " %s [%d] %d\n", types[type], len, val);
248   *cp++ = (val >> 8) & 0377;
249   *cp++ = val & 0377;
250   *cpp = cp;
251 }
252 
253 static void
254 LcpSendConfigReq(struct fsm * fp)
255 {
256   u_char *cp;
257   struct lcpstate *lcp = &LcpInfo;
258   struct lqrreq *req;
259 
260   LogPrintf(LogLCP, "LcpSendConfigReq\n");
261   cp = ReqBuff;
262   if (!DEV_IS_SYNC) {
263     if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) {
264       *cp++ = TY_ACFCOMP;
265       *cp++ = 2;
266       LogPrintf(LogLCP, " %s\n", cftypes[TY_ACFCOMP]);
267     }
268     if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) {
269       *cp++ = TY_PROTOCOMP;
270       *cp++ = 2;
271       LogPrintf(LogLCP, " %s\n", cftypes[TY_PROTOCOMP]);
272     }
273     if (!REJECTED(lcp, TY_ACCMAP))
274       PutConfValue(&cp, cftypes, TY_ACCMAP, 6, lcp->want_accmap);
275   }
276   if (!REJECTED(lcp, TY_MRU))
277     PutConfValue(&cp, cftypes, TY_MRU, 4, lcp->want_mru);
278   if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM))
279     PutConfValue(&cp, cftypes, TY_MAGICNUM, 6, lcp->want_magic);
280   if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) {
281     req = (struct lqrreq *) cp;
282     req->type = TY_QUALPROTO;
283     req->length = sizeof(struct lqrreq);
284     req->proto = htons(PROTO_LQR);
285     req->period = htonl(lcp->want_lqrperiod);
286     cp += sizeof(struct lqrreq);
287     LogPrintf(LogLCP, " %s (%d)\n", cftypes[TY_QUALPROTO], lcp->want_lqrperiod);
288   }
289   switch (lcp->want_auth) {
290   case PROTO_PAP:
291     PutConfValue(&cp, cftypes, TY_AUTHPROTO, 4, lcp->want_auth);
292     break;
293   case PROTO_CHAP:
294     PutConfValue(&cp, cftypes, TY_AUTHPROTO, 5, lcp->want_auth);
295 #ifdef HAVE_DES
296     *cp++ = VarMSChap ? 0x80 : 0x05;	/* Use MSChap vs. RFC 1994 (MD5) */
297 #else
298     *cp++ = 0x05;			/* Use MD5 */
299 #endif
300     break;
301   }
302   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
303 }
304 
305 void
306 LcpSendProtoRej(u_char * option, int count)
307 {
308   struct fsm *fp = &LcpFsm;
309 
310   LogPrintf(LogLCP, "LcpSendProtoRej\n");
311   FsmOutput(fp, CODE_PROTOREJ, fp->reqid, option, count);
312 }
313 
314 static void
315 LcpSendTerminateReq(struct fsm * fp)
316 {
317   /* Most thins are done in fsm layer. Nothing to to. */
318 }
319 
320 static void
321 LcpSendTerminateAck(struct fsm * fp)
322 {
323   LogPrintf(LogLCP, "LcpSendTerminateAck.\n");
324   FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
325 }
326 
327 static void
328 LcpLayerStart(struct fsm * fp)
329 {
330   LogPrintf(LogLCP, "LcpLayerStart\n");
331   NewPhase(PHASE_ESTABLISH);
332 }
333 
334 static void
335 StopAllTimers()
336 {
337   StopTimer(&LcpReportTimer);
338   StopTimer(&IpcpReportTimer);
339   StopIdleTimer();
340   StopTimer(&AuthPapInfo.authtimer);
341   StopTimer(&AuthChapInfo.authtimer);
342   StopLqrTimer();
343 }
344 
345 static void
346 LcpLayerFinish(struct fsm * fp)
347 {
348   LogPrintf(LogLCP, "LcpLayerFinish\n");
349   OsCloseLink(1);
350   NewPhase(PHASE_DEAD);
351   StopAllTimers();
352   (void) OsInterfaceDown(0);
353   Prompt();
354 }
355 
356 static void
357 LcpLayerUp(struct fsm * fp)
358 {
359   LogPrintf(LogLCP, "LcpLayerUp\n");
360   OsSetInterfaceParams(23, LcpInfo.his_mru, ModemSpeed());
361   SetLinkParams(&LcpInfo);
362 
363   NewPhase(PHASE_AUTHENTICATE);
364 
365   StartLqm();
366   StopTimer(&LcpReportTimer);
367   LcpReportTimer.state = TIMER_STOPPED;
368   LcpReportTimer.load = 60 * SECTICKS;
369   LcpReportTimer.func = LcpReportTime;
370   StartTimer(&LcpReportTimer);
371 }
372 
373 static void
374 LcpLayerDown(struct fsm * fp)
375 {
376   StopAllTimers();
377   OsLinkdown();
378   LogPrintf(LogLCP, "LcpLayerDown\n");
379   NewPhase(PHASE_TERMINATE);
380 }
381 
382 void
383 LcpUp()
384 {
385   FsmUp(&LcpFsm);
386   LcpFailedMagic = 0;
387 }
388 
389 void
390 LcpDown()
391 {				/* Sudden death */
392   LcpFailedMagic = 0;
393   NewPhase(PHASE_DEAD);
394   StopAllTimers();
395   FsmDown(&LcpFsm);
396 }
397 
398 void
399 LcpOpen(int mode)
400 {
401   LcpFsm.open_mode = mode;
402   LcpFailedMagic = 0;
403   FsmOpen(&LcpFsm);
404 }
405 
406 void
407 LcpClose()
408 {
409   FsmClose(&LcpFsm);
410   LcpFailedMagic = 0;
411 }
412 
413 /*
414  *	XXX: Should validate option length
415  */
416 static void
417 LcpDecodeConfig(u_char * cp, int plen, int mode)
418 {
419   char *request;
420   int type, length, mru, mtu;
421   u_long *lp, magic, accmap;
422   u_short *sp, proto;
423   struct lqrreq *req;
424 
425   ackp = AckBuff;
426   nakp = NakBuff;
427   rejp = RejBuff;
428 
429   while (plen >= sizeof(struct fsmconfig)) {
430     type = *cp;
431     length = cp[1];
432     if (type <= TY_ACFCOMP)
433       request = cftypes[type];
434     else
435       request = "???";
436 
437     switch (type) {
438     case TY_MRU:
439       sp = (u_short *) (cp + 2);
440       mru = htons(*sp);
441       LogPrintf(LogLCP, " %s %d\n", request, mru);
442 
443       switch (mode) {
444       case MODE_REQ:
445         mtu = VarPrefMTU;
446         if (mtu == 0)
447           mtu = MAX_MTU;
448 	if (mru > mtu) {
449 	  *sp = htons(mtu);
450 	  bcopy(cp, nakp, 4);
451 	  nakp += 4;
452 	} else if (mru < MIN_MRU) {
453 	  *sp = htons(MIN_MRU);
454 	  bcopy(cp, nakp, 4);
455 	  nakp += 4;
456 	} else {
457 	  LcpInfo.his_mru = mru;
458 	  bcopy(cp, ackp, 4);
459 	  ackp += 4;
460 	}
461 	break;
462       case MODE_NAK:
463 	if (mru >= MIN_MRU || mru <= MAX_MRU)
464 	  LcpInfo.want_mru = mru;
465 	break;
466       case MODE_REJ:
467 	LcpInfo.his_reject |= (1 << type);
468 	break;
469       }
470       break;
471     case TY_ACCMAP:
472       lp = (u_long *) (cp + 2);
473       accmap = htonl(*lp);
474       LogPrintf(LogLCP, " %s %08x\n", request, accmap);
475 
476       switch (mode) {
477       case MODE_REQ:
478 	LcpInfo.his_accmap = accmap;
479 	bcopy(cp, ackp, 6);
480 	ackp += 6;
481 	break;
482       case MODE_NAK:
483 	LcpInfo.want_accmap = accmap;
484 	break;
485       case MODE_REJ:
486 	LcpInfo.his_reject |= (1 << type);
487 	break;
488       }
489       break;
490     case TY_AUTHPROTO:
491       sp = (u_short *) (cp + 2);
492       proto = ntohs(*sp);
493       LogPrintf(LogLCP, " %s proto = %04x\n", request, proto);
494 
495       switch (mode) {
496       case MODE_REQ:
497 	switch (proto) {
498 	case PROTO_PAP:
499 	  if (length != 4) {
500 	    LogPrintf(LogLCP, " %s bad length (%d)\n", request, length);
501 	    goto reqreject;
502 	  }
503 	  if (Acceptable(ConfPap)) {
504 	    LcpInfo.his_auth = proto;
505 	    bcopy(cp, ackp, length);
506 	    ackp += length;
507 	  } else if (Acceptable(ConfChap)) {
508 	    *nakp++ = *cp;
509 	    *nakp++ = 5;
510 	    *nakp++ = (unsigned char) (PROTO_CHAP >> 8);
511 	    *nakp++ = (unsigned char) PROTO_CHAP;
512 	    *nakp++ = 5;
513 	  } else
514 	    goto reqreject;
515 	  break;
516 	case PROTO_CHAP:
517 	  if (length < 5) {
518 	    LogPrintf(LogLCP, " %s bad length (%d)\n", request, length);
519 	    goto reqreject;
520 	  }
521 #ifdef HAVE_DES
522           if (Acceptable(ConfChap) && (cp[4] == 5 || cp[4] == 0x80))
523 #else
524           if (Acceptable(ConfChap) && cp[4] == 5)
525 #endif
526 	  {
527 	    LcpInfo.his_auth = proto;
528 	    bcopy(cp, ackp, length);
529 	    ackp += length;
530 #ifdef HAVE_DES
531             VarMSChap = cp[4] = 0x80;
532 #endif
533 	  } else if (Acceptable(ConfPap)) {
534 	    *nakp++ = *cp;
535 	    *nakp++ = 4;
536 	    *nakp++ = (unsigned char) (PROTO_PAP >> 8);
537 	    *nakp++ = (unsigned char) PROTO_PAP;
538 	  } else
539 	    goto reqreject;
540 	  break;
541 	default:
542 	  LogPrintf(LogLCP, " %s not implemented, NAK.\n", request);
543 	  bcopy(cp, nakp, length);
544 	  nakp += length;
545 	  break;
546 	}
547 	break;
548       case MODE_NAK:
549 	break;
550       case MODE_REJ:
551 	LcpInfo.his_reject |= (1 << type);
552 	break;
553       }
554       break;
555     case TY_QUALPROTO:
556       req = (struct lqrreq *) cp;
557       LogPrintf(LogLCP, " %s proto: %x, interval: %dms\n",
558 		request, ntohs(req->proto), ntohl(req->period) * 10);
559       switch (mode) {
560       case MODE_REQ:
561 	if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr))
562 	  goto reqreject;
563 	else {
564 	  LcpInfo.his_lqrperiod = ntohl(req->period);
565 	  if (LcpInfo.his_lqrperiod < 500)
566 	    LcpInfo.his_lqrperiod = 500;
567 	  req->period = htonl(LcpInfo.his_lqrperiod);
568 	  bcopy(cp, ackp, length);
569 	  ackp += length;
570 	}
571 	break;
572       case MODE_NAK:
573 	break;
574       case MODE_REJ:
575 	LcpInfo.his_reject |= (1 << type);
576 	break;
577       }
578       break;
579     case TY_MAGICNUM:
580       lp = (u_long *) (cp + 2);
581       magic = ntohl(*lp);
582       LogPrintf(LogLCP, " %s %08x\n", request, magic);
583 
584       switch (mode) {
585       case MODE_REQ:
586 	if (LcpInfo.want_magic) {
587 	  /* Validate magic number */
588 	  if (magic == LcpInfo.want_magic) {
589 	    LogPrintf(LogLCP, "Magic is same (%08x) - %d times\n",
590                       magic, ++LcpFailedMagic);
591 	    LcpInfo.want_magic = GenerateMagic();
592 	    bcopy(cp, nakp, 6);
593 	    nakp += 6;
594             ualarm(TICKUNIT * (4 + 4 * LcpFailedMagic), 0);
595             sigpause(0);
596 	  } else {
597 	    LcpInfo.his_magic = magic;
598 	    bcopy(cp, ackp, length);
599 	    ackp += length;
600             LcpFailedMagic = 0;
601 	  }
602 	} else {
603 	  LcpInfo.my_reject |= (1 << type);
604 	  goto reqreject;
605 	}
606 	break;
607       case MODE_NAK:
608 	LogPrintf(LogLCP, " %s magic %08x has NAKed\n", request, magic);
609 	LcpInfo.want_magic = GenerateMagic();
610 	break;
611       case MODE_REJ:
612 	LogPrintf(LogLCP, " %s magic has REJected\n", request);
613 	LcpInfo.want_magic = 0;
614 	LcpInfo.his_reject |= (1 << type);
615 	break;
616       }
617       break;
618     case TY_PROTOCOMP:
619       LogPrintf(LogLCP, " %s\n", request);
620 
621       switch (mode) {
622       case MODE_REQ:
623 	if (Acceptable(ConfProtocomp)) {
624 	  LcpInfo.his_protocomp = 1;
625 	  bcopy(cp, ackp, 2);
626 	  ackp += 2;
627 	} else {
628 #ifdef OLDMST
629 
630 	  /*
631 	   * MorningStar before v1.3 needs NAK
632 	   */
633 	  bcopy(cp, nakp, 2);
634 	  nakp += 2;
635 #else
636 	  bcopy(cp, rejp, 2);
637 	  rejp += 2;
638 	  LcpInfo.my_reject |= (1 << type);
639 #endif
640 	}
641 	break;
642       case MODE_NAK:
643       case MODE_REJ:
644 	LcpInfo.want_protocomp = 0;
645 	LcpInfo.his_reject |= (1 << type);
646 	break;
647       }
648       break;
649     case TY_ACFCOMP:
650       LogPrintf(LogLCP, " %s\n", request);
651       switch (mode) {
652       case MODE_REQ:
653 	if (Acceptable(ConfAcfcomp)) {
654 	  LcpInfo.his_acfcomp = 1;
655 	  bcopy(cp, ackp, 2);
656 	  ackp += 2;
657 	} else {
658 #ifdef OLDMST
659 
660 	  /*
661 	   * MorningStar before v1.3 needs NAK
662 	   */
663 	  bcopy(cp, nakp, 2);
664 	  nakp += 2;
665 #else
666 	  bcopy(cp, rejp, 2);
667 	  rejp += 2;
668 	  LcpInfo.my_reject |= (1 << type);
669 #endif
670 	}
671 	break;
672       case MODE_NAK:
673       case MODE_REJ:
674 	LcpInfo.want_acfcomp = 0;
675 	LcpInfo.his_reject |= (1 << type);
676 	break;
677       }
678       break;
679     case TY_SDP:
680       LogPrintf(LogLCP, " %s\n", request);
681       switch (mode) {
682       case MODE_REQ:
683       case MODE_NAK:
684       case MODE_REJ:
685 	break;
686       }
687       break;
688     default:
689       LogPrintf(LogLCP, " ???[%02x]\n", type);
690       if (mode == MODE_REQ) {
691     reqreject:
692 	bcopy(cp, rejp, length);
693 	rejp += length;
694 	LcpInfo.my_reject |= (1 << type);
695       }
696       break;
697     }
698     /* to avoid inf. loop */
699     if (length == 0) {
700       LogPrintf(LogLCP, "LCP size zero\n");
701       break;
702     }
703     plen -= length;
704     cp += length;
705   }
706 }
707 
708 void
709 LcpInput(struct mbuf * bp)
710 {
711   FsmInput(&LcpFsm, bp);
712 }
713