ccp.c revision 32381
16059Samurai/*
26059Samurai *	   PPP Compression Control Protocol (CCP) Module
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
198857Srgrimes *
2032381Sbrian * $Id: ccp.c,v 1.27 1998/01/04 20:25:39 brian Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o Support other compression protocols
246059Samurai */
2530715Sbrian#include <sys/param.h>
2630715Sbrian#include <netinet/in.h>
2730715Sbrian
2830715Sbrian#include <stdio.h>
2930715Sbrian#include <string.h>
3030715Sbrian
3131343Sbrian#include "command.h"
3230715Sbrian#include "mbuf.h"
3330715Sbrian#include "log.h"
3430715Sbrian#include "defs.h"
3530715Sbrian#include "timer.h"
366059Samurai#include "fsm.h"
376059Samurai#include "lcpproto.h"
386059Samurai#include "lcp.h"
396059Samurai#include "ccp.h"
406059Samurai#include "phase.h"
4126142Sbrian#include "loadalias.h"
426059Samurai#include "vars.h"
4313389Sphk#include "pred.h"
4431514Sbrian#include "deflate.h"
458857Srgrimes
4632381Sbrianstruct ccpstate CcpInfo = { -1, -1, -1, -1 };
476059Samurai
4826516Sbrianstatic void CcpSendConfigReq(struct fsm *);
4930715Sbrianstatic void CcpSendTerminateReq(struct fsm *);
5030715Sbrianstatic void CcpSendTerminateAck(struct fsm *);
5130715Sbrianstatic void CcpDecodeConfig(u_char *, int, int);
5226516Sbrianstatic void CcpLayerStart(struct fsm *);
5326516Sbrianstatic void CcpLayerFinish(struct fsm *);
5426516Sbrianstatic void CcpLayerUp(struct fsm *);
5526516Sbrianstatic void CcpLayerDown(struct fsm *);
5626516Sbrianstatic void CcpInitRestartCounter(struct fsm *);
576059Samurai
586059Samuraistruct fsm CcpFsm = {
596059Samurai  "CCP",
606059Samurai  PROTO_CCP,
616059Samurai  CCP_MAXCODE,
626059Samurai  OPEN_ACTIVE,
636059Samurai  ST_INITIAL,
646059Samurai  0, 0, 0,
656059Samurai  0,
6628679Sbrian  {0, 0, 0, NULL, NULL, NULL},
6728679Sbrian  {0, 0, 0, NULL, NULL, NULL},
6828461Sbrian  LogCCP,
696059Samurai
706059Samurai  CcpLayerUp,
716059Samurai  CcpLayerDown,
726059Samurai  CcpLayerStart,
736059Samurai  CcpLayerFinish,
746059Samurai  CcpInitRestartCounter,
756059Samurai  CcpSendConfigReq,
766059Samurai  CcpSendTerminateReq,
776059Samurai  CcpSendTerminateAck,
786059Samurai  CcpDecodeConfig,
796059Samurai};
806059Samurai
8113760Sphkstatic char const *cftypes[] = {
8231171Sbrian  /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
8331518Sbrian  "OUI",		/* 0: OUI */
8431518Sbrian  "PRED1",		/* 1: Predictor type 1 */
8531518Sbrian  "PRED2",		/* 2: Predictor type 2 */
8631518Sbrian  "PUDDLE",		/* 3: Puddle Jumber */
8731518Sbrian  "???", "???", "???", "???", "???", "???",
8831518Sbrian  "???", "???", "???", "???", "???", "???",
8931518Sbrian  "HWPPC",		/* 16: Hewlett-Packard PPC */
9031518Sbrian  "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
9131518Sbrian  "MSPPC",		/* 18: Microsoft PPC */
9231518Sbrian  "GAND",		/* 19: Gandalf FZA (rfc1993) */
9331518Sbrian  "V42BIS",		/* 20: ARG->DATA.42bis compression */
9431518Sbrian  "BSD",		/* 21: BSD LZW Compress */
9531518Sbrian  "???",
9631518Sbrian  "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
9731518Sbrian  "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
9831518Sbrian			/* 24: Deflate (according to pppd-2.3.1) */
9931518Sbrian  "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
10031518Sbrian  "DEFLATE",		/* 26: Deflate (rfc1979) */
1016059Samurai};
1026059Samurai
10331962Sbrian#define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
10431171Sbrian
10531514Sbrianstatic const char *
10631514Sbrianprotoname(int proto)
10731514Sbrian{
10831514Sbrian  if (proto < 0 || proto > NCFTYPES)
10931514Sbrian    return "none";
11031514Sbrian  return cftypes[proto];
11131514Sbrian}
11231514Sbrian
11331518Sbrian/* We support these algorithms, and Req them in the given order */
11431514Sbrianstatic const struct ccp_algorithm *algorithm[] = {
11531518Sbrian  &DeflateAlgorithm,
11631514Sbrian  &Pred1Algorithm,
11731518Sbrian  &PppdDeflateAlgorithm
11831514Sbrian};
11931514Sbrian
12031514Sbrianstatic int in_algorithm = -1;
12131514Sbrianstatic int out_algorithm = -1;
12231962Sbrian#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
12331514Sbrian
12425630Sbrianint
12531343SbrianReportCcpStatus(struct cmdargs const *arg)
1266059Samurai{
12726516Sbrian  if (VarTerm) {
12831539Sbrian    fprintf(VarTerm, "%s [%s]\n", CcpFsm.name, StateNames[CcpFsm.state]);
12931514Sbrian    fprintf(VarTerm, "My protocol = %s, His protocol = %s\n",
13031539Sbrian            protoname(CcpInfo.my_proto), protoname(CcpInfo.his_proto));
13131514Sbrian    fprintf(VarTerm, "Output: %ld --> %ld,  Input: %ld --> %ld\n",
13231539Sbrian            CcpInfo.uncompout, CcpInfo.compout,
13331539Sbrian            CcpInfo.compin, CcpInfo.uncompin);
13426516Sbrian  }
13525630Sbrian  return 0;
1366059Samurai}
1376059Samurai
13831539Sbrianstatic void
13931539SbrianccpstateInit(void)
1406059Samurai{
14132246Sbrian  if (CcpInfo.in_init)
14232246Sbrian    (*algorithm[in_algorithm]->i.Term)();
14332246Sbrian  if (CcpInfo.out_init)
14432246Sbrian    (*algorithm[out_algorithm]->o.Term)();
14532246Sbrian  in_algorithm = -1;
14632246Sbrian  out_algorithm = -1;
14731962Sbrian  memset(&CcpInfo, '\0', sizeof CcpInfo);
14831539Sbrian  CcpInfo.his_proto = CcpInfo.my_proto = -1;
14932381Sbrian  CcpInfo.reset_sent = CcpInfo.last_reset = -1;
15031539Sbrian}
15131539Sbrian
15231539Sbrianvoid
15331539SbrianCcpInit()
15431539Sbrian{
15531539Sbrian  FsmInit(&CcpFsm);
15631539Sbrian  ccpstateInit();
1576059Samurai  CcpFsm.maxconfig = 10;
1586059Samurai}
1596059Samurai
1606059Samuraistatic void
16130715SbrianCcpInitRestartCounter(struct fsm *fp)
1626059Samurai{
1636735Samurai  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
1646059Samurai  fp->restart = 5;
1656059Samurai}
1666059Samurai
1676059Samuraistatic void
16830715SbrianCcpSendConfigReq(struct fsm *fp)
1696059Samurai{
1706059Samurai  u_char *cp;
17131514Sbrian  int f;
1726059Samurai
17331514Sbrian  LogPrintf(LogCCP, "CcpSendConfigReq\n");
1746059Samurai  cp = ReqBuff;
17531514Sbrian  CcpInfo.my_proto = -1;
17631514Sbrian  out_algorithm = -1;
17731514Sbrian  for (f = 0; f < NALGORITHMS; f++)
17831539Sbrian    if (Enabled(algorithm[f]->Conf) && !REJECTED(&CcpInfo, algorithm[f]->id)) {
17931514Sbrian      struct lcp_opt o;
18031514Sbrian
18131514Sbrian      (*algorithm[f]->o.Get)(&o);
18231514Sbrian      cp += LcpPutConf(LogCCP, cp, &o, cftypes[o.id],
18331514Sbrian                       (*algorithm[f]->Disp)(&o));
18431514Sbrian      CcpInfo.my_proto = o.id;
18531514Sbrian      out_algorithm = f;
18631514Sbrian    }
1876059Samurai  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
1886059Samurai}
1896059Samurai
1906059Samuraivoid
19130715SbrianCcpSendResetReq(struct fsm *fp)
1926059Samurai{
19332381Sbrian  LogPrintf(LogCCP, "SendResetReq(%d)\n", fp->reqid);
19432381Sbrian  CcpInfo.reset_sent = fp->reqid;
19532381Sbrian  CcpInfo.last_reset = -1;
1966059Samurai  FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
1976059Samurai}
1986059Samurai
1996059Samuraistatic void
20030715SbrianCcpSendTerminateReq(struct fsm *fp)
2016059Samurai{
2026059Samurai  /* XXX: No code yet */
2036059Samurai}
2046059Samurai
2056059Samuraistatic void
20630715SbrianCcpSendTerminateAck(struct fsm *fp)
2076059Samurai{
20828461Sbrian  LogPrintf(LogCCP, "CcpSendTerminateAck\n");
2096059Samurai  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
2106059Samurai}
2116059Samurai
2126059Samuraivoid
21330715SbrianCcpRecvResetReq(struct fsm *fp)
2146059Samurai{
21531514Sbrian  if (out_algorithm >= 0 && out_algorithm < NALGORITHMS)
21631514Sbrian    (*algorithm[out_algorithm]->o.Reset)();
2176059Samurai}
2186059Samurai
2196059Samuraistatic void
22030715SbrianCcpLayerStart(struct fsm *fp)
2216059Samurai{
22228461Sbrian  LogPrintf(LogCCP, "CcpLayerStart.\n");
2236059Samurai}
2246059Samurai
2256059Samuraistatic void
22630715SbrianCcpLayerFinish(struct fsm *fp)
2276059Samurai{
22828461Sbrian  LogPrintf(LogCCP, "CcpLayerFinish.\n");
22931539Sbrian  ccpstateInit();
2306059Samurai}
2316059Samurai
2326059Samuraistatic void
23330715SbrianCcpLayerDown(struct fsm *fp)
2346059Samurai{
23528461Sbrian  LogPrintf(LogCCP, "CcpLayerDown.\n");
23631539Sbrian  ccpstateInit();
2376059Samurai}
2386059Samurai
2396059Samurai/*
24031514Sbrian *  Called when CCP has reached the OPEN state
2416059Samurai */
2426059Samuraistatic void
24330715SbrianCcpLayerUp(struct fsm *fp)
2446059Samurai{
24528461Sbrian  LogPrintf(LogCCP, "CcpLayerUp(%d).\n", fp->state);
24631514Sbrian  LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n",
24731514Sbrian            protoname(CcpInfo.my_proto), CcpInfo.my_proto,
24831514Sbrian            protoname(CcpInfo.his_proto), CcpInfo.his_proto);
24932246Sbrian  if (!CcpInfo.in_init && in_algorithm >= 0 && in_algorithm < NALGORITHMS) {
25031514Sbrian    (*algorithm[in_algorithm]->i.Init)();
25132246Sbrian    CcpInfo.in_init = 1;
25232246Sbrian  }
25332246Sbrian  if (!CcpInfo.out_init && out_algorithm >= 0 && out_algorithm < NALGORITHMS) {
25431514Sbrian    (*algorithm[out_algorithm]->o.Init)();
25532246Sbrian    CcpInfo.out_init = 1;
25632246Sbrian  }
2576059Samurai}
2586059Samurai
2596059Samuraivoid
2606059SamuraiCcpUp()
2616059Samurai{
2626059Samurai  FsmUp(&CcpFsm);
26328461Sbrian  LogPrintf(LogCCP, "CCP Up event!!\n");
2646059Samurai}
2656059Samurai
2666059Samuraivoid
2676059SamuraiCcpOpen()
2686059Samurai{
26931514Sbrian  int f;
27031514Sbrian
27131514Sbrian  for (f = 0; f < NALGORITHMS; f++)
27231514Sbrian    if (Enabled(algorithm[f]->Conf)) {
27331514Sbrian      CcpFsm.open_mode = OPEN_ACTIVE;
27431514Sbrian      FsmOpen(&CcpFsm);
27531514Sbrian      break;
27631514Sbrian    }
27731514Sbrian
27831514Sbrian  if (f == NALGORITHMS)
27931514Sbrian    for (f = 0; f < NALGORITHMS; f++)
28031514Sbrian      if (Acceptable(algorithm[f]->Conf)) {
28131514Sbrian        CcpFsm.open_mode = OPEN_PASSIVE;
28231514Sbrian        FsmOpen(&CcpFsm);
28331514Sbrian        break;
28431514Sbrian      }
2856059Samurai}
2866059Samurai
2876059Samuraistatic void
28831034SbrianCcpDecodeConfig(u_char *cp, int plen, int mode_type)
2896059Samurai{
2906735Samurai  int type, length;
29131514Sbrian  int f;
2926059Samurai
2936059Samurai  ackp = AckBuff;
2946059Samurai  nakp = NakBuff;
2956059Samurai  rejp = RejBuff;
2966059Samurai
2976059Samurai  while (plen >= sizeof(struct fsmconfig)) {
2986059Samurai    type = *cp;
2996059Samurai    length = cp[1];
30031171Sbrian    if (type < NCFTYPES)
30131514Sbrian      LogPrintf(LogCCP, " %s[%d]\n", cftypes[type], length);
3026059Samurai    else
30331514Sbrian      LogPrintf(LogCCP, " ???[%d]\n", length);
3046059Samurai
30531514Sbrian    for (f = NALGORITHMS-1; f > -1; f--)
30631514Sbrian      if (algorithm[f]->id == type)
30731514Sbrian        break;
3086059Samurai
30931514Sbrian    if (f == -1) {
31031514Sbrian      /* Don't understand that :-( */
31131514Sbrian      if (mode_type == MODE_REQ) {
31231514Sbrian        CcpInfo.my_reject |= (1 << type);
31331514Sbrian        memcpy(rejp, cp, length);
31431514Sbrian        rejp += length;
31531514Sbrian      }
31631514Sbrian    } else {
31731514Sbrian      struct lcp_opt o;
31831514Sbrian
31931034Sbrian      switch (mode_type) {
3206059Samurai      case MODE_REQ:
32131514Sbrian	if (Acceptable(algorithm[f]->Conf) && in_algorithm == -1) {
32231514Sbrian	  memcpy(&o, cp, length);
32331514Sbrian          switch ((*algorithm[f]->i.Set)(&o)) {
32431514Sbrian          case MODE_REJ:
32531514Sbrian	    memcpy(rejp, &o, o.len);
32631514Sbrian	    rejp += o.len;
32731514Sbrian            break;
32831514Sbrian          case MODE_NAK:
32931514Sbrian	    memcpy(nakp, &o, o.len);
33031514Sbrian	    nakp += o.len;
33131514Sbrian            break;
33231514Sbrian          case MODE_ACK:
33331514Sbrian	    memcpy(ackp, cp, length);
33431514Sbrian	    ackp += length;
33531514Sbrian	    CcpInfo.his_proto = type;
33631514Sbrian            in_algorithm = f;		/* This one'll do ! */
33731514Sbrian            break;
33831514Sbrian          }
3396059Samurai	} else {
34030715Sbrian	  memcpy(rejp, cp, length);
3416059Samurai	  rejp += length;
3426059Samurai	}
3436059Samurai	break;
3446059Samurai      case MODE_NAK:
34531514Sbrian	memcpy(&o, cp, length);
34631514Sbrian        if ((*algorithm[f]->o.Set)(&o) == MODE_ACK)
34731514Sbrian          CcpInfo.my_proto = algorithm[f]->id;
34831514Sbrian        else {
34931514Sbrian	  CcpInfo.his_reject |= (1 << type);
35031514Sbrian	  CcpInfo.my_proto = -1;
35131514Sbrian        }
35231514Sbrian        break;
3536059Samurai      case MODE_REJ:
3546059Samurai	CcpInfo.his_reject |= (1 << type);
35531514Sbrian	CcpInfo.my_proto = -1;
3566059Samurai	break;
3576059Samurai      }
3586059Samurai    }
35931514Sbrian
3606059Samurai    plen -= length;
3616059Samurai    cp += length;
3626059Samurai  }
36331514Sbrian
36431514Sbrian  if (rejp != RejBuff) {
36531514Sbrian    ackp = AckBuff;	/* let's not send both ! */
36631514Sbrian    CcpInfo.his_proto = -1;
36731514Sbrian    in_algorithm = -1;
36831514Sbrian  }
3696059Samurai}
3706059Samurai
3716059Samuraivoid
37230715SbrianCcpInput(struct mbuf *bp)
3736059Samurai{
3746059Samurai  if (phase == PHASE_NETWORK)
3756059Samurai    FsmInput(&CcpFsm, bp);
3766059Samurai  else {
37729294Sbrian    if (phase > PHASE_NETWORK)
37831690Sbrian      LogPrintf(LogCCP, "Error: Unexpected CCP in phase %d\n", phase);
3796059Samurai    pfree(bp);
3806059Samurai  }
3816059Samurai}
38231514Sbrian
38331514Sbrianvoid
38432381SbrianCcpResetInput(u_char id)
38531514Sbrian{
38632381Sbrian  if (CcpInfo.reset_sent != -1) {
38732381Sbrian    if (id != CcpInfo.reset_sent) {
38832381Sbrian      LogPrintf(LogWARN, "CCP: Incorrect ResetAck (id %d, not %d) ignored\n",
38932381Sbrian                id, CcpInfo.reset_sent);
39032381Sbrian      return;
39132381Sbrian    }
39232381Sbrian    /* Whaddaya know - a correct reset ack */
39332381Sbrian  } else if (id == CcpInfo.last_reset)
39432381Sbrian    LogPrintf(LogCCP, "Duplicate ResetAck (resetting again)\n");
39532381Sbrian  else {
39632381Sbrian    LogPrintf(LogWARN, "CCP: Unexpected ResetAck (id %d) ignored\n", id);
39732381Sbrian    return;
39832381Sbrian  }
39932381Sbrian
40032381Sbrian  CcpInfo.last_reset = CcpInfo.reset_sent;
40132381Sbrian  CcpInfo.reset_sent = -1;
40231514Sbrian  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
40331514Sbrian    (*algorithm[in_algorithm]->i.Reset)();
40431514Sbrian}
40531514Sbrian
40631514Sbrianint
40731514SbrianCcpOutput(int pri, u_short proto, struct mbuf *m)
40831514Sbrian{
40931514Sbrian  if (out_algorithm >= 0 && out_algorithm < NALGORITHMS)
41031514Sbrian    return (*algorithm[out_algorithm]->o.Write)(pri, proto, m);
41131514Sbrian  return 0;
41231514Sbrian}
41331514Sbrian
41431514Sbrianstruct mbuf *
41531514SbrianCompdInput(u_short *proto, struct mbuf *m)
41631514Sbrian{
41732381Sbrian  if (CcpInfo.reset_sent != -1) {
41832381Sbrian    /* Send another REQ and put the packet in the bit bucket */
41932381Sbrian    LogPrintf(LogCCP, "ReSendResetReq(%d)\n", CcpInfo.reset_sent);
42032381Sbrian    FsmOutput(&CcpFsm, CODE_RESETREQ, CcpInfo.reset_sent, NULL, 0);
42132381Sbrian    pfree(m);
42232381Sbrian  } else if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
42331514Sbrian    return (*algorithm[in_algorithm]->i.Read)(proto, m);
42431514Sbrian  return NULL;
42531514Sbrian}
42631514Sbrian
42731514Sbrianvoid
42831514SbrianCcpDictSetup(u_short proto, struct mbuf *m)
42931514Sbrian{
43031514Sbrian  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
43131514Sbrian    (*algorithm[in_algorithm]->i.DictSetup)(proto, m);
43231514Sbrian}
433