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