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