2 * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
3 * Ian Donaldson <iand@labtam.labtam.oz.au>
4 * Carsten Bormann <cabo@cs.tu-berlin.de>
5 * Dave Rand <dlr@bungi.com>/<dave_rand@novell.com>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $FreeBSD: src/usr.sbin/ppp/pred.c,v 1.29.2.3 2002/09/01 02:12:31 brian Exp $
30 * $DragonFly: src/usr.sbin/ppp/pred.c,v 1.2 2003/06/17 04:30:01 dillon Exp $
33 #include <sys/types.h>
49 #include "throughput.h"
53 /* The following hash code is the heart of the algorithm:
54 * It builds a sliding hash sum of the previous 3-and-a-bit characters
55 * which will be used to index the guess table.
56 * A better hash function would result in additional compression,
57 * at the expense of time.
59 #define HASH(state, x) state->hash = (state->hash << 4) ^ (x)
60 #define GUESS_TABLE_SIZE 65536
64 u_char dict
[GUESS_TABLE_SIZE
];
68 compress(struct pred1_state
*state
, u_char
*source
, u_char
*dest
, int len
)
71 unsigned char *flagdest
, flags
, *orgdest
;
76 flags
= 0; /* All guess wrong initially */
77 for (bitmask
= 1, i
= 0; i
< 8 && len
; i
++, bitmask
<<= 1) {
78 if (state
->dict
[state
->hash
] == *source
) {
79 flags
|= bitmask
; /* Guess was right - don't output */
81 state
->dict
[state
->hash
] = *source
;
82 *dest
++ = *source
; /* Guess wrong, output char */
84 HASH(state
, *source
++);
89 return (dest
- orgdest
);
93 SyncTable(struct pred1_state
*state
, u_char
*source
, u_char
*dest
, int len
)
96 *dest
++ = state
->dict
[state
->hash
] = *source
;
97 HASH(state
, *source
++);
102 decompress(struct pred1_state
*state
, u_char
*source
, u_char
*dest
, int len
)
105 unsigned char flags
, *orgdest
;
111 for (i
= 0, bitmask
= 1; i
< 8; i
++, bitmask
<<= 1) {
112 if (flags
& bitmask
) {
113 *dest
= state
->dict
[state
->hash
]; /* Guess correct */
116 break; /* we seem to be really done -- cabo */
117 state
->dict
[state
->hash
] = *source
; /* Guess wrong */
118 *dest
= *source
++; /* Read from source */
121 HASH(state
, *dest
++);
124 return (dest
- orgdest
);
130 struct pred1_state
*state
= (struct pred1_state
*)v
;
135 Pred1ResetInput(void *v
)
137 struct pred1_state
*state
= (struct pred1_state
*)v
;
139 memset(state
->dict
, '\0', sizeof state
->dict
);
140 log_Printf(LogCCP
, "Predictor1: Input channel reset\n");
144 Pred1ResetOutput(void *v
)
146 struct pred1_state
*state
= (struct pred1_state
*)v
;
148 memset(state
->dict
, '\0', sizeof state
->dict
);
149 log_Printf(LogCCP
, "Predictor1: Output channel reset\n");
151 return 1; /* Ask FSM to ACK */
155 Pred1InitInput(struct bundle
*bundle
, struct fsm_opt
*o
)
157 struct pred1_state
*state
;
158 state
= (struct pred1_state
*)malloc(sizeof(struct pred1_state
));
160 Pred1ResetInput(state
);
165 Pred1InitOutput(struct bundle
*bundle
, struct fsm_opt
*o
)
167 struct pred1_state
*state
;
168 state
= (struct pred1_state
*)malloc(sizeof(struct pred1_state
));
170 Pred1ResetOutput(state
);
175 Pred1Output(void *v
, struct ccp
*ccp
, struct link
*l
, int pri
, u_short
*proto
,
178 struct pred1_state
*state
= (struct pred1_state
*)v
;
180 u_char
*cp
, *wp
, *hp
;
182 u_char bufp
[MAX_MTU
+ 2];
185 orglen
= m_length(bp
) + 2; /* add count of proto */
186 mwp
= m_get((orglen
+ 2) / 8 * 9 + 12, MB_CCPOUT
);
187 hp
= wp
= MBUF_CTOP(mwp
);
189 *wp
++ = *cp
++ = orglen
>> 8;
190 *wp
++ = *cp
++ = orglen
& 0377;
192 *cp
++ = *proto
& 0377;
193 mbuf_Read(bp
, cp
, orglen
- 2);
194 fcs
= hdlc_Fcs(bufp
, 2 + orglen
);
197 len
= compress(state
, bufp
+ 2, wp
, orglen
);
198 log_Printf(LogDEBUG
, "Pred1Output: orglen (%d) --> len (%d)\n", orglen
, len
);
199 ccp
->uncompout
+= orglen
;
205 memcpy(wp
, bufp
+ 2, orglen
);
207 ccp
->compout
+= orglen
;
212 mwp
->m_len
= wp
- MBUF_CTOP(mwp
);
213 *proto
= ccp_Proto(ccp
);
218 Pred1Input(void *v
, struct ccp
*ccp
, u_short
*proto
, struct mbuf
*bp
)
220 struct pred1_state
*state
= (struct pred1_state
*)v
;
227 wp
= m_get(MAX_MRU
+ 2, MB_CCPIN
);
230 pp
= bufp
= MBUF_CTOP(wp
);
235 ccp
->uncompin
+= len
& 0x7fff;
237 len1
= decompress(state
, cp
, pp
, olen
- 4);
240 if (len
!= len1
) { /* Error is detected. Send reset request */
241 log_Printf(LogCCP
, "Pred1: Length error (got %d, not %d)\n", len1
, len
);
242 fsm_Reopen(&ccp
->fsm
);
249 } else if (len
+ 4 != olen
) {
250 log_Printf(LogCCP
, "Pred1: Length error (got %d, not %d)\n", len
+ 4, olen
);
251 fsm_Reopen(&ccp
->fsm
);
257 SyncTable(state
, cp
, pp
, len
);
261 *pp
++ = *cp
++; /* CRC */
263 fcs
= hdlc_Fcs(bufp
, wp
->m_len
= pp
- bufp
);
264 if (fcs
== GOODFCS
) {
265 wp
->m_offset
+= 2; /* skip length */
266 wp
->m_len
-= 4; /* skip length & CRC */
275 *proto
= (*proto
<< 8) | *pp
++;
280 const char *pre
= *MBUF_CTOP(bp
) & 0x80 ? "" : "un";
281 log_Printf(LogDEBUG
, "Pred1Input: fcs = 0x%04x (%scompressed), len = 0x%x,"
282 " olen = 0x%x\n", fcs
, pre
, len
, olen
);
283 log_Printf(LogCCP
, "%s: Bad %scompressed CRC-16\n",
284 ccp
->fsm
.link
->name
, pre
);
285 fsm_Reopen(&ccp
->fsm
);
293 Pred1DictSetup(void *v
, struct ccp
*ccp
, u_short proto
, struct mbuf
*bp
)
298 Pred1DispOpts(struct fsm_opt
*o
)
304 Pred1InitOptsOutput(struct bundle
*bundle
, struct fsm_opt
*o
,
305 const struct ccp_config
*cfg
)
311 Pred1SetOpts(struct bundle
*bundle
, struct fsm_opt
*o
,
312 const struct ccp_config
*cfg
)
314 if (o
->hdr
.len
!= 2) {
321 const struct ccp_algorithm Pred1Algorithm
= {