ccp.c revision 31343
1/*
2 *	   PPP Compression Control Protocol (CCP) Module
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1994, 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: ccp.c,v 1.19 1997/11/14 15:39:14 brian Exp $
21 *
22 *	TODO:
23 *		o Support other compression protocols
24 */
25#include <sys/param.h>
26#include <netinet/in.h>
27
28#include <stdio.h>
29#include <string.h>
30
31#include "command.h"
32#include "mbuf.h"
33#include "log.h"
34#include "defs.h"
35#include "timer.h"
36#include "fsm.h"
37#include "lcpproto.h"
38#include "lcp.h"
39#include "ccp.h"
40#include "phase.h"
41#include "loadalias.h"
42#include "vars.h"
43#include "pred.h"
44
45struct ccpstate CcpInfo;
46
47static void CcpSendConfigReq(struct fsm *);
48static void CcpSendTerminateReq(struct fsm *);
49static void CcpSendTerminateAck(struct fsm *);
50static void CcpDecodeConfig(u_char *, int, int);
51static void CcpLayerStart(struct fsm *);
52static void CcpLayerFinish(struct fsm *);
53static void CcpLayerUp(struct fsm *);
54static void CcpLayerDown(struct fsm *);
55static void CcpInitRestartCounter(struct fsm *);
56
57#define	REJECTED(p, x)	(p->his_reject & (1<<x))
58
59struct fsm CcpFsm = {
60  "CCP",
61  PROTO_CCP,
62  CCP_MAXCODE,
63  OPEN_ACTIVE,
64  ST_INITIAL,
65  0, 0, 0,
66  0,
67  {0, 0, 0, NULL, NULL, NULL},
68  {0, 0, 0, NULL, NULL, NULL},
69  LogCCP,
70
71  CcpLayerUp,
72  CcpLayerDown,
73  CcpLayerStart,
74  CcpLayerFinish,
75  CcpInitRestartCounter,
76  CcpSendConfigReq,
77  CcpSendTerminateReq,
78  CcpSendTerminateAck,
79  CcpDecodeConfig,
80};
81
82static char const *cftypes[] = {
83  /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
84   "OUI",	/* 0: OUI */
85   "PRED1",	/* 1: Predictor type 1 */
86   "PRED2",	/* 2: Predictor type 2 */
87   "PUDDLE",	/* 3: Puddle Jumber */
88   "???", "???", "???", "???", "???", "???",
89   "???", "???", "???", "???", "???", "???",
90   "HWPPC",	/* 16: Hewlett-Packard PPC */
91   "STAC",	/* 17: Stac Electronics LZS */
92   "MSPPC",	/* 18: Microsoft PPC */
93   "GAND",	/* 19: Gandalf FZA */
94   "V42BIS",	/* 20: ARG->DATA.42bis compression */
95   "BSD",	/* BSD LZW Compress */
96};
97
98#define NCFTYPES (sizeof(cftypes)/sizeof(char *))
99
100int
101ReportCcpStatus(struct cmdargs const *arg)
102{
103  struct ccpstate *icp = &CcpInfo;
104  struct fsm *fp = &CcpFsm;
105
106  if (VarTerm) {
107    fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]);
108    fprintf(VarTerm, "myproto = %s, hisproto = %s\n",
109	    cftypes[icp->want_proto], cftypes[icp->his_proto]);
110    fprintf(VarTerm, "Input: %ld --> %ld,  Output: %ld --> %ld\n",
111	    icp->orgin, icp->compin, icp->orgout, icp->compout);
112  }
113  return 0;
114}
115
116void
117CcpInit()
118{
119  struct ccpstate *icp = &CcpInfo;
120
121  FsmInit(&CcpFsm);
122  memset(icp, '\0', sizeof(struct ccpstate));
123  if (Enabled(ConfPred1))
124    icp->want_proto = TY_PRED1;
125  CcpFsm.maxconfig = 10;
126}
127
128static void
129CcpInitRestartCounter(struct fsm *fp)
130{
131  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
132  fp->restart = 5;
133}
134
135static void
136CcpSendConfigReq(struct fsm *fp)
137{
138  u_char *cp;
139  struct ccpstate *icp = &CcpInfo;
140
141  cp = ReqBuff;
142  LogPrintf(LogCCP, "CcpSendConfigReq\n");
143  if (icp->want_proto && !REJECTED(icp, TY_PRED1)) {
144    *cp++ = TY_PRED1;
145    *cp++ = 2;
146  }
147  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
148}
149
150void
151CcpSendResetReq(struct fsm *fp)
152{
153  LogPrintf(LogCCP, "CcpSendResetReq\n");
154  FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
155}
156
157static void
158CcpSendTerminateReq(struct fsm *fp)
159{
160  /* XXX: No code yet */
161}
162
163static void
164CcpSendTerminateAck(struct fsm *fp)
165{
166  LogPrintf(LogCCP, "CcpSendTerminateAck\n");
167  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
168}
169
170void
171CcpRecvResetReq(struct fsm *fp)
172{
173  Pred1Init(2);			/* Initialize Output part */
174}
175
176static void
177CcpLayerStart(struct fsm *fp)
178{
179  LogPrintf(LogCCP, "CcpLayerStart.\n");
180}
181
182static void
183CcpLayerFinish(struct fsm *fp)
184{
185  LogPrintf(LogCCP, "CcpLayerFinish.\n");
186}
187
188static void
189CcpLayerDown(struct fsm *fp)
190{
191  LogPrintf(LogCCP, "CcpLayerDown.\n");
192}
193
194/*
195 *  Called when CCP has reached to OPEN state
196 */
197static void
198CcpLayerUp(struct fsm *fp)
199{
200  LogPrintf(LogCCP, "CcpLayerUp(%d).\n", fp->state);
201  LogPrintf(LogCCP, "myproto = %d, hisproto = %d\n",
202	    CcpInfo.want_proto, CcpInfo.his_proto);
203  Pred1Init(3);			/* Initialize Input and Output */
204}
205
206void
207CcpUp()
208{
209  FsmUp(&CcpFsm);
210  LogPrintf(LogCCP, "CCP Up event!!\n");
211}
212
213void
214CcpOpen()
215{
216  if (Enabled(ConfPred1))
217    FsmOpen(&CcpFsm);
218}
219
220static void
221CcpDecodeConfig(u_char *cp, int plen, int mode_type)
222{
223  int type, length;
224  char tbuff[100];
225
226  ackp = AckBuff;
227  nakp = NakBuff;
228  rejp = RejBuff;
229
230  while (plen >= sizeof(struct fsmconfig)) {
231    if (plen < 0)
232      break;
233    type = *cp;
234    length = cp[1];
235    if (type < NCFTYPES)
236      snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes[type], length);
237    else
238      snprintf(tbuff, sizeof(tbuff), " ");
239
240    LogPrintf(LogCCP, "%s\n", tbuff);
241
242    switch (type) {
243    case TY_PRED1:
244      switch (mode_type) {
245      case MODE_REQ:
246	if (Acceptable(ConfPred1)) {
247	  memcpy(ackp, cp, length);
248	  ackp += length;
249	  CcpInfo.his_proto = type;
250	} else {
251	  memcpy(rejp, cp, length);
252	  rejp += length;
253	}
254	break;
255      case MODE_NAK:
256      case MODE_REJ:
257	CcpInfo.his_reject |= (1 << type);
258	CcpInfo.want_proto = 0;
259	break;
260      }
261      break;
262    case TY_BSD:
263    default:
264      CcpInfo.my_reject |= (1 << type);
265      memcpy(rejp, cp, length);
266      rejp += length;
267      break;
268    }
269    plen -= length;
270    cp += length;
271  }
272}
273
274void
275CcpInput(struct mbuf *bp)
276{
277  if (phase == PHASE_NETWORK)
278    FsmInput(&CcpFsm, bp);
279  else {
280    if (phase > PHASE_NETWORK)
281      LogPrintf(LogERROR, "Unexpected CCP in phase %d\n", phase);
282    pfree(bp);
283  }
284}
285