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