ccp.c revision 32246
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.26 1997/12/24 09:28:52 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#include "deflate.h"
45
46struct ccpstate CcpInfo = { -1, -1 };
47
48static void CcpSendConfigReq(struct fsm *);
49static void CcpSendTerminateReq(struct fsm *);
50static void CcpSendTerminateAck(struct fsm *);
51static void CcpDecodeConfig(u_char *, int, int);
52static void CcpLayerStart(struct fsm *);
53static void CcpLayerFinish(struct fsm *);
54static void CcpLayerUp(struct fsm *);
55static void CcpLayerDown(struct fsm *);
56static void CcpInitRestartCounter(struct fsm *);
57
58struct fsm CcpFsm = {
59  "CCP",
60  PROTO_CCP,
61  CCP_MAXCODE,
62  OPEN_ACTIVE,
63  ST_INITIAL,
64  0, 0, 0,
65  0,
66  {0, 0, 0, NULL, NULL, NULL},
67  {0, 0, 0, NULL, NULL, NULL},
68  LogCCP,
69
70  CcpLayerUp,
71  CcpLayerDown,
72  CcpLayerStart,
73  CcpLayerFinish,
74  CcpInitRestartCounter,
75  CcpSendConfigReq,
76  CcpSendTerminateReq,
77  CcpSendTerminateAck,
78  CcpDecodeConfig,
79};
80
81static char const *cftypes[] = {
82  /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
83  "OUI",		/* 0: OUI */
84  "PRED1",		/* 1: Predictor type 1 */
85  "PRED2",		/* 2: Predictor type 2 */
86  "PUDDLE",		/* 3: Puddle Jumber */
87  "???", "???", "???", "???", "???", "???",
88  "???", "???", "???", "???", "???", "???",
89  "HWPPC",		/* 16: Hewlett-Packard PPC */
90  "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
91  "MSPPC",		/* 18: Microsoft PPC */
92  "GAND",		/* 19: Gandalf FZA (rfc1993) */
93  "V42BIS",		/* 20: ARG->DATA.42bis compression */
94  "BSD",		/* 21: BSD LZW Compress */
95  "???",
96  "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
97  "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
98			/* 24: Deflate (according to pppd-2.3.1) */
99  "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
100  "DEFLATE",		/* 26: Deflate (rfc1979) */
101};
102
103#define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
104
105static const char *
106protoname(int proto)
107{
108  if (proto < 0 || proto > NCFTYPES)
109    return "none";
110  return cftypes[proto];
111}
112
113/* We support these algorithms, and Req them in the given order */
114static const struct ccp_algorithm *algorithm[] = {
115  &DeflateAlgorithm,
116  &Pred1Algorithm,
117  &PppdDeflateAlgorithm
118};
119
120static int in_algorithm = -1;
121static int out_algorithm = -1;
122#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
123
124int
125ReportCcpStatus(struct cmdargs const *arg)
126{
127  if (VarTerm) {
128    fprintf(VarTerm, "%s [%s]\n", CcpFsm.name, StateNames[CcpFsm.state]);
129    fprintf(VarTerm, "My protocol = %s, His protocol = %s\n",
130            protoname(CcpInfo.my_proto), protoname(CcpInfo.his_proto));
131    fprintf(VarTerm, "Output: %ld --> %ld,  Input: %ld --> %ld\n",
132            CcpInfo.uncompout, CcpInfo.compout,
133            CcpInfo.compin, CcpInfo.uncompin);
134  }
135  return 0;
136}
137
138static void
139ccpstateInit(void)
140{
141  if (CcpInfo.in_init)
142    (*algorithm[in_algorithm]->i.Term)();
143  if (CcpInfo.out_init)
144    (*algorithm[out_algorithm]->o.Term)();
145  in_algorithm = -1;
146  out_algorithm = -1;
147  memset(&CcpInfo, '\0', sizeof CcpInfo);
148  CcpInfo.his_proto = CcpInfo.my_proto = -1;
149}
150
151void
152CcpInit()
153{
154  FsmInit(&CcpFsm);
155  ccpstateInit();
156  CcpFsm.maxconfig = 10;
157}
158
159static void
160CcpInitRestartCounter(struct fsm *fp)
161{
162  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
163  fp->restart = 5;
164}
165
166static void
167CcpSendConfigReq(struct fsm *fp)
168{
169  u_char *cp;
170  int f;
171
172  LogPrintf(LogCCP, "CcpSendConfigReq\n");
173  cp = ReqBuff;
174  CcpInfo.my_proto = -1;
175  out_algorithm = -1;
176  for (f = 0; f < NALGORITHMS; f++)
177    if (Enabled(algorithm[f]->Conf) && !REJECTED(&CcpInfo, algorithm[f]->id)) {
178      struct lcp_opt o;
179
180      (*algorithm[f]->o.Get)(&o);
181      cp += LcpPutConf(LogCCP, cp, &o, cftypes[o.id],
182                       (*algorithm[f]->Disp)(&o));
183      CcpInfo.my_proto = o.id;
184      out_algorithm = f;
185    }
186  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
187}
188
189void
190CcpSendResetReq(struct fsm *fp)
191{
192  LogPrintf(LogCCP, "CcpSendResetReq\n");
193  FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
194}
195
196static void
197CcpSendTerminateReq(struct fsm *fp)
198{
199  /* XXX: No code yet */
200}
201
202static void
203CcpSendTerminateAck(struct fsm *fp)
204{
205  LogPrintf(LogCCP, "CcpSendTerminateAck\n");
206  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
207}
208
209void
210CcpRecvResetReq(struct fsm *fp)
211{
212  if (out_algorithm >= 0 && out_algorithm < NALGORITHMS)
213    (*algorithm[out_algorithm]->o.Reset)();
214}
215
216static void
217CcpLayerStart(struct fsm *fp)
218{
219  LogPrintf(LogCCP, "CcpLayerStart.\n");
220}
221
222static void
223CcpLayerFinish(struct fsm *fp)
224{
225  LogPrintf(LogCCP, "CcpLayerFinish.\n");
226  ccpstateInit();
227}
228
229static void
230CcpLayerDown(struct fsm *fp)
231{
232  LogPrintf(LogCCP, "CcpLayerDown.\n");
233  ccpstateInit();
234}
235
236/*
237 *  Called when CCP has reached the OPEN state
238 */
239static void
240CcpLayerUp(struct fsm *fp)
241{
242  LogPrintf(LogCCP, "CcpLayerUp(%d).\n", fp->state);
243  LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n",
244            protoname(CcpInfo.my_proto), CcpInfo.my_proto,
245            protoname(CcpInfo.his_proto), CcpInfo.his_proto);
246  if (!CcpInfo.in_init && in_algorithm >= 0 && in_algorithm < NALGORITHMS) {
247    (*algorithm[in_algorithm]->i.Init)();
248    CcpInfo.in_init = 1;
249  }
250  if (!CcpInfo.out_init && out_algorithm >= 0 && out_algorithm < NALGORITHMS) {
251    (*algorithm[out_algorithm]->o.Init)();
252    CcpInfo.out_init = 1;
253  }
254}
255
256void
257CcpUp()
258{
259  FsmUp(&CcpFsm);
260  LogPrintf(LogCCP, "CCP Up event!!\n");
261}
262
263void
264CcpOpen()
265{
266  int f;
267
268  for (f = 0; f < NALGORITHMS; f++)
269    if (Enabled(algorithm[f]->Conf)) {
270      CcpFsm.open_mode = OPEN_ACTIVE;
271      FsmOpen(&CcpFsm);
272      break;
273    }
274
275  if (f == NALGORITHMS)
276    for (f = 0; f < NALGORITHMS; f++)
277      if (Acceptable(algorithm[f]->Conf)) {
278        CcpFsm.open_mode = OPEN_PASSIVE;
279        FsmOpen(&CcpFsm);
280        break;
281      }
282}
283
284static void
285CcpDecodeConfig(u_char *cp, int plen, int mode_type)
286{
287  int type, length;
288  int f;
289
290  ackp = AckBuff;
291  nakp = NakBuff;
292  rejp = RejBuff;
293
294  while (plen >= sizeof(struct fsmconfig)) {
295    type = *cp;
296    length = cp[1];
297    if (type < NCFTYPES)
298      LogPrintf(LogCCP, " %s[%d]\n", cftypes[type], length);
299    else
300      LogPrintf(LogCCP, " ???[%d]\n", length);
301
302    for (f = NALGORITHMS-1; f > -1; f--)
303      if (algorithm[f]->id == type)
304        break;
305
306    if (f == -1) {
307      /* Don't understand that :-( */
308      if (mode_type == MODE_REQ) {
309        CcpInfo.my_reject |= (1 << type);
310        memcpy(rejp, cp, length);
311        rejp += length;
312      }
313    } else {
314      struct lcp_opt o;
315
316      switch (mode_type) {
317      case MODE_REQ:
318	if (Acceptable(algorithm[f]->Conf) && in_algorithm == -1) {
319	  memcpy(&o, cp, length);
320          switch ((*algorithm[f]->i.Set)(&o)) {
321          case MODE_REJ:
322	    memcpy(rejp, &o, o.len);
323	    rejp += o.len;
324            break;
325          case MODE_NAK:
326	    memcpy(nakp, &o, o.len);
327	    nakp += o.len;
328            break;
329          case MODE_ACK:
330	    memcpy(ackp, cp, length);
331	    ackp += length;
332	    CcpInfo.his_proto = type;
333            in_algorithm = f;		/* This one'll do ! */
334            break;
335          }
336	} else {
337	  memcpy(rejp, cp, length);
338	  rejp += length;
339	}
340	break;
341      case MODE_NAK:
342	memcpy(&o, cp, length);
343        if ((*algorithm[f]->o.Set)(&o) == MODE_ACK)
344          CcpInfo.my_proto = algorithm[f]->id;
345        else {
346	  CcpInfo.his_reject |= (1 << type);
347	  CcpInfo.my_proto = -1;
348        }
349        break;
350      case MODE_REJ:
351	CcpInfo.his_reject |= (1 << type);
352	CcpInfo.my_proto = -1;
353	break;
354      }
355    }
356
357    plen -= length;
358    cp += length;
359  }
360
361  if (rejp != RejBuff) {
362    ackp = AckBuff;	/* let's not send both ! */
363    CcpInfo.his_proto = -1;
364    in_algorithm = -1;
365  }
366}
367
368void
369CcpInput(struct mbuf *bp)
370{
371  if (phase == PHASE_NETWORK)
372    FsmInput(&CcpFsm, bp);
373  else {
374    if (phase > PHASE_NETWORK)
375      LogPrintf(LogCCP, "Error: Unexpected CCP in phase %d\n", phase);
376    pfree(bp);
377  }
378}
379
380void
381CcpResetInput()
382{
383  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
384    (*algorithm[in_algorithm]->i.Reset)();
385}
386
387int
388CcpOutput(int pri, u_short proto, struct mbuf *m)
389{
390  if (out_algorithm >= 0 && out_algorithm < NALGORITHMS)
391    return (*algorithm[out_algorithm]->o.Write)(pri, proto, m);
392  return 0;
393}
394
395struct mbuf *
396CompdInput(u_short *proto, struct mbuf *m)
397{
398  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
399    return (*algorithm[in_algorithm]->i.Read)(proto, m);
400  return NULL;
401}
402
403void
404CcpDictSetup(u_short proto, struct mbuf *m)
405{
406  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
407    (*algorithm[in_algorithm]->i.DictSetup)(proto, m);
408}
409