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