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