ccp.c revision 31824
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.24 1997/12/13 02:37:21 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;
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(char *))
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  memset(&CcpInfo, '\0', sizeof(struct ccpstate));
142  CcpInfo.his_proto = CcpInfo.my_proto = -1;
143  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) {
144    (*algorithm[in_algorithm]->i.Term)();
145    in_algorithm = -1;
146  }
147  if (out_algorithm >= 0 && out_algorithm < NALGORITHMS) {
148    (*algorithm[out_algorithm]->o.Term)();
149    out_algorithm = -1;
150  }
151}
152
153void
154CcpInit()
155{
156  FsmInit(&CcpFsm);
157  ccpstateInit();
158  CcpFsm.maxconfig = 10;
159}
160
161static void
162CcpInitRestartCounter(struct fsm *fp)
163{
164  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
165  fp->restart = 5;
166}
167
168static void
169CcpSendConfigReq(struct fsm *fp)
170{
171  u_char *cp;
172  int f;
173
174  LogPrintf(LogCCP, "CcpSendConfigReq\n");
175  cp = ReqBuff;
176  CcpInfo.my_proto = -1;
177  out_algorithm = -1;
178  for (f = 0; f < NALGORITHMS; f++)
179    if (Enabled(algorithm[f]->Conf) && !REJECTED(&CcpInfo, algorithm[f]->id)) {
180      struct lcp_opt o;
181
182      (*algorithm[f]->o.Get)(&o);
183      cp += LcpPutConf(LogCCP, cp, &o, cftypes[o.id],
184                       (*algorithm[f]->Disp)(&o));
185      CcpInfo.my_proto = o.id;
186      out_algorithm = f;
187    }
188  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
189}
190
191void
192CcpSendResetReq(struct fsm *fp)
193{
194  LogPrintf(LogCCP, "CcpSendResetReq\n");
195  FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
196}
197
198static void
199CcpSendTerminateReq(struct fsm *fp)
200{
201  /* XXX: No code yet */
202}
203
204static void
205CcpSendTerminateAck(struct fsm *fp)
206{
207  LogPrintf(LogCCP, "CcpSendTerminateAck\n");
208  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
209}
210
211void
212CcpRecvResetReq(struct fsm *fp)
213{
214  if (out_algorithm >= 0 && out_algorithm < NALGORITHMS)
215    (*algorithm[out_algorithm]->o.Reset)();
216}
217
218static void
219CcpLayerStart(struct fsm *fp)
220{
221  LogPrintf(LogCCP, "CcpLayerStart.\n");
222}
223
224static void
225CcpLayerFinish(struct fsm *fp)
226{
227  LogPrintf(LogCCP, "CcpLayerFinish.\n");
228  ccpstateInit();
229}
230
231static void
232CcpLayerDown(struct fsm *fp)
233{
234  LogPrintf(LogCCP, "CcpLayerDown.\n");
235  ccpstateInit();
236}
237
238/*
239 *  Called when CCP has reached the OPEN state
240 */
241static void
242CcpLayerUp(struct fsm *fp)
243{
244  LogPrintf(LogCCP, "CcpLayerUp(%d).\n", fp->state);
245  LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n",
246            protoname(CcpInfo.my_proto), CcpInfo.my_proto,
247            protoname(CcpInfo.his_proto), CcpInfo.his_proto);
248  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
249    (*algorithm[in_algorithm]->i.Init)();
250  if (out_algorithm >= 0 && out_algorithm < NALGORITHMS)
251    (*algorithm[out_algorithm]->o.Init)();
252}
253
254void
255CcpUp()
256{
257  FsmUp(&CcpFsm);
258  LogPrintf(LogCCP, "CCP Up event!!\n");
259}
260
261void
262CcpOpen()
263{
264  int f;
265
266  for (f = 0; f < NALGORITHMS; f++)
267    if (Enabled(algorithm[f]->Conf)) {
268      CcpFsm.open_mode = OPEN_ACTIVE;
269      FsmOpen(&CcpFsm);
270      break;
271    }
272
273  if (f == NALGORITHMS)
274    for (f = 0; f < NALGORITHMS; f++)
275      if (Acceptable(algorithm[f]->Conf)) {
276        CcpFsm.open_mode = OPEN_PASSIVE;
277        FsmOpen(&CcpFsm);
278        break;
279      }
280}
281
282static void
283CcpDecodeConfig(u_char *cp, int plen, int mode_type)
284{
285  int type, length;
286  int f;
287
288  ackp = AckBuff;
289  nakp = NakBuff;
290  rejp = RejBuff;
291
292  while (plen >= sizeof(struct fsmconfig)) {
293    type = *cp;
294    length = cp[1];
295    if (type < NCFTYPES)
296      LogPrintf(LogCCP, " %s[%d]\n", cftypes[type], length);
297    else
298      LogPrintf(LogCCP, " ???[%d]\n", length);
299
300    for (f = NALGORITHMS-1; f > -1; f--)
301      if (algorithm[f]->id == type)
302        break;
303
304    if (f == -1) {
305      /* Don't understand that :-( */
306      if (mode_type == MODE_REQ) {
307        CcpInfo.my_reject |= (1 << type);
308        memcpy(rejp, cp, length);
309        rejp += length;
310      }
311    } else {
312      struct lcp_opt o;
313
314      switch (mode_type) {
315      case MODE_REQ:
316	if (Acceptable(algorithm[f]->Conf) && in_algorithm == -1) {
317	  memcpy(&o, cp, length);
318          switch ((*algorithm[f]->i.Set)(&o)) {
319          case MODE_REJ:
320	    memcpy(rejp, &o, o.len);
321	    rejp += o.len;
322            break;
323          case MODE_NAK:
324	    memcpy(nakp, &o, o.len);
325	    nakp += o.len;
326            break;
327          case MODE_ACK:
328	    memcpy(ackp, cp, length);
329	    ackp += length;
330	    CcpInfo.his_proto = type;
331            in_algorithm = f;		/* This one'll do ! */
332            break;
333          }
334	} else {
335	  memcpy(rejp, cp, length);
336	  rejp += length;
337	}
338	break;
339      case MODE_NAK:
340	memcpy(&o, cp, length);
341        if ((*algorithm[f]->o.Set)(&o) == MODE_ACK)
342          CcpInfo.my_proto = algorithm[f]->id;
343        else {
344	  CcpInfo.his_reject |= (1 << type);
345	  CcpInfo.my_proto = -1;
346        }
347        break;
348      case MODE_REJ:
349	CcpInfo.his_reject |= (1 << type);
350	CcpInfo.my_proto = -1;
351	break;
352      }
353    }
354
355    plen -= length;
356    cp += length;
357  }
358
359  if (rejp != RejBuff) {
360    ackp = AckBuff;	/* let's not send both ! */
361    CcpInfo.his_proto = -1;
362    in_algorithm = -1;
363  }
364}
365
366void
367CcpInput(struct mbuf *bp)
368{
369  if (phase == PHASE_NETWORK)
370    FsmInput(&CcpFsm, bp);
371  else {
372    if (phase > PHASE_NETWORK)
373      LogPrintf(LogCCP, "Error: Unexpected CCP in phase %d\n", phase);
374    pfree(bp);
375  }
376}
377
378void
379CcpResetInput()
380{
381  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
382    (*algorithm[in_algorithm]->i.Reset)();
383}
384
385int
386CcpOutput(int pri, u_short proto, struct mbuf *m)
387{
388  if (out_algorithm >= 0 && out_algorithm < NALGORITHMS)
389    return (*algorithm[out_algorithm]->o.Write)(pri, proto, m);
390  return 0;
391}
392
393struct mbuf *
394CompdInput(u_short *proto, struct mbuf *m)
395{
396  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
397    return (*algorithm[in_algorithm]->i.Read)(proto, m);
398  return NULL;
399}
400
401void
402CcpDictSetup(u_short proto, struct mbuf *m)
403{
404  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
405    (*algorithm[in_algorithm]->i.DictSetup)(proto, m);
406}
407