11ae349f5Scvs2svn /*- 21ae349f5Scvs2svn * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> 31ae349f5Scvs2svn * Ian Donaldson <iand@labtam.labtam.oz.au> 41ae349f5Scvs2svn * Carsten Bormann <cabo@cs.tu-berlin.de> 51ae349f5Scvs2svn * Dave Rand <dlr@bungi.com>/<dave_rand@novell.com> 61ae349f5Scvs2svn * All rights reserved. 71ae349f5Scvs2svn * 81ae349f5Scvs2svn * Redistribution and use in source and binary forms, with or without 91ae349f5Scvs2svn * modification, are permitted provided that the following conditions 101ae349f5Scvs2svn * are met: 111ae349f5Scvs2svn * 1. Redistributions of source code must retain the above copyright 121ae349f5Scvs2svn * notice, this list of conditions and the following disclaimer. 131ae349f5Scvs2svn * 2. Redistributions in binary form must reproduce the above copyright 141ae349f5Scvs2svn * notice, this list of conditions and the following disclaimer in the 151ae349f5Scvs2svn * documentation and/or other materials provided with the distribution. 161ae349f5Scvs2svn * 171ae349f5Scvs2svn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 181ae349f5Scvs2svn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191ae349f5Scvs2svn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201ae349f5Scvs2svn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 211ae349f5Scvs2svn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221ae349f5Scvs2svn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231ae349f5Scvs2svn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241ae349f5Scvs2svn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251ae349f5Scvs2svn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261ae349f5Scvs2svn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271ae349f5Scvs2svn * SUCH DAMAGE. 281ae349f5Scvs2svn * 29dd7e2610SBrian Somers * $Id: pred.c,v 1.20.2.11 1998/04/25 00:09:14 brian Exp $ 301ae349f5Scvs2svn */ 311ae349f5Scvs2svn 322764b86aSBrian Somers #include <sys/types.h> 331ae349f5Scvs2svn 341ae349f5Scvs2svn #include <stdlib.h> 351ae349f5Scvs2svn #include <string.h> 361ae349f5Scvs2svn 371ae349f5Scvs2svn #include "mbuf.h" 381ae349f5Scvs2svn #include "log.h" 391ae349f5Scvs2svn #include "timer.h" 401ae349f5Scvs2svn #include "fsm.h" 41879ed6faSBrian Somers #include "lqr.h" 421ae349f5Scvs2svn #include "hdlc.h" 431ae349f5Scvs2svn #include "lcp.h" 441ae349f5Scvs2svn #include "ccp.h" 451ae349f5Scvs2svn #include "pred.h" 461ae349f5Scvs2svn 471ae349f5Scvs2svn /* The following hash code is the heart of the algorithm: 481ae349f5Scvs2svn * It builds a sliding hash sum of the previous 3-and-a-bit characters 491ae349f5Scvs2svn * which will be used to index the guess table. 501ae349f5Scvs2svn * A better hash function would result in additional compression, 511ae349f5Scvs2svn * at the expense of time. 521ae349f5Scvs2svn */ 5303036ec7SBrian Somers #define HASH(state, x) state->hash = (state->hash << 4) ^ (x) 541ae349f5Scvs2svn #define GUESS_TABLE_SIZE 65536 551ae349f5Scvs2svn 5603036ec7SBrian Somers struct pred1_state { 5703036ec7SBrian Somers u_short hash; 5803036ec7SBrian Somers u_char dict[GUESS_TABLE_SIZE]; 5903036ec7SBrian Somers }; 601ae349f5Scvs2svn 611ae349f5Scvs2svn static int 6203036ec7SBrian Somers compress(struct pred1_state *state, u_char *source, u_char *dest, int len) 631ae349f5Scvs2svn { 641ae349f5Scvs2svn int i, bitmask; 651ae349f5Scvs2svn unsigned char *flagdest, flags, *orgdest; 661ae349f5Scvs2svn 671ae349f5Scvs2svn orgdest = dest; 681ae349f5Scvs2svn while (len) { 691ae349f5Scvs2svn flagdest = dest++; 701ae349f5Scvs2svn flags = 0; /* All guess wrong initially */ 711ae349f5Scvs2svn for (bitmask = 1, i = 0; i < 8 && len; i++, bitmask <<= 1) { 7203036ec7SBrian Somers if (state->dict[state->hash] == *source) { 731ae349f5Scvs2svn flags |= bitmask; /* Guess was right - don't output */ 741ae349f5Scvs2svn } else { 7503036ec7SBrian Somers state->dict[state->hash] = *source; 761ae349f5Scvs2svn *dest++ = *source; /* Guess wrong, output char */ 771ae349f5Scvs2svn } 7803036ec7SBrian Somers HASH(state, *source++); 791ae349f5Scvs2svn len--; 801ae349f5Scvs2svn } 811ae349f5Scvs2svn *flagdest = flags; 821ae349f5Scvs2svn } 831ae349f5Scvs2svn return (dest - orgdest); 841ae349f5Scvs2svn } 851ae349f5Scvs2svn 861ae349f5Scvs2svn static void 8703036ec7SBrian Somers SyncTable(struct pred1_state *state, u_char * source, u_char * dest, int len) 881ae349f5Scvs2svn { 891ae349f5Scvs2svn while (len--) { 9003036ec7SBrian Somers if (state->dict[state->hash] != *source) 9103036ec7SBrian Somers state->dict[state->hash] = *source; 9203036ec7SBrian Somers HASH(state, *dest++ = *source++); 931ae349f5Scvs2svn } 941ae349f5Scvs2svn } 951ae349f5Scvs2svn 961ae349f5Scvs2svn static int 9703036ec7SBrian Somers decompress(struct pred1_state *state, u_char * source, u_char * dest, int len) 981ae349f5Scvs2svn { 991ae349f5Scvs2svn int i, bitmask; 1001ae349f5Scvs2svn unsigned char flags, *orgdest; 1011ae349f5Scvs2svn 1021ae349f5Scvs2svn orgdest = dest; 1031ae349f5Scvs2svn while (len) { 1041ae349f5Scvs2svn flags = *source++; 1051ae349f5Scvs2svn len--; 1061ae349f5Scvs2svn for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) { 1071ae349f5Scvs2svn if (flags & bitmask) { 10803036ec7SBrian Somers *dest = state->dict[state->hash]; /* Guess correct */ 1091ae349f5Scvs2svn } else { 1101ae349f5Scvs2svn if (!len) 1111ae349f5Scvs2svn break; /* we seem to be really done -- cabo */ 11203036ec7SBrian Somers state->dict[state->hash] = *source; /* Guess wrong */ 1131ae349f5Scvs2svn *dest = *source++; /* Read from source */ 1141ae349f5Scvs2svn len--; 1151ae349f5Scvs2svn } 11603036ec7SBrian Somers HASH(state, *dest++); 1171ae349f5Scvs2svn } 1181ae349f5Scvs2svn } 1191ae349f5Scvs2svn return (dest - orgdest); 1201ae349f5Scvs2svn } 1211ae349f5Scvs2svn 1221ae349f5Scvs2svn static void 12303036ec7SBrian Somers Pred1Term(void *v) 1241ae349f5Scvs2svn { 12503036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 12603036ec7SBrian Somers free(state); 1271ae349f5Scvs2svn } 1281ae349f5Scvs2svn 1291ae349f5Scvs2svn static void 13003036ec7SBrian Somers Pred1ResetInput(void *v) 1311ae349f5Scvs2svn { 13203036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 13303036ec7SBrian Somers state->hash = 0; 13403036ec7SBrian Somers memset(state->dict, '\0', sizeof state->dict); 135dd7e2610SBrian Somers log_Printf(LogCCP, "Predictor1: Input channel reset\n"); 1361ae349f5Scvs2svn } 1371ae349f5Scvs2svn 1381ae349f5Scvs2svn static void 13903036ec7SBrian Somers Pred1ResetOutput(void *v) 1401ae349f5Scvs2svn { 14103036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 14203036ec7SBrian Somers state->hash = 0; 14303036ec7SBrian Somers memset(state->dict, '\0', sizeof state->dict); 144dd7e2610SBrian Somers log_Printf(LogCCP, "Predictor1: Output channel reset\n"); 1451ae349f5Scvs2svn } 1461ae349f5Scvs2svn 14703036ec7SBrian Somers static void * 14803036ec7SBrian Somers Pred1InitInput(struct lcp_opt *o) 1491ae349f5Scvs2svn { 15003036ec7SBrian Somers struct pred1_state *state; 15103036ec7SBrian Somers state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); 15203036ec7SBrian Somers if (state != NULL) 15303036ec7SBrian Somers Pred1ResetInput(state); 15403036ec7SBrian Somers return state; 15503036ec7SBrian Somers } 15603036ec7SBrian Somers 15703036ec7SBrian Somers static void * 15803036ec7SBrian Somers Pred1InitOutput(struct lcp_opt *o) 15903036ec7SBrian Somers { 16003036ec7SBrian Somers struct pred1_state *state; 16103036ec7SBrian Somers state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); 16203036ec7SBrian Somers if (state != NULL) 16303036ec7SBrian Somers Pred1ResetOutput(state); 16403036ec7SBrian Somers return state; 1651ae349f5Scvs2svn } 1661ae349f5Scvs2svn 1671ae349f5Scvs2svn static int 16803036ec7SBrian Somers Pred1Output(void *v, struct ccp *ccp, struct link *l, int pri, u_short proto, 169f4768038SBrian Somers struct mbuf *bp) 1701ae349f5Scvs2svn { 17103036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 1721ae349f5Scvs2svn struct mbuf *mwp; 1731ae349f5Scvs2svn u_char *cp, *wp, *hp; 1741ae349f5Scvs2svn int orglen, len; 1751ae349f5Scvs2svn u_char bufp[MAX_MTU + 2]; 1761ae349f5Scvs2svn u_short fcs; 1771ae349f5Scvs2svn 178dd7e2610SBrian Somers orglen = mbuf_Length(bp) + 2; /* add count of proto */ 179dd7e2610SBrian Somers mwp = mbuf_Alloc((orglen + 2) / 8 * 9 + 12, MB_HDLCOUT); 1801ae349f5Scvs2svn hp = wp = MBUF_CTOP(mwp); 1811ae349f5Scvs2svn cp = bufp; 1821ae349f5Scvs2svn *wp++ = *cp++ = orglen >> 8; 1831ae349f5Scvs2svn *wp++ = *cp++ = orglen & 0377; 1841ae349f5Scvs2svn *cp++ = proto >> 8; 1851ae349f5Scvs2svn *cp++ = proto & 0377; 186dd7e2610SBrian Somers mbuf_Read(bp, cp, orglen - 2); 187dd7e2610SBrian Somers fcs = hdlc_Fcs(INITFCS, bufp, 2 + orglen); 1881ae349f5Scvs2svn fcs = ~fcs; 1891ae349f5Scvs2svn 19003036ec7SBrian Somers len = compress(state, bufp + 2, wp, orglen); 191dd7e2610SBrian Somers log_Printf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len); 192f4768038SBrian Somers ccp->uncompout += orglen; 1931ae349f5Scvs2svn if (len < orglen) { 1941ae349f5Scvs2svn *hp |= 0x80; 1951ae349f5Scvs2svn wp += len; 196f4768038SBrian Somers ccp->compout += len; 1971ae349f5Scvs2svn } else { 1981ae349f5Scvs2svn memcpy(wp, bufp + 2, orglen); 1991ae349f5Scvs2svn wp += orglen; 200f4768038SBrian Somers ccp->compout += orglen; 2011ae349f5Scvs2svn } 2021ae349f5Scvs2svn 2031ae349f5Scvs2svn *wp++ = fcs & 0377; 2041ae349f5Scvs2svn *wp++ = fcs >> 8; 2051ae349f5Scvs2svn mwp->cnt = wp - MBUF_CTOP(mwp); 206dd7e2610SBrian Somers hdlc_Output(l, PRI_NORMAL, ccp_Proto(ccp), mwp); 2071ae349f5Scvs2svn return 1; 2081ae349f5Scvs2svn } 2091ae349f5Scvs2svn 2101ae349f5Scvs2svn static struct mbuf * 21103036ec7SBrian Somers Pred1Input(void *v, struct ccp *ccp, u_short *proto, struct mbuf *bp) 2121ae349f5Scvs2svn { 21303036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 2141ae349f5Scvs2svn u_char *cp, *pp; 2151ae349f5Scvs2svn int len, olen, len1; 2161ae349f5Scvs2svn struct mbuf *wp; 2171ae349f5Scvs2svn u_char *bufp; 2181ae349f5Scvs2svn u_short fcs; 2191ae349f5Scvs2svn 220dd7e2610SBrian Somers wp = mbuf_Alloc(MAX_MTU + 2, MB_IPIN); 2211ae349f5Scvs2svn cp = MBUF_CTOP(bp); 222dd7e2610SBrian Somers olen = mbuf_Length(bp); 2231ae349f5Scvs2svn pp = bufp = MBUF_CTOP(wp); 2241ae349f5Scvs2svn *pp++ = *cp & 0177; 2251ae349f5Scvs2svn len = *cp++ << 8; 2261ae349f5Scvs2svn *pp++ = *cp; 2271ae349f5Scvs2svn len += *cp++; 228f4768038SBrian Somers ccp->uncompin += len & 0x7fff; 2291ae349f5Scvs2svn if (len & 0x8000) { 23003036ec7SBrian Somers len1 = decompress(state, cp, pp, olen - 4); 231f4768038SBrian Somers ccp->compin += olen; 2321ae349f5Scvs2svn len &= 0x7fff; 2331ae349f5Scvs2svn if (len != len1) { /* Error is detected. Send reset request */ 234dd7e2610SBrian Somers log_Printf(LogCCP, "Pred1: Length error\n"); 235dd7e2610SBrian Somers ccp_SendResetReq(&ccp->fsm); 236dd7e2610SBrian Somers mbuf_Free(bp); 237dd7e2610SBrian Somers mbuf_Free(wp); 2381ae349f5Scvs2svn return NULL; 2391ae349f5Scvs2svn } 2401ae349f5Scvs2svn cp += olen - 4; 2411ae349f5Scvs2svn pp += len1; 2421ae349f5Scvs2svn } else { 243f4768038SBrian Somers ccp->compin += len; 24403036ec7SBrian Somers SyncTable(state, cp, pp, len); 2451ae349f5Scvs2svn cp += len; 2461ae349f5Scvs2svn pp += len; 2471ae349f5Scvs2svn } 2481ae349f5Scvs2svn *pp++ = *cp++; /* CRC */ 2491ae349f5Scvs2svn *pp++ = *cp++; 250dd7e2610SBrian Somers fcs = hdlc_Fcs(INITFCS, bufp, wp->cnt = pp - bufp); 2511ae349f5Scvs2svn if (fcs != GOODFCS) 252dd7e2610SBrian Somers log_Printf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%s), len = 0x%x," 2531ae349f5Scvs2svn " olen = 0x%x\n", fcs, (fcs == GOODFCS) ? "good" : "bad", 2541ae349f5Scvs2svn len, olen); 2551ae349f5Scvs2svn if (fcs == GOODFCS) { 2561ae349f5Scvs2svn wp->offset += 2; /* skip length */ 2571ae349f5Scvs2svn wp->cnt -= 4; /* skip length & CRC */ 2581ae349f5Scvs2svn pp = MBUF_CTOP(wp); 2591ae349f5Scvs2svn *proto = *pp++; 2601ae349f5Scvs2svn if (*proto & 1) { 2611ae349f5Scvs2svn wp->offset++; 2621ae349f5Scvs2svn wp->cnt--; 2631ae349f5Scvs2svn } else { 2641ae349f5Scvs2svn wp->offset += 2; 2651ae349f5Scvs2svn wp->cnt -= 2; 2661ae349f5Scvs2svn *proto = (*proto << 8) | *pp++; 2671ae349f5Scvs2svn } 268dd7e2610SBrian Somers mbuf_Free(bp); 2691ae349f5Scvs2svn return wp; 2701ae349f5Scvs2svn } else { 271dd7e2610SBrian Somers log_DumpBp(LogHDLC, "Bad FCS", wp); 272dd7e2610SBrian Somers ccp_SendResetReq(&ccp->fsm); 273dd7e2610SBrian Somers mbuf_Free(wp); 2741ae349f5Scvs2svn } 275dd7e2610SBrian Somers mbuf_Free(bp); 2761ae349f5Scvs2svn return NULL; 2771ae349f5Scvs2svn } 2781ae349f5Scvs2svn 2791ae349f5Scvs2svn static void 28003036ec7SBrian Somers Pred1DictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf * bp) 2811ae349f5Scvs2svn { 2821ae349f5Scvs2svn } 2831ae349f5Scvs2svn 2841ae349f5Scvs2svn static const char * 2851ae349f5Scvs2svn Pred1DispOpts(struct lcp_opt *o) 2861ae349f5Scvs2svn { 2871ae349f5Scvs2svn return NULL; 2881ae349f5Scvs2svn } 2891ae349f5Scvs2svn 2901ae349f5Scvs2svn static void 29103036ec7SBrian Somers Pred1InitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg) 2921ae349f5Scvs2svn { 2931ae349f5Scvs2svn o->len = 2; 2941ae349f5Scvs2svn } 2951ae349f5Scvs2svn 2961ae349f5Scvs2svn static int 29703036ec7SBrian Somers Pred1SetOptsOutput(struct lcp_opt *o) 2981ae349f5Scvs2svn { 29903036ec7SBrian Somers if (o->len != 2) { 30003036ec7SBrian Somers o->len = 2; 3011ae349f5Scvs2svn return MODE_NAK; 3021ae349f5Scvs2svn } 3031ae349f5Scvs2svn return MODE_ACK; 3041ae349f5Scvs2svn } 3051ae349f5Scvs2svn 30603036ec7SBrian Somers static int 30703036ec7SBrian Somers Pred1SetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg) 30803036ec7SBrian Somers { 30903036ec7SBrian Somers return Pred1SetOptsOutput(o); 31003036ec7SBrian Somers } 31103036ec7SBrian Somers 3121ae349f5Scvs2svn const struct ccp_algorithm Pred1Algorithm = { 3131ae349f5Scvs2svn TY_PRED1, 3141342caedSBrian Somers CCP_NEG_PRED1, 3151ae349f5Scvs2svn Pred1DispOpts, 3161ae349f5Scvs2svn { 31703036ec7SBrian Somers Pred1SetOptsInput, 3181ae349f5Scvs2svn Pred1InitInput, 31903036ec7SBrian Somers Pred1Term, 3201ae349f5Scvs2svn Pred1ResetInput, 3211ae349f5Scvs2svn Pred1Input, 3221ae349f5Scvs2svn Pred1DictSetup 3231ae349f5Scvs2svn }, 3241ae349f5Scvs2svn { 32503036ec7SBrian Somers Pred1InitOptsOutput, 32603036ec7SBrian Somers Pred1SetOptsOutput, 3271ae349f5Scvs2svn Pred1InitOutput, 32803036ec7SBrian Somers Pred1Term, 3291ae349f5Scvs2svn Pred1ResetOutput, 3301ae349f5Scvs2svn Pred1Output 3311ae349f5Scvs2svn }, 3321ae349f5Scvs2svn }; 333