pred.c revision 31514
1/*
2 * pred.c -- Test program for Dave Rand's rendition of the
3 * predictor algorithm
4 * Updated by: iand@labtam.labtam.oz.au (Ian Donaldson)
5 * Updated by: Carsten Bormann <cabo@cs.tu-berlin.de>
6 * Original  : Dave Rand <dlr@bungi.com>/<dave_rand@novell.com>
7 *
8 * $Id: pred.c,v 1.17 1997/11/22 03:37:44 brian Exp $
9 *
10 */
11
12#include <sys/param.h>
13#include <netinet/in.h>
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18
19#include "command.h"
20#include "mbuf.h"
21#include "log.h"
22#include "defs.h"
23#include "loadalias.h"
24#include "vars.h"
25#include "timer.h"
26#include "fsm.h"
27#include "hdlc.h"
28#include "lcpproto.h"
29#include "lcp.h"
30#include "ccp.h"
31#include "pred.h"
32
33/* The following hash code is the heart of the algorithm:
34 * It builds a sliding hash sum of the previous 3-and-a-bit characters
35 * which will be used to index the guess table.
36 * A better hash function would result in additional compression,
37 * at the expense of time.
38 */
39#define IHASH(x) do {iHash = (iHash << 4) ^ (x);} while(0)
40#define OHASH(x) do {oHash = (oHash << 4) ^ (x);} while(0)
41#define GUESS_TABLE_SIZE 65536
42
43static unsigned short int iHash, oHash;
44static unsigned char *InputGuessTable;
45static unsigned char *OutputGuessTable;
46
47static int
48compress(u_char * source, u_char * dest, int len)
49{
50  int i, bitmask;
51  unsigned char *flagdest, flags, *orgdest;
52
53  orgdest = dest;
54  while (len) {
55    flagdest = dest++;
56    flags = 0;			/* All guess wrong initially */
57    for (bitmask = 1, i = 0; i < 8 && len; i++, bitmask <<= 1) {
58      if (OutputGuessTable[oHash] == *source) {
59	flags |= bitmask;	/* Guess was right - don't output */
60      } else {
61	OutputGuessTable[oHash] = *source;
62	*dest++ = *source;	/* Guess wrong, output char */
63      }
64      OHASH(*source++);
65      len--;
66    }
67    *flagdest = flags;
68  }
69  return (dest - orgdest);
70}
71
72static void
73SyncTable(u_char * source, u_char * dest, int len)
74{
75
76  while (len--) {
77    if (InputGuessTable[iHash] != *source) {
78      InputGuessTable[iHash] = *source;
79    }
80    IHASH(*dest++ = *source++);
81  }
82}
83
84static int
85decompress(u_char * source, u_char * dest, int len)
86{
87  int i, bitmask;
88  unsigned char flags, *orgdest;
89
90  orgdest = dest;
91  while (len) {
92    flags = *source++;
93    len--;
94    for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) {
95      if (flags & bitmask) {
96	*dest = InputGuessTable[iHash];	/* Guess correct */
97      } else {
98	if (!len)
99	  break;		/* we seem to be really done -- cabo */
100	InputGuessTable[iHash] = *source;	/* Guess wrong */
101	*dest = *source++;	/* Read from source */
102	len--;
103      }
104      IHASH(*dest++);
105    }
106  }
107  return (dest - orgdest);
108}
109
110static void
111Pred1TermInput(void)
112{
113  if (InputGuessTable != NULL) {
114    free(InputGuessTable);
115    InputGuessTable = NULL;
116  }
117}
118
119static void
120Pred1TermOutput(void)
121{
122  if (OutputGuessTable != NULL) {
123    free(OutputGuessTable);
124    OutputGuessTable = NULL;
125  }
126}
127
128static void
129Pred1ResetInput(void)
130{
131  iHash = 0;
132  memset(InputGuessTable, '\0', GUESS_TABLE_SIZE);
133  LogPrintf(LogCCP, "Predictor1: Input channel reset\n");
134}
135
136static void
137Pred1ResetOutput(void)
138{
139  oHash = 0;
140  memset(OutputGuessTable, '\0', GUESS_TABLE_SIZE);
141  LogPrintf(LogCCP, "Predictor1: Output channel reset\n");
142}
143
144static int
145Pred1InitInput(void)
146{
147  if (InputGuessTable == NULL)
148    if ((InputGuessTable = malloc(GUESS_TABLE_SIZE)) == NULL)
149      return 0;
150  Pred1ResetInput();
151  return 1;
152}
153
154static int
155Pred1InitOutput(void)
156{
157  if (OutputGuessTable == NULL)
158    if ((OutputGuessTable = malloc(GUESS_TABLE_SIZE)) == NULL)
159      return 0;
160  Pred1ResetOutput();
161  return 1;
162}
163
164static int
165Pred1Output(int pri, u_short proto, struct mbuf * bp)
166{
167  struct mbuf *mwp;
168  u_char *cp, *wp, *hp;
169  int orglen, len;
170  u_char bufp[MAX_MTU + 2];
171  u_short fcs;
172
173  orglen = plength(bp) + 2;	/* add count of proto */
174  mwp = mballoc((orglen + 2) / 8 * 9 + 12, MB_HDLCOUT);
175  hp = wp = MBUF_CTOP(mwp);
176  cp = bufp;
177  *wp++ = *cp++ = orglen >> 8;
178  *wp++ = *cp++ = orglen & 0377;
179  *cp++ = proto >> 8;
180  *cp++ = proto & 0377;
181  mbread(bp, cp, orglen - 2);
182  fcs = HdlcFcs(INITFCS, bufp, 2 + orglen);
183  fcs = ~fcs;
184
185  len = compress(bufp + 2, wp, orglen);
186  LogPrintf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len);
187  CcpInfo.uncompout += orglen;
188  if (len < orglen) {
189    *hp |= 0x80;
190    wp += len;
191    CcpInfo.compout += len;
192  } else {
193    memcpy(wp, bufp + 2, orglen);
194    wp += orglen;
195    CcpInfo.compout += orglen;
196  }
197
198  *wp++ = fcs & 0377;
199  *wp++ = fcs >> 8;
200  mwp->cnt = wp - MBUF_CTOP(mwp);
201  HdlcOutput(PRI_NORMAL, PROTO_COMPD, mwp);
202  return 1;
203}
204
205static struct mbuf *
206Pred1Input(u_short *proto, struct mbuf *bp)
207{
208  u_char *cp, *pp;
209  int len, olen, len1;
210  struct mbuf *wp;
211  u_char *bufp;
212  u_short fcs;
213
214  wp = mballoc(MAX_MTU + 2, MB_IPIN);
215  cp = MBUF_CTOP(bp);
216  olen = plength(bp);
217  pp = bufp = MBUF_CTOP(wp);
218  *pp++ = *cp & 0177;
219  len = *cp++ << 8;
220  *pp++ = *cp;
221  len += *cp++;
222  CcpInfo.uncompin += len & 0x7fff;
223  if (len & 0x8000) {
224    len1 = decompress(cp, pp, olen - 4);
225    CcpInfo.compin += olen;
226    len &= 0x7fff;
227    if (len != len1) {		/* Error is detected. Send reset request */
228      LogPrintf(LogCCP, "Pred1: Length error\n");
229      CcpSendResetReq(&CcpFsm);
230      pfree(bp);
231      pfree(wp);
232      return NULL;
233    }
234    cp += olen - 4;
235    pp += len1;
236  } else {
237    CcpInfo.compin += len;
238    SyncTable(cp, pp, len);
239    cp += len;
240    pp += len;
241  }
242  *pp++ = *cp++;		/* CRC */
243  *pp++ = *cp++;
244  fcs = HdlcFcs(INITFCS, bufp, wp->cnt = pp - bufp);
245  if (fcs != GOODFCS)
246    LogPrintf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%s), len = 0x%x,"
247	      " olen = 0x%x\n", fcs, (fcs == GOODFCS) ? "good" : "bad",
248	      len, olen);
249  if (fcs == GOODFCS) {
250    wp->offset += 2;		/* skip length */
251    wp->cnt -= 4;		/* skip length & CRC */
252    pp = MBUF_CTOP(wp);
253    *proto = *pp++;
254    if (*proto & 1) {
255      wp->offset++;
256      wp->cnt--;
257    } else {
258      wp->offset += 2;
259      wp->cnt -= 2;
260      *proto = (*proto << 8) | *pp++;
261    }
262    return wp;
263  } else {
264    LogDumpBp(LogHDLC, "Bad FCS", wp);
265    CcpSendResetReq(&CcpFsm);
266    pfree(wp);
267  }
268  pfree(bp);
269  return NULL;
270}
271
272static void
273Pred1DictSetup(u_short proto, struct mbuf * bp)
274{
275}
276
277static const char *
278Pred1DispOpts(struct lcp_opt *o)
279{
280  return NULL;
281}
282
283static void
284Pred1GetOpts(struct lcp_opt *o)
285{
286  o->id = TY_PRED1;
287  o->len = 2;
288}
289
290static int
291Pred1SetOpts(struct lcp_opt *o)
292{
293  if (o->id != TY_PRED1 || o->len != 2) {
294    Pred1GetOpts(o);
295    return MODE_NAK;
296  }
297  return MODE_ACK;
298}
299
300const struct ccp_algorithm Pred1Algorithm = {
301  TY_PRED1,
302  ConfPred1,
303  Pred1DispOpts,
304  {
305    Pred1GetOpts,
306    Pred1SetOpts,
307    Pred1InitInput,
308    Pred1TermInput,
309    Pred1ResetInput,
310    Pred1Input,
311    Pred1DictSetup
312  },
313  {
314    Pred1GetOpts,
315    Pred1SetOpts,
316    Pred1InitOutput,
317    Pred1TermOutput,
318    Pred1ResetOutput,
319    Pred1Output
320  },
321};
322