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