ccp.c revision 32658
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.28 1998/01/10 01:55:08 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  0,
63  ST_INITIAL,
64  0, 0, 0,
65  0,
66  {0, 0, 0, NULL, NULL, NULL},	/* FSM timer */
67  {0, 0, 0, NULL, NULL, NULL},	/* Open timer */
68  {0, 0, 0, NULL, NULL, NULL},	/* Stopped timer */
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 (rfc1974) */
92  "MSPPC",		/* 18: Microsoft PPC */
93  "GAND",		/* 19: Gandalf FZA (rfc1993) */
94  "V42BIS",		/* 20: ARG->DATA.42bis compression */
95  "BSD",		/* 21: BSD LZW Compress */
96  "???",
97  "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
98  "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
99			/* 24: Deflate (according to pppd-2.3.1) */
100  "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
101  "DEFLATE",		/* 26: Deflate (rfc1979) */
102};
103
104#define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
105
106static const char *
107protoname(int proto)
108{
109  if (proto < 0 || proto > NCFTYPES)
110    return "none";
111  return cftypes[proto];
112}
113
114/* We support these algorithms, and Req them in the given order */
115static const struct ccp_algorithm *algorithm[] = {
116  &DeflateAlgorithm,
117  &Pred1Algorithm,
118  &PppdDeflateAlgorithm
119};
120
121static int in_algorithm = -1;
122static int out_algorithm = -1;
123#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
124
125int
126ReportCcpStatus(struct cmdargs const *arg)
127{
128  if (VarTerm) {
129    fprintf(VarTerm, "%s [%s]\n", CcpFsm.name, StateNames[CcpFsm.state]);
130    fprintf(VarTerm, "My protocol = %s, His protocol = %s\n",
131            protoname(CcpInfo.my_proto), protoname(CcpInfo.his_proto));
132    fprintf(VarTerm, "Output: %ld --> %ld,  Input: %ld --> %ld\n",
133            CcpInfo.uncompout, CcpInfo.compout,
134            CcpInfo.compin, CcpInfo.uncompin);
135  }
136  return 0;
137}
138
139static void
140ccpstateInit(void)
141{
142  if (CcpInfo.in_init)
143    (*algorithm[in_algorithm]->i.Term)();
144  if (CcpInfo.out_init)
145    (*algorithm[out_algorithm]->o.Term)();
146  in_algorithm = -1;
147  out_algorithm = -1;
148  memset(&CcpInfo, '\0', sizeof CcpInfo);
149  CcpInfo.his_proto = CcpInfo.my_proto = -1;
150  CcpInfo.reset_sent = CcpInfo.last_reset = -1;
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, "SendResetReq(%d)\n", fp->reqid);
195  CcpInfo.reset_sent = fp->reqid;
196  CcpInfo.last_reset = -1;
197  FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
198}
199
200static void
201CcpSendTerminateReq(struct fsm *fp)
202{
203  /* XXX: No code yet */
204}
205
206static void
207CcpSendTerminateAck(struct fsm *fp)
208{
209  LogPrintf(LogCCP, "CcpSendTerminateAck\n");
210  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
211}
212
213void
214CcpRecvResetReq(struct fsm *fp)
215{
216  if (out_algorithm >= 0 && out_algorithm < NALGORITHMS)
217    (*algorithm[out_algorithm]->o.Reset)();
218}
219
220static void
221CcpLayerStart(struct fsm *fp)
222{
223  LogPrintf(LogCCP, "CcpLayerStart.\n");
224}
225
226static void
227CcpLayerFinish(struct fsm *fp)
228{
229  LogPrintf(LogCCP, "CcpLayerFinish.\n");
230  ccpstateInit();
231}
232
233static void
234CcpLayerDown(struct fsm *fp)
235{
236  LogPrintf(LogCCP, "CcpLayerDown.\n");
237  ccpstateInit();
238}
239
240/*
241 *  Called when CCP has reached the OPEN state
242 */
243static void
244CcpLayerUp(struct fsm *fp)
245{
246  LogPrintf(LogCCP, "CcpLayerUp(%d).\n", fp->state);
247  LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n",
248            protoname(CcpInfo.my_proto), CcpInfo.my_proto,
249            protoname(CcpInfo.his_proto), CcpInfo.his_proto);
250  if (!CcpInfo.in_init && in_algorithm >= 0 && in_algorithm < NALGORITHMS) {
251    (*algorithm[in_algorithm]->i.Init)();
252    CcpInfo.in_init = 1;
253  }
254  if (!CcpInfo.out_init && out_algorithm >= 0 && out_algorithm < NALGORITHMS) {
255    (*algorithm[out_algorithm]->o.Init)();
256    CcpInfo.out_init = 1;
257  }
258}
259
260void
261CcpUp()
262{
263  FsmUp(&CcpFsm);
264  LogPrintf(LogCCP, "CCP Up event!!\n");
265}
266
267void
268CcpOpen()
269{
270  int f;
271
272  for (f = 0; f < NALGORITHMS; f++)
273    if (Enabled(algorithm[f]->Conf)) {
274      CcpFsm.open_mode = 0;
275      FsmOpen(&CcpFsm);
276      break;
277    }
278
279  if (f == NALGORITHMS)
280    for (f = 0; f < NALGORITHMS; f++)
281      if (Acceptable(algorithm[f]->Conf)) {
282        CcpFsm.open_mode = OPEN_PASSIVE;
283        FsmOpen(&CcpFsm);
284        break;
285      }
286}
287
288static void
289CcpDecodeConfig(u_char *cp, int plen, int mode_type)
290{
291  int type, length;
292  int f;
293
294  ackp = AckBuff;
295  nakp = NakBuff;
296  rejp = RejBuff;
297
298  while (plen >= sizeof(struct fsmconfig)) {
299    type = *cp;
300    length = cp[1];
301    if (type < NCFTYPES)
302      LogPrintf(LogCCP, " %s[%d]\n", cftypes[type], length);
303    else
304      LogPrintf(LogCCP, " ???[%d]\n", length);
305
306    for (f = NALGORITHMS-1; f > -1; f--)
307      if (algorithm[f]->id == type)
308        break;
309
310    if (f == -1) {
311      /* Don't understand that :-( */
312      if (mode_type == MODE_REQ) {
313        CcpInfo.my_reject |= (1 << type);
314        memcpy(rejp, cp, length);
315        rejp += length;
316      }
317    } else {
318      struct lcp_opt o;
319
320      switch (mode_type) {
321      case MODE_REQ:
322	if (Acceptable(algorithm[f]->Conf) && in_algorithm == -1) {
323	  memcpy(&o, cp, length);
324          switch ((*algorithm[f]->i.Set)(&o)) {
325          case MODE_REJ:
326	    memcpy(rejp, &o, o.len);
327	    rejp += o.len;
328            break;
329          case MODE_NAK:
330	    memcpy(nakp, &o, o.len);
331	    nakp += o.len;
332            break;
333          case MODE_ACK:
334	    memcpy(ackp, cp, length);
335	    ackp += length;
336	    CcpInfo.his_proto = type;
337            in_algorithm = f;		/* This one'll do ! */
338            break;
339          }
340	} else {
341	  memcpy(rejp, cp, length);
342	  rejp += length;
343	}
344	break;
345      case MODE_NAK:
346	memcpy(&o, cp, length);
347        if ((*algorithm[f]->o.Set)(&o) == MODE_ACK)
348          CcpInfo.my_proto = algorithm[f]->id;
349        else {
350	  CcpInfo.his_reject |= (1 << type);
351	  CcpInfo.my_proto = -1;
352        }
353        break;
354      case MODE_REJ:
355	CcpInfo.his_reject |= (1 << type);
356	CcpInfo.my_proto = -1;
357	break;
358      }
359    }
360
361    plen -= length;
362    cp += length;
363  }
364
365  if (rejp != RejBuff) {
366    ackp = AckBuff;	/* let's not send both ! */
367    CcpInfo.his_proto = -1;
368    in_algorithm = -1;
369  }
370}
371
372void
373CcpInput(struct mbuf *bp)
374{
375  if (phase == PHASE_NETWORK)
376    FsmInput(&CcpFsm, bp);
377  else {
378    if (phase > PHASE_NETWORK)
379      LogPrintf(LogCCP, "Error: Unexpected CCP in phase %d\n", phase);
380    pfree(bp);
381  }
382}
383
384void
385CcpResetInput(u_char id)
386{
387  if (CcpInfo.reset_sent != -1) {
388    if (id != CcpInfo.reset_sent) {
389      LogPrintf(LogWARN, "CCP: Incorrect ResetAck (id %d, not %d) ignored\n",
390                id, CcpInfo.reset_sent);
391      return;
392    }
393    /* Whaddaya know - a correct reset ack */
394  } else if (id == CcpInfo.last_reset)
395    LogPrintf(LogCCP, "Duplicate ResetAck (resetting again)\n");
396  else {
397    LogPrintf(LogWARN, "CCP: Unexpected ResetAck (id %d) ignored\n", id);
398    return;
399  }
400
401  CcpInfo.last_reset = CcpInfo.reset_sent;
402  CcpInfo.reset_sent = -1;
403  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
404    (*algorithm[in_algorithm]->i.Reset)();
405}
406
407int
408CcpOutput(int pri, u_short proto, struct mbuf *m)
409{
410  if (out_algorithm >= 0 && out_algorithm < NALGORITHMS)
411    return (*algorithm[out_algorithm]->o.Write)(pri, proto, m);
412  return 0;
413}
414
415struct mbuf *
416CompdInput(u_short *proto, struct mbuf *m)
417{
418  if (CcpInfo.reset_sent != -1) {
419    /* Send another REQ and put the packet in the bit bucket */
420    LogPrintf(LogCCP, "ReSendResetReq(%d)\n", CcpInfo.reset_sent);
421    FsmOutput(&CcpFsm, CODE_RESETREQ, CcpInfo.reset_sent, NULL, 0);
422    pfree(m);
423  } else if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
424    return (*algorithm[in_algorithm]->i.Read)(proto, m);
425  return NULL;
426}
427
428void
429CcpDictSetup(u_short proto, struct mbuf *m)
430{
431  if (in_algorithm >= 0 && in_algorithm < NALGORITHMS)
432    (*algorithm[in_algorithm]->i.DictSetup)(proto, m);
433}
434