xref: /freebsd/usr.sbin/ppp/lcp.c (revision ce834215a70ff69e7e222827437116eee2f9ac6f)
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.23 1997/06/09 03:27:24 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 "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 "loadalias.h"
37 #include "vars.h"
38 #include "auth.h"
39 #include <arpa/inet.h>
40 
41 extern void IpcpUp();
42 extern void IpcpOpen();
43 extern void StartPapChallenge();
44 extern void StartChapChallenge();
45 extern void SetLinkParams(struct lcpstate *);
46 extern void Prompt();
47 extern void StopIdleTimer();
48 extern void OsLinkdown();
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 
82   0,
83   { 0, 0, 0, NULL, NULL, NULL },
84 
85   LcpLayerUp,
86   LcpLayerDown,
87   LcpLayerStart,
88   LcpLayerFinish,
89   LcpInitRestartCounter,
90   LcpSendConfigReq,
91   LcpSendTerminateReq,
92   LcpSendTerminateAck,
93   LcpDecodeConfig,
94 };
95 
96 static struct pppTimer LcpReportTimer;
97 
98 char *PhaseNames[] = {
99   "Dead", "Establish", "Authenticate", "Network", "Terminate"
100 };
101 
102 void
103 NewPhase(new)
104 int new;
105 {
106   struct lcpstate *lcp = &LcpInfo;
107 
108   phase = new;
109   LogPrintf(LogPHASE, "NewPhase: %s\n", PhaseNames[phase]);
110   switch (phase) {
111   case PHASE_AUTHENTICATE:
112     lcp->auth_ineed = lcp->want_auth;
113     lcp->auth_iwait = lcp->his_auth;
114     if (lcp->his_auth || lcp->want_auth) {
115       LogPrintf(LogPHASE, " his = %x, mine = %x\n", lcp->his_auth, lcp->want_auth);
116       if (lcp->his_auth == PROTO_PAP)
117 	StartAuthChallenge(&AuthPapInfo);
118       if (lcp->want_auth == PROTO_CHAP)
119 	StartAuthChallenge(&AuthChapInfo);
120     } else
121       NewPhase(PHASE_NETWORK);
122     break;
123   case PHASE_NETWORK:
124     IpcpUp();
125     IpcpOpen();
126     CcpUp();
127     CcpOpen();
128     break;
129   case PHASE_DEAD:
130     if (mode & MODE_DIRECT)
131       Cleanup(EX_DEAD);
132     if (mode & MODE_BACKGROUND && reconnectState != RECON_TRUE)
133       Cleanup(EX_DEAD);
134     break;
135   }
136 }
137 
138 static void
139 LcpReportTime()
140 {
141   if (LogIsKept(LogDEBUG)) {
142     time_t t;
143 
144     time(&t);
145     LogPrintf(LogDEBUG, "LcpReportTime: %s", ctime(&t));
146   }
147   StopTimer(&LcpReportTimer);
148   LcpReportTimer.state = TIMER_STOPPED;
149   StartTimer(&LcpReportTimer);
150   HdlcErrorCheck();
151 }
152 
153 int
154 ReportLcpStatus()
155 {
156   struct lcpstate *lcp = &LcpInfo;
157   struct fsm *fp = &LcpFsm;
158 
159   if (!VarTerm)
160     return 1;
161 
162   fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]);
163   fprintf(VarTerm,
164     " his side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n"
165     "           REJECT %04lx\n",
166     lcp->his_mru, lcp->his_accmap, lcp->his_protocomp, lcp->his_acfcomp,
167     lcp->his_magic, lcp->his_reject);
168   fprintf(VarTerm,
169     " my  side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n"
170     "           REJECT %04lx\n",
171     lcp->want_mru, lcp->want_accmap, lcp->want_protocomp, lcp->want_acfcomp,
172     lcp->want_magic, lcp->my_reject);
173   fprintf(VarTerm, "\nDefaults:   MRU = %ld, ACCMAP = %08x\t", VarMRU, VarAccmap);
174   fprintf(VarTerm, "Open Mode: %s\n", (VarOpenMode == OPEN_ACTIVE)? "active" : "passive");
175   return 0;
176 }
177 
178 /*
179  * Generate random number which will be used as magic number.
180  */
181 u_long
182 GenerateMagic()
183 {
184   if (!randinit) {
185     randinit = 1;
186     srandomdev();
187   }
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)) 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(LogLCP, " %s [%d] %s\n",
242 	types[type], len, inet_ntoa(ina));
243     } else {
244       LogPrintf(LogLCP, " %s [%d] %08x\n", types[type], len, val);
245     }
246     *cp++ = (val >> 24) & 0377;
247     *cp++ = (val >> 16) & 0377;
248   } else
249     LogPrintf(LogLCP, " %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(LogLCP, "LcpSendConfigReq\n");
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(LogLCP, " %s\n", cftypes[TY_ACFCOMP]);
269     }
270     if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) {
271       *cp++ = TY_PROTOCOMP; *cp++ = 2;
272       LogPrintf(LogLCP, " %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(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     *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(LogLCP, "LcpSendProtoRej\n");
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(LogLCP, "LcpSendTerminateAck.\n");
324   FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
325 }
326 
327 static void
328 LcpLayerStart(fp)
329 struct fsm *fp;
330 {
331   LogPrintf(LogLCP, "LcpLayerStart\n");
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   LogPrintf(LogLCP, "LcpLayerFinish\n");
351   OsCloseLink(1);
352   NewPhase(PHASE_DEAD);
353   StopAllTimers();
354   (void)OsInterfaceDown(0);
355   Prompt();
356 }
357 
358 static void
359 LcpLayerUp(fp)
360 struct fsm *fp;
361 {
362   LogPrintf(LogLCP, "LcpLayerUp\n");
363   OsSetInterfaceParams(23, LcpInfo.his_mru, ModemSpeed());
364   SetLinkParams(&LcpInfo);
365 
366   NewPhase(PHASE_AUTHENTICATE);
367 
368   StartLqm();
369   StopTimer(&LcpReportTimer);
370   LcpReportTimer.state = TIMER_STOPPED;
371   LcpReportTimer.load = 60 * SECTICKS;
372   LcpReportTimer.func = LcpReportTime;
373   StartTimer(&LcpReportTimer);
374 }
375 
376 static void
377 LcpLayerDown(fp)
378 struct fsm *fp;
379 {
380   LogPrintf(LogLCP, "LcpLayerDown\n");
381   StopAllTimers();
382   OsLinkdown();
383   NewPhase(PHASE_TERMINATE);
384 }
385 
386 void
387 LcpUp()
388 {
389   FsmUp(&LcpFsm);
390 }
391 
392 void
393 LcpDown()			/* Sudden death */
394 {
395   NewPhase(PHASE_DEAD);
396   StopAllTimers();
397   FsmDown(&LcpFsm);
398 }
399 
400 void
401 LcpOpen(mode)
402 int mode;
403 {
404   LcpFsm.open_mode = mode;
405   FsmOpen(&LcpFsm);
406 }
407 
408 void
409 LcpClose()
410 {
411   FsmClose(&LcpFsm);
412 }
413 
414 /*
415  *	XXX: Should validate option length
416  */
417 static void
418 LcpDecodeConfig(cp, plen, mode)
419 u_char *cp;
420 int plen;
421 int mode;
422 {
423   char *request;
424   int type, length, mru;
425   u_long *lp, magic, accmap;
426   u_short *sp, proto;
427   struct lqrreq *req;
428 
429   ackp = AckBuff;
430   nakp = NakBuff;
431   rejp = RejBuff;
432 
433   while (plen >= sizeof(struct fsmconfig)) {
434     type = *cp;
435     length = cp[1];
436     if (type <= TY_ACFCOMP)
437       request = cftypes[type];
438     else
439       request = "???";
440 
441     switch (type) {
442     case TY_MRU:
443       sp = (u_short *)(cp + 2);
444       mru = htons(*sp);
445       LogPrintf(LogLCP, " %s %d\n", request, mru);
446 
447       switch (mode) {
448       case MODE_REQ:
449 	if (mru > MAX_MRU) {
450 	  *sp = htons(MAX_MRU);
451 	  bcopy(cp, nakp, 4); nakp += 4;
452 	} else if (mru < MIN_MRU) {
453 	  *sp = htons(MIN_MRU);
454 	  bcopy(cp, nakp, 4); nakp += 4;
455 	} else {
456 	  LcpInfo.his_mru = mru;
457 	  bcopy(cp, ackp, 4); ackp += 4;
458 	}
459 	break;
460       case MODE_NAK:
461 	if (mru >= MIN_MRU || mru <= MAX_MRU)
462 	  LcpInfo.want_mru = mru;
463 	break;
464       case MODE_REJ:
465 	LcpInfo.his_reject |= (1 << type);
466 	break;
467       }
468       break;
469     case TY_ACCMAP:
470       lp = (u_long *)(cp + 2);
471       accmap = htonl(*lp);
472       LogPrintf(LogLCP, " %s %08x\n", request, accmap);
473 
474       switch (mode) {
475       case MODE_REQ:
476 	LcpInfo.his_accmap = accmap;
477 	bcopy(cp, ackp, 6); ackp += 6;
478 	break;
479       case MODE_NAK:
480 	LcpInfo.want_accmap = accmap;
481 	break;
482       case MODE_REJ:
483 	LcpInfo.his_reject |= (1 << type);
484 	break;
485       }
486       break;
487     case TY_AUTHPROTO:
488       sp = (u_short *)(cp + 2);
489       proto = ntohs(*sp);
490       LogPrintf(LogLCP, " %s proto = %04x\n", request, proto);
491 
492       switch (mode) {
493       case MODE_REQ:
494 	switch (proto) {
495 	case PROTO_PAP:
496 	  if (length != 4) {
497 	    LogPrintf(LogLCP, " %s bad length (%d)\n", request, length);
498 	    goto reqreject;
499 	  }
500 	  if (Acceptable(ConfPap)) {
501 	    LcpInfo.his_auth = proto;
502 	    bcopy(cp, ackp, length); ackp += length;
503 	  } else if (Acceptable(ConfChap)) {
504 	    *nakp++ = *cp; *nakp++ = 5;
505 	    *nakp++ = (unsigned char)(PROTO_CHAP >> 8);
506 	    *nakp++ = (unsigned char)PROTO_CHAP;
507 	    *nakp++ = 5;
508 	  } else
509 	    goto reqreject;
510 	  break;
511 	case PROTO_CHAP:
512 	  if (length < 5) {
513 	    LogPrintf(LogLCP, " %s bad length (%d)\n", request, length);
514 	    goto reqreject;
515 	  }
516 	  if (Acceptable(ConfChap) && cp[4] == 5) {
517 	    LcpInfo.his_auth = proto;
518 	    bcopy(cp, ackp, length); ackp += length;
519 	  } else if (Acceptable(ConfPap)) {
520 	    *nakp++ = *cp; *nakp++ = 4;
521 	    *nakp++ = (unsigned char)(PROTO_PAP >> 8);
522 	    *nakp++ = (unsigned char)PROTO_PAP;
523 	  } else
524 	    goto reqreject;
525 	  break;
526 	default:
527  	    LogPrintf(LogLCP, " %s not implemented, NAK.\n", request);
528             bcopy(cp, nakp, length);
529             nakp += length;
530             break;
531 	}
532 	break;
533       case MODE_NAK:
534 	break;
535       case MODE_REJ:
536 	LcpInfo.his_reject |= (1 << type);
537 	break;
538       }
539       break;
540     case TY_QUALPROTO:
541       req = (struct lqrreq *)cp;
542       LogPrintf(LogLCP, " %s proto: %x, interval: %dms\n",
543 		request, ntohs(req->proto), ntohl(req->period)*10);
544       switch (mode) {
545       case MODE_REQ:
546 	if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr))
547 	  goto reqreject;
548 	else {
549 	  LcpInfo.his_lqrperiod = ntohl(req->period);
550 	  if (LcpInfo.his_lqrperiod < 500)
551 	    LcpInfo.his_lqrperiod = 500;
552 	  req->period = htonl(LcpInfo.his_lqrperiod);
553 	  bcopy(cp, ackp, length); ackp += length;
554 	}
555 	break;
556       case MODE_NAK:
557 	break;
558       case MODE_REJ:
559 	LcpInfo.his_reject |= (1 << type);
560 	break;
561       }
562       break;
563     case TY_MAGICNUM:
564       lp = (u_long *)(cp + 2);
565       magic = ntohl(*lp);
566       LogPrintf(LogLCP, " %s %08x\n", request, magic);
567 
568       switch (mode) {
569       case MODE_REQ:
570 	if (LcpInfo.want_magic) {
571 	  /* Validate magic number */
572 	  if (magic == LcpInfo.want_magic) {
573 	    LogPrintf(LogLCP, "Magic is same (%08x)\n", magic);
574 	    LcpInfo.want_magic = GenerateMagic();
575 	    bcopy(cp, nakp, 6);
576             nakp += 6;
577           } else {
578 	    LcpInfo.his_magic = magic;
579 	    bcopy(cp, ackp, length); ackp += length;
580           }
581 	} else {
582 	  LcpInfo.my_reject |= (1 << type);
583 	  goto reqreject;
584 	}
585 	break;
586       case MODE_NAK:
587 	LogPrintf(LogLCP, " %s magic %08x has NAKed\n", request, magic);
588 	LcpInfo.want_magic = GenerateMagic();
589 	break;
590       case MODE_REJ:
591 	LogPrintf(LogLCP, " %s magic has REJected\n", request);
592 	LcpInfo.want_magic = 0;
593 	LcpInfo.his_reject |= (1 << type);
594 	break;
595       }
596       break;
597     case TY_PROTOCOMP:
598       LogPrintf(LogLCP, " %s\n", request);
599 
600       switch (mode) {
601       case MODE_REQ:
602         if (Acceptable(ConfProtocomp)) {
603 	  LcpInfo.his_protocomp = 1;
604 	  bcopy(cp, ackp, 2); ackp += 2;
605         } else {
606 #ifdef OLDMST
607 	  /*
608 	   * MorningStar before v1.3 needs NAK
609 	   */
610 	  bcopy(cp, nakp, 2); nakp += 2;
611 #else
612 	  bcopy(cp, rejp, 2); rejp += 2;
613 	  LcpInfo.my_reject |= (1 << type);
614 #endif
615         }
616 	break;
617       case MODE_NAK:
618       case MODE_REJ:
619 	LcpInfo.want_protocomp = 0;
620 	LcpInfo.his_reject |= (1 << type);
621 	break;
622       }
623       break;
624     case TY_ACFCOMP:
625       LogPrintf(LogLCP, " %s\n", request);
626       switch (mode) {
627       case MODE_REQ:
628         if (Acceptable(ConfAcfcomp)) {
629 	  LcpInfo.his_acfcomp = 1;
630 	  bcopy(cp, ackp, 2);
631 	  ackp += 2;
632         } else {
633 #ifdef OLDMST
634 	  /*
635 	   * MorningStar before v1.3 needs NAK
636 	   */
637 	  bcopy(cp, nakp, 2);
638 	  nakp += 2;
639 #else
640 	  bcopy(cp, rejp, 2);
641 	  rejp += 2;
642 	  LcpInfo.my_reject |= (1 << type);
643 #endif
644 	}
645 	break;
646       case MODE_NAK:
647       case MODE_REJ:
648 	LcpInfo.want_acfcomp = 0;
649 	LcpInfo.his_reject |= (1 << type);
650 	break;
651       }
652       break;
653     case TY_SDP:
654       LogPrintf(LogLCP, " %s\n", request);
655       switch (mode) {
656       case MODE_REQ:
657       case MODE_NAK:
658       case MODE_REJ:
659 	break;
660       }
661       break;
662     default:
663       LogPrintf(LogLCP, " ???[%02x]\n", type);
664       if (mode == MODE_REQ) {
665 reqreject:
666         bcopy(cp, rejp, length);
667         rejp += length;
668         LcpInfo.my_reject |= (1 << type);
669       }
670       break;
671     }
672     /* to avoid inf. loop */
673     if (length == 0) {
674       LogPrintf(LogLCP, "LCP size zero\n");
675       break;
676     }
677 
678     plen -= length;
679     cp += length;
680   }
681 }
682 
683 void
684 LcpInput(struct mbuf *bp)
685 {
686   FsmInput(&LcpFsm, bp);
687 }
688