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