xref: /freebsd/usr.sbin/ppp/lcp.c (revision 8e6b01171e30297084bb0b4457c4183c2746aacc)
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.5 1995/07/08 05:09:57 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   StopLqr( LQM_LQR );
376   OsLinkdown();
377   NewPhase(PHASE_TERMINATE);
378 }
379 
380 void
381 LcpUp()
382 {
383   FsmUp(&LcpFsm);
384 }
385 
386 void
387 LcpDown()			/* Sudden death */
388 {
389   NewPhase(PHASE_DEAD);
390   StopAllTimers();
391   FsmDown(&LcpFsm);
392 }
393 
394 void
395 LcpOpen(mode)
396 int mode;
397 {
398   LcpFsm.open_mode = mode;
399   FsmOpen(&LcpFsm);
400 }
401 
402 void
403 LcpClose()
404 {
405   FsmClose(&LcpFsm);
406 }
407 
408 /*
409  *	XXX: Should validate option length
410  */
411 static void
412 LcpDecodeConfig(cp, plen, mode)
413 u_char *cp;
414 int plen;
415 int mode;
416 {
417   char *request;
418   int type, length, mru;
419   u_long *lp, magic, accmap;
420   u_short *sp, proto;
421   struct lqrreq *req;
422 
423   ackp = AckBuff;
424   nakp = NakBuff;
425   rejp = RejBuff;
426 
427   while (plen >= sizeof(struct fsmconfig)) {
428     type = *cp;
429     length = cp[1];
430     if (type <= TY_ACFCOMP)
431       request = cftypes[type];
432     else
433       request = "???";
434 
435     switch (type) {
436     case TY_MRU:
437       sp = (u_short *)(cp + 2);
438       mru = htons(*sp);
439       LogPrintf(LOG_LCP, " %s %d\n", request, mru);
440 
441       switch (mode) {
442       case MODE_REQ:
443 	if (mru > MAX_MRU) {
444 	  *sp = htons(MAX_MRU);
445 	  bcopy(cp, nakp, 4); nakp += 4;
446 	} else if (mru < MIN_MRU) {
447 	  *sp = htons(MIN_MRU);
448 	  bcopy(cp, nakp, 4); nakp += 4;
449 	} else {
450 	  LcpInfo.his_mru = mru;
451 	  bcopy(cp, ackp, 4); ackp += 4;
452 	}
453 	break;
454       case MODE_NAK:
455 	if (mru >= MIN_MRU || mru <= MAX_MRU)
456 	  LcpInfo.want_mru = mru;
457 	break;
458       case MODE_REJ:
459 	LcpInfo.his_reject |= (1 << type);
460 	break;
461       }
462       break;
463     case TY_ACCMAP:
464       lp = (u_long *)(cp + 2);
465       accmap = htonl(*lp);
466       LogPrintf(LOG_LCP, " %s %08x\n", request, accmap);
467 
468       switch (mode) {
469       case MODE_REQ:
470 	LcpInfo.his_accmap = accmap;
471 	bcopy(cp, ackp, 6); ackp += 6;
472 	break;
473       case MODE_NAK:
474 	LcpInfo.want_accmap = accmap;
475 	break;
476       case MODE_REJ:
477 	LcpInfo.his_reject |= (1 << type);
478 	break;
479       }
480       break;
481     case TY_AUTHPROTO:
482       sp = (u_short *)(cp + 2);
483       proto = ntohs(*sp);
484       LogPrintf(LOG_LCP, " %s proto = %04x\n", request, proto);
485 
486       switch (mode) {
487       case MODE_REQ:
488 	switch (proto) {
489 	case PROTO_PAP:
490 	  if (length != 4) {
491 	    LogPrintf(LOG_LCP, " %s bad length (%d)\n", request, length);
492 	    goto reqreject;
493 	  }
494 	  if (Acceptable(ConfPap)) {
495 	    LcpInfo.his_auth = proto;
496 	    bcopy(cp, ackp, length); ackp += length;
497 	  } else if (Acceptable(ConfChap)) {
498 	    *nakp++ = *cp; *nakp++ = 5;
499 	    *nakp++ = (unsigned char)(PROTO_CHAP >> 8);
500 	    *nakp++ = (unsigned char)PROTO_CHAP;
501 	    *nakp++ = 5;
502 	  } else
503 	    goto reqreject;
504 	  break;
505 	case PROTO_CHAP:
506 	  if (length < 5) {
507 	    LogPrintf(LOG_LCP, " %s bad length (%d)\n", request, length);
508 	    goto reqreject;
509 	  }
510 	  if (Acceptable(ConfChap) && cp[4] == 5) {
511 	    LcpInfo.his_auth = proto;
512 	    bcopy(cp, ackp, length); ackp += length;
513 	  } else if (Acceptable(ConfPap)) {
514 	    *nakp++ = *cp; *nakp++ = 4;
515 	    *nakp++ = (unsigned char)(PROTO_PAP >> 8);
516 	    *nakp++ = (unsigned char)PROTO_PAP;
517 	  } else
518 	    goto reqreject;
519 	  break;
520 	default:
521  	    LogPrintf(LOG_LCP, " %s not implemented, NAK.\n", request);
522             bcopy(cp, nakp, length);
523             nakp += length;
524             break;
525 	}
526 	break;
527       case MODE_NAK:
528 	break;
529       case MODE_REJ:
530 	LcpInfo.his_reject |= (1 << type);
531 	break;
532       }
533       break;
534     case TY_QUALPROTO:
535       req = (struct lqrreq *)cp;
536       LogPrintf(LOG_LCP, " %s proto: %x, interval: %dms\n",
537 		request, ntohs(req->proto), ntohl(req->period)*10);
538       switch (mode) {
539       case MODE_REQ:
540 	if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr))
541 	  goto reqreject;
542 	else {
543 	  LcpInfo.his_lqrperiod = ntohl(req->period);
544 	  if (LcpInfo.his_lqrperiod < 500)
545 	    LcpInfo.his_lqrperiod = 500;
546 	  req->period = htonl(LcpInfo.his_lqrperiod);
547 	  bcopy(cp, ackp, length); ackp += length;
548 	}
549 	break;
550       case MODE_NAK:
551 	break;
552       case MODE_REJ:
553 	LcpInfo.his_reject |= (1 << type);
554 	break;
555       }
556       break;
557     case TY_MAGICNUM:
558       lp = (u_long *)(cp + 2);
559       magic = ntohl(*lp);
560       LogPrintf(LOG_LCP, " %s %08x\n", request, magic);
561 
562       switch (mode) {
563       case MODE_REQ:
564 	if (LcpInfo.want_magic) {
565 	  /* XXX: Shoud validate magic number */
566 	  if (magic == LcpInfo.want_magic)
567 	    logprintf("magic is same!! %x, %x, %x\n",
568 		magic, LcpInfo.want_magic, LcpInfo.his_magic);
569 	  LcpInfo.his_magic = magic;
570 	  bcopy(cp, ackp, length); ackp += length;
571 	} else {
572 	  LcpInfo.my_reject |= (1 << type);
573 	  goto reqreject;
574 	}
575 	break;
576       case MODE_NAK:
577 	LogPrintf(LOG_LCP, " %s magic %08x has NAKed\n", request, magic);
578 	LcpInfo.want_magic = GenerateMagic();
579 	break;
580       case MODE_REJ:
581 	LogPrintf(LOG_LCP, " %s magic has REJected\n", request);
582 	LcpInfo.want_magic = 0;
583 	LcpInfo.his_reject |= (1 << type);
584 	break;
585       }
586       break;
587     case TY_PROTOCOMP:
588       LogPrintf(LOG_LCP, " %s\n", request);
589 
590       switch (mode) {
591       case MODE_REQ:
592         if (Acceptable(ConfProtocomp)) {
593 	  LcpInfo.his_protocomp = 1;
594 	  bcopy(cp, ackp, 2); ackp += 2;
595         } else {
596 #ifdef OLDMST
597 	  /*
598 	   * MorningStar before v1.3 needs NAK
599 	   */
600 	  bcopy(cp, nakp, 2); nakp += 2;
601 #else
602 	  bcopy(cp, rejp, 2); rejp += 2;
603 	  LcpInfo.my_reject |= (1 << type);
604 #endif
605         }
606 	break;
607       case MODE_NAK:
608       case MODE_REJ:
609 	LcpInfo.want_protocomp = 0;
610 	LcpInfo.his_reject |= (1 << type);
611 	break;
612       }
613       break;
614     case TY_ACFCOMP:
615       LogPrintf(LOG_LCP, " %s\n", request);
616       switch (mode) {
617       case MODE_REQ:
618         if (Acceptable(ConfAcfcomp)) {
619 	  LcpInfo.his_acfcomp = 1;
620 	  bcopy(cp, ackp, 2);
621 	  ackp += 2;
622         } else {
623 #ifdef OLDMST
624 	  /*
625 	   * MorningStar before v1.3 needs NAK
626 	   */
627 	  bcopy(cp, nakp, 2);
628 	  nakp += 2;
629 #else
630 	  bcopy(cp, rejp, 2);
631 	  rejp += 2;
632 	  LcpInfo.my_reject |= (1 << type);
633 #endif
634 	}
635 	break;
636       case MODE_NAK:
637       case MODE_REJ:
638 	LcpInfo.want_acfcomp = 0;
639 	LcpInfo.his_reject |= (1 << type);
640 	break;
641       }
642       break;
643     case TY_SDP:
644       LogPrintf(LOG_LCP, " %s\n", request);
645       switch (mode) {
646       case MODE_REQ:
647       case MODE_NAK:
648       case MODE_REJ:
649 	break;
650       }
651       break;
652     default:
653       LogPrintf(LOG_LCP, " ???[%02x]\n", type);
654       if (mode == MODE_REQ) {
655 reqreject:
656         bcopy(cp, rejp, length);
657         rejp += length;
658         LcpInfo.my_reject |= (1 << type);
659       }
660       break;
661     }
662     plen -= length;
663     cp += length;
664   }
665 }
666 
667 void
668 LcpInput(struct mbuf *bp)
669 {
670   FsmInput(&LcpFsm, bp);
671 }
672