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