xref: /freebsd/usr.sbin/ppp/pred.c (revision df7f5d4de4592a8948a25ce01e5bddfbb7ce39dc)
1 #include "fsm.h"
2 #include "hdlc.h"
3 #include "lcpproto.h"
4 #include "ccp.h"
5 
6 /*
7  *
8  * $Id$
9  *
10  * pred.c -- Test program for Dave Rand's rendition of the
11  * predictor algorithm
12  * Updated by: iand@labtam.labtam.oz.au (Ian Donaldson)
13  * Updated by: Carsten Bormann <cabo@cs.tu-berlin.de>
14  * Original  : Dave Rand <dlr@bungi.com>/<dave_rand@novell.com>
15  */
16 
17 /* The following hash code is the heart of the algorithm:
18  * It builds a sliding hash sum of the previous 3-and-a-bit characters
19  * which will be used to index the guess table.
20  * A better hash function would result in additional compression,
21  * at the expense of time.
22  */
23 #define IHASH(x) iHash = (iHash << 4) ^ (x)
24 #define OHASH(x) oHash = (oHash << 4) ^ (x)
25 
26 static unsigned short int iHash, oHash;
27 static unsigned char InputGuessTable[65536];
28 static unsigned char OutputGuessTable[65536];
29 
30 static int
31 compress(source, dest, len)
32 unsigned char *source, *dest;
33 int len;
34 {
35     int i, bitmask;
36     unsigned char *flagdest, flags, *orgdest;
37 
38     orgdest = dest;
39     while (len) {
40         flagdest = dest++; flags = 0;   /* All guess wrong initially */
41         for (bitmask=1, i=0; i < 8 && len; i++, bitmask <<= 1) {
42             if (OutputGuessTable[oHash] == *source) {
43                 flags |= bitmask;       /* Guess was right - don't output */
44             } else {
45                 OutputGuessTable[oHash] = *source;
46                 *dest++ = *source;      /* Guess wrong, output char */
47             }
48             OHASH(*source++);len--;
49         }
50         *flagdest = flags;
51     }
52     return(dest - orgdest);
53 }
54 
55 static void
56 SyncTable(source, dest, len)
57 unsigned char *source, *dest;
58 int len;
59 {
60 
61     while (len--) {
62         if (InputGuessTable[iHash] != *source) {
63             InputGuessTable[iHash] = *source;
64         }
65         IHASH(*dest++ = *source++);
66     }
67 }
68 
69 static int
70 decompress(source, dest, len)
71 unsigned char *source, *dest;
72 int len;
73 {
74     int i, bitmask;
75     unsigned char flags, *orgdest;
76 
77     orgdest = dest;
78     while (len) {
79         flags = *source++;
80         len--;
81         for (i=0, bitmask = 1; i < 8; i++, bitmask <<= 1) {
82             if (flags & bitmask) {
83                 *dest = InputGuessTable[iHash];       /* Guess correct */
84             } else {
85                 if (!len)
86                     break;      /* we seem to be really done -- cabo */
87                 InputGuessTable[iHash] = *source;     /* Guess wrong */
88                 *dest = *source++;              /* Read from source */
89                 len--;
90             }
91             IHASH(*dest++);
92         }
93     }
94     return(dest - orgdest);
95 }
96 
97 #define SIZ1 2048
98 
99 void
100 Pred1Init(direction)
101 int direction;
102 {
103   if (direction & 1) {	/* Input part */
104     iHash = 0;
105     bzero(InputGuessTable, sizeof(InputGuessTable));
106   }
107   if (direction & 2) { /* Output part */
108     oHash = 0;
109     bzero(OutputGuessTable, sizeof(OutputGuessTable));
110   }
111 }
112 
113 void
114 Pred1Output(pri, proto, bp)
115 int pri;
116 u_short proto;
117 struct mbuf *bp;
118 {
119   struct mbuf *mwp;
120   u_char *cp, *wp, *hp;
121   int orglen, len;
122   u_char bufp[SIZ1];
123   u_short fcs;
124 
125   orglen = plength(bp) + 2;	/* add count of proto */
126   mwp = mballoc((orglen+2)/8*9+12, MB_HDLCOUT);
127   hp = wp = MBUF_CTOP(mwp);
128   cp = bufp;
129   *wp++ = *cp++ = orglen >> 8;
130   *wp++ = *cp++ = orglen & 0377;
131   *cp++ = proto >> 8;
132   *cp++ = proto & 0377;
133   mbread(bp, cp, orglen-2);
134   fcs = HdlcFcs(INITFCS, bufp, 2+orglen);
135   fcs = ~fcs;
136 
137   len = compress(bufp + 2, wp, orglen);
138 #ifdef DEBUG
139   logprintf("orglen (%d) --> len (%d)\n", orglen, len);
140 #endif
141   CcpInfo.orgout += orglen;
142   if (len < orglen) {
143     *hp |= 0x80;
144     wp += len;
145     CcpInfo.compout += len;
146   } else {
147     bcopy(bufp+2, wp, orglen);
148     wp += orglen;
149     CcpInfo.compout += orglen;
150   }
151 
152   *wp++ = fcs & 0377;
153   *wp++ = fcs >> 8;
154   mwp->cnt = wp - MBUF_CTOP(mwp);
155   HdlcOutput(PRI_NORMAL, PROTO_COMPD, mwp);
156 }
157 
158 void
159 Pred1Input(bp)
160 struct mbuf *bp;
161 {
162   u_char *cp, *pp;
163   int len, olen, len1;
164   struct mbuf *wp;
165   u_char *bufp;
166   u_short fcs, proto;
167 
168   wp = mballoc(SIZ1, MB_IPIN);
169   cp = MBUF_CTOP(bp);
170   olen = plength(bp);
171   pp = bufp = MBUF_CTOP(wp);
172   *pp++ = *cp & 0177;
173   len = *cp++ << 8;
174   *pp++ = *cp;
175   len += *cp++;
176   CcpInfo.orgin += len & 0x7fff;
177   if (len & 0x8000) {
178     len1 = decompress(cp, pp, olen - 4);
179     CcpInfo.compin += olen;
180     len &= 0x7fff;
181     if (len != len1) {	/* Error is detected. Send reset request */
182       LogPrintf(LOG_LCP_BIT, "%s: Length Error\n", CcpFsm.name);
183       CcpSendResetReq(&CcpFsm);
184       pfree(bp);
185       pfree(wp);
186       return;
187     }
188     cp += olen - 4;
189     pp += len1;
190   } else {
191     CcpInfo.compin += len;
192     SyncTable(cp, pp, len);
193     cp += len;
194     pp += len;
195   }
196   *pp++ = *cp++;	/* CRC */
197   *pp++ = *cp++;
198   fcs = HdlcFcs(INITFCS, bufp, wp->cnt = pp - bufp);
199 #ifdef DEBUG
200   if (fcs != GOODFCS)
201   logprintf("fcs = 0x%04x (%s), len = 0x%x, olen = 0x%x\n",
202        fcs, (fcs == GOODFCS)? "good" : "bad", len, olen);
203 #endif
204   if (fcs == GOODFCS) {
205     wp->offset += 2;		/* skip length */
206     wp->cnt -= 4;		/* skip length & CRC */
207     pp = MBUF_CTOP(wp);
208     proto = *pp++;
209     if (proto & 1) {
210       wp->offset++;
211       wp->cnt--;
212     } else {
213       wp->offset += 2;
214       wp->cnt -= 2;
215       proto = (proto << 8) | *pp++;
216     }
217     DecodePacket(proto, wp);
218   }
219   else
220   {
221       LogDumpBp(LOG_HDLC, "Bad FCS", wp);
222       CcpSendResetReq(&CcpFsm);
223       pfree(wp);
224   }
225   pfree(bp);
226 }
227