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