ccp.c revision 31690
1112158Sdas/*
2112158Sdas *	   PPP Compression Control Protocol (CCP) Module
3112158Sdas *
4112158Sdas *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5112158Sdas *
6112158Sdas *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
7112158Sdas *
8112158Sdas * Redistribution and use in source and binary forms are permitted
9112158Sdas * provided that the above copyright notice and this paragraph are
10112158Sdas * duplicated in all such forms and that any documentation,
11112158Sdas * advertising materials, and other materials related to such
12112158Sdas * distribution and use acknowledge that the software was developed
13112158Sdas * by the Internet Initiative Japan, Inc.  The name of the
14112158Sdas * IIJ may not be used to endorse or promote products derived
15112158Sdas * from this software without specific prior written permission.
16112158Sdas * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17112158Sdas * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18112158Sdas * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19112158Sdas *
20112158Sdas * $Id: ccp.c,v 1.23 1997/12/04 18:49:32 brian Exp $
21112158Sdas *
22112158Sdas *	TODO:
23112158Sdas *		o Support other compression protocols
24112158Sdas */
25112158Sdas#include <sys/param.h>
26112158Sdas#include <netinet/in.h>
27112158Sdas
28112158Sdas#include <stdio.h>
29165743Sdas#include <string.h>
30165743Sdas
31112158Sdas#include "command.h"
32112158Sdas#include "mbuf.h"
33112158Sdas#include "log.h"
34112158Sdas#include "defs.h"
35112158Sdas#include "timer.h"
36187808Sdas#include "fsm.h"
37112158Sdas#include "lcpproto.h"
38187808Sdas#include "lcp.h"
39112158Sdas#include "ccp.h"
40112158Sdas#include "phase.h"
41187808Sdas#include "loadalias.h"
42112158Sdas#include "vars.h"
43112158Sdas#include "pred.h"
44112158Sdas#include "deflate.h"
45187808Sdas
46187808Sdasstruct ccpstate CcpInfo;
47187808Sdas
48187808Sdasstatic void CcpSendConfigReq(struct fsm *);
49187808Sdasstatic void CcpSendTerminateReq(struct fsm *);
50112158Sdasstatic void CcpSendTerminateAck(struct fsm *);
51112158Sdasstatic void CcpDecodeConfig(u_char *, int, int);
52112158Sdasstatic void CcpLayerStart(struct fsm *);
53112158Sdasstatic void CcpLayerFinish(struct fsm *);
54112158Sdasstatic void CcpLayerUp(struct fsm *);
55112158Sdasstatic void CcpLayerDown(struct fsm *);
56112158Sdasstatic void CcpInitRestartCounter(struct fsm *);
57112158Sdas
58112158Sdasstruct fsm CcpFsm = {
59112158Sdas  "CCP",
60112158Sdas  PROTO_CCP,
61112158Sdas  CCP_MAXCODE,
62112158Sdas  OPEN_ACTIVE,
63112158Sdas  ST_INITIAL,
64112158Sdas  0, 0, 0,
65112158Sdas  0,
66112158Sdas  {0, 0, 0, NULL, NULL, NULL},
67112158Sdas  {0, 0, 0, NULL, NULL, NULL},
68112158Sdas  LogCCP,
69112158Sdas
70112158Sdas  CcpLayerUp,
71112158Sdas  CcpLayerDown,
72112158Sdas  CcpLayerStart,
73112158Sdas  CcpLayerFinish,
74112158Sdas  CcpInitRestartCounter,
75112158Sdas  CcpSendConfigReq,
76112158Sdas  CcpSendTerminateReq,
77112158Sdas  CcpSendTerminateAck,
78112158Sdas  CcpDecodeConfig,
79112158Sdas};
80112158Sdas
81112158Sdasstatic char const *cftypes[] = {
82112158Sdas  /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
83112158Sdas  "OUI",		/* 0: OUI */
84112158Sdas  "PRED1",		/* 1: Predictor type 1 */
85112158Sdas  "PRED2",		/* 2: Predictor type 2 */
86112158Sdas  "PUDDLE",		/* 3: Puddle Jumber */
87112158Sdas  "???", "???", "???", "???", "???", "???",
88112158Sdas  "???", "???", "???", "???", "???", "???",
89112158Sdas  "HWPPC",		/* 16: Hewlett-Packard PPC */
90112158Sdas  "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
91187808Sdas  "MSPPC",		/* 18: Microsoft PPC */
92187808Sdas  "GAND",		/* 19: Gandalf FZA (rfc1993) */
93112158Sdas  "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    if (plen < 0)
294      break;
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