1c39934eaSBrian Somers /*- 2c39934eaSBrian Somers * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> 3c39934eaSBrian Somers * Ian Donaldson <iand@labtam.labtam.oz.au> 4c39934eaSBrian Somers * Carsten Bormann <cabo@cs.tu-berlin.de> 5c39934eaSBrian Somers * Dave Rand <dlr@bungi.com>/<dave_rand@novell.com> 6c39934eaSBrian Somers * All rights reserved. 775240ed1SBrian Somers * 8c39934eaSBrian Somers * Redistribution and use in source and binary forms, with or without 9c39934eaSBrian Somers * modification, are permitted provided that the following conditions 10c39934eaSBrian Somers * are met: 11c39934eaSBrian Somers * 1. Redistributions of source code must retain the above copyright 12c39934eaSBrian Somers * notice, this list of conditions and the following disclaimer. 13c39934eaSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 14c39934eaSBrian Somers * notice, this list of conditions and the following disclaimer in the 15c39934eaSBrian Somers * documentation and/or other materials provided with the distribution. 1675240ed1SBrian Somers * 17c39934eaSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18c39934eaSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19c39934eaSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20c39934eaSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21c39934eaSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22c39934eaSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23c39934eaSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24c39934eaSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25c39934eaSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26c39934eaSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27c39934eaSBrian Somers * SUCH DAMAGE. 28c39934eaSBrian Somers * 29a36ca3ccSBrian Somers * $Id: pred.c,v 1.22 1998/08/07 18:42:50 brian Exp $ 30af57ed9fSAtsushi Murai */ 31af57ed9fSAtsushi Murai 322764b86aSBrian Somers #include <sys/types.h> 3375240ed1SBrian Somers 340053cc58SBrian Somers #include <stdlib.h> 3575240ed1SBrian Somers #include <string.h> 3675240ed1SBrian Somers 3792b09558SBrian Somers #include "defs.h" 3875240ed1SBrian Somers #include "mbuf.h" 3975240ed1SBrian Somers #include "log.h" 4075240ed1SBrian Somers #include "timer.h" 4175240ed1SBrian Somers #include "fsm.h" 42879ed6faSBrian Somers #include "lqr.h" 4375240ed1SBrian Somers #include "hdlc.h" 440053cc58SBrian Somers #include "lcp.h" 4575240ed1SBrian Somers #include "ccp.h" 46a36ca3ccSBrian Somers #include "throughput.h" 47a36ca3ccSBrian Somers #include "link.h" 4875240ed1SBrian Somers #include "pred.h" 4975240ed1SBrian Somers 50af57ed9fSAtsushi Murai /* The following hash code is the heart of the algorithm: 51af57ed9fSAtsushi Murai * It builds a sliding hash sum of the previous 3-and-a-bit characters 52af57ed9fSAtsushi Murai * which will be used to index the guess table. 53af57ed9fSAtsushi Murai * A better hash function would result in additional compression, 54af57ed9fSAtsushi Murai * at the expense of time. 55af57ed9fSAtsushi Murai */ 5603036ec7SBrian Somers #define HASH(state, x) state->hash = (state->hash << 4) ^ (x) 570053cc58SBrian Somers #define GUESS_TABLE_SIZE 65536 58af57ed9fSAtsushi Murai 5903036ec7SBrian Somers struct pred1_state { 6003036ec7SBrian Somers u_short hash; 6103036ec7SBrian Somers u_char dict[GUESS_TABLE_SIZE]; 6203036ec7SBrian Somers }; 63af57ed9fSAtsushi Murai 64af57ed9fSAtsushi Murai static int 6503036ec7SBrian Somers compress(struct pred1_state *state, u_char *source, u_char *dest, int len) 66af57ed9fSAtsushi Murai { 67af57ed9fSAtsushi Murai int i, bitmask; 68af57ed9fSAtsushi Murai unsigned char *flagdest, flags, *orgdest; 69af57ed9fSAtsushi Murai 70af57ed9fSAtsushi Murai orgdest = dest; 71af57ed9fSAtsushi Murai while (len) { 72944f7098SBrian Somers flagdest = dest++; 73944f7098SBrian Somers flags = 0; /* All guess wrong initially */ 74af57ed9fSAtsushi Murai for (bitmask = 1, i = 0; i < 8 && len; i++, bitmask <<= 1) { 7503036ec7SBrian Somers if (state->dict[state->hash] == *source) { 76af57ed9fSAtsushi Murai flags |= bitmask; /* Guess was right - don't output */ 77af57ed9fSAtsushi Murai } else { 7803036ec7SBrian Somers state->dict[state->hash] = *source; 79af57ed9fSAtsushi Murai *dest++ = *source; /* Guess wrong, output char */ 80af57ed9fSAtsushi Murai } 8103036ec7SBrian Somers HASH(state, *source++); 82944f7098SBrian Somers len--; 83af57ed9fSAtsushi Murai } 84af57ed9fSAtsushi Murai *flagdest = flags; 85af57ed9fSAtsushi Murai } 86af57ed9fSAtsushi Murai return (dest - orgdest); 87af57ed9fSAtsushi Murai } 88af57ed9fSAtsushi Murai 89af57ed9fSAtsushi Murai static void 9003036ec7SBrian Somers SyncTable(struct pred1_state *state, u_char * source, u_char * dest, int len) 91af57ed9fSAtsushi Murai { 92af57ed9fSAtsushi Murai while (len--) { 9303036ec7SBrian Somers if (state->dict[state->hash] != *source) 9403036ec7SBrian Somers state->dict[state->hash] = *source; 9503036ec7SBrian Somers HASH(state, *dest++ = *source++); 96af57ed9fSAtsushi Murai } 97af57ed9fSAtsushi Murai } 98af57ed9fSAtsushi Murai 99af57ed9fSAtsushi Murai static int 10003036ec7SBrian Somers decompress(struct pred1_state *state, u_char * source, u_char * dest, int len) 101af57ed9fSAtsushi Murai { 102af57ed9fSAtsushi Murai int i, bitmask; 103af57ed9fSAtsushi Murai unsigned char flags, *orgdest; 104af57ed9fSAtsushi Murai 105af57ed9fSAtsushi Murai orgdest = dest; 106af57ed9fSAtsushi Murai while (len) { 107af57ed9fSAtsushi Murai flags = *source++; 108af57ed9fSAtsushi Murai len--; 109af57ed9fSAtsushi Murai for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) { 110af57ed9fSAtsushi Murai if (flags & bitmask) { 11103036ec7SBrian Somers *dest = state->dict[state->hash]; /* Guess correct */ 112af57ed9fSAtsushi Murai } else { 113af57ed9fSAtsushi Murai if (!len) 114af57ed9fSAtsushi Murai break; /* we seem to be really done -- cabo */ 11503036ec7SBrian Somers state->dict[state->hash] = *source; /* Guess wrong */ 116af57ed9fSAtsushi Murai *dest = *source++; /* Read from source */ 117af57ed9fSAtsushi Murai len--; 118af57ed9fSAtsushi Murai } 11903036ec7SBrian Somers HASH(state, *dest++); 120af57ed9fSAtsushi Murai } 121af57ed9fSAtsushi Murai } 122af57ed9fSAtsushi Murai return (dest - orgdest); 123af57ed9fSAtsushi Murai } 124af57ed9fSAtsushi Murai 1250053cc58SBrian Somers static void 12603036ec7SBrian Somers Pred1Term(void *v) 127af57ed9fSAtsushi Murai { 12803036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 12903036ec7SBrian Somers free(state); 130af57ed9fSAtsushi Murai } 131af57ed9fSAtsushi Murai 1320053cc58SBrian Somers static void 13303036ec7SBrian Somers Pred1ResetInput(void *v) 1340053cc58SBrian Somers { 13503036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 13603036ec7SBrian Somers state->hash = 0; 13703036ec7SBrian Somers memset(state->dict, '\0', sizeof state->dict); 138dd7e2610SBrian Somers log_Printf(LogCCP, "Predictor1: Input channel reset\n"); 1390053cc58SBrian Somers } 1400053cc58SBrian Somers 1410053cc58SBrian Somers static void 14203036ec7SBrian Somers Pred1ResetOutput(void *v) 1430053cc58SBrian Somers { 14403036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 14503036ec7SBrian Somers state->hash = 0; 14603036ec7SBrian Somers memset(state->dict, '\0', sizeof state->dict); 147dd7e2610SBrian Somers log_Printf(LogCCP, "Predictor1: Output channel reset\n"); 1480053cc58SBrian Somers } 1490053cc58SBrian Somers 15003036ec7SBrian Somers static void * 15103036ec7SBrian Somers Pred1InitInput(struct lcp_opt *o) 1520053cc58SBrian Somers { 15303036ec7SBrian Somers struct pred1_state *state; 15403036ec7SBrian Somers state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); 15503036ec7SBrian Somers if (state != NULL) 15603036ec7SBrian Somers Pred1ResetInput(state); 15703036ec7SBrian Somers return state; 15803036ec7SBrian Somers } 15903036ec7SBrian Somers 16003036ec7SBrian Somers static void * 16103036ec7SBrian Somers Pred1InitOutput(struct lcp_opt *o) 16203036ec7SBrian Somers { 16303036ec7SBrian Somers struct pred1_state *state; 16403036ec7SBrian Somers state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); 16503036ec7SBrian Somers if (state != NULL) 16603036ec7SBrian Somers Pred1ResetOutput(state); 16703036ec7SBrian Somers return state; 1680053cc58SBrian Somers } 1690053cc58SBrian Somers 1700053cc58SBrian Somers static int 17103036ec7SBrian Somers Pred1Output(void *v, struct ccp *ccp, struct link *l, int pri, u_short proto, 172f4768038SBrian Somers struct mbuf *bp) 1730053cc58SBrian Somers { 17403036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 175af57ed9fSAtsushi Murai struct mbuf *mwp; 176af57ed9fSAtsushi Murai u_char *cp, *wp, *hp; 177af57ed9fSAtsushi Murai int orglen, len; 178e979ce38SBrian Somers u_char bufp[MAX_MTU + 2]; 179af57ed9fSAtsushi Murai u_short fcs; 180af57ed9fSAtsushi Murai 181dd7e2610SBrian Somers orglen = mbuf_Length(bp) + 2; /* add count of proto */ 182dd7e2610SBrian Somers mwp = mbuf_Alloc((orglen + 2) / 8 * 9 + 12, MB_HDLCOUT); 183af57ed9fSAtsushi Murai hp = wp = MBUF_CTOP(mwp); 184af57ed9fSAtsushi Murai cp = bufp; 185af57ed9fSAtsushi Murai *wp++ = *cp++ = orglen >> 8; 186af57ed9fSAtsushi Murai *wp++ = *cp++ = orglen & 0377; 187af57ed9fSAtsushi Murai *cp++ = proto >> 8; 188af57ed9fSAtsushi Murai *cp++ = proto & 0377; 189dd7e2610SBrian Somers mbuf_Read(bp, cp, orglen - 2); 190dd7e2610SBrian Somers fcs = hdlc_Fcs(INITFCS, bufp, 2 + orglen); 191af57ed9fSAtsushi Murai fcs = ~fcs; 192af57ed9fSAtsushi Murai 19303036ec7SBrian Somers len = compress(state, bufp + 2, wp, orglen); 194dd7e2610SBrian Somers log_Printf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len); 195f4768038SBrian Somers ccp->uncompout += orglen; 196af57ed9fSAtsushi Murai if (len < orglen) { 197af57ed9fSAtsushi Murai *hp |= 0x80; 198af57ed9fSAtsushi Murai wp += len; 199f4768038SBrian Somers ccp->compout += len; 200af57ed9fSAtsushi Murai } else { 20175240ed1SBrian Somers memcpy(wp, bufp + 2, orglen); 202af57ed9fSAtsushi Murai wp += orglen; 203f4768038SBrian Somers ccp->compout += orglen; 204af57ed9fSAtsushi Murai } 205af57ed9fSAtsushi Murai 206af57ed9fSAtsushi Murai *wp++ = fcs & 0377; 207af57ed9fSAtsushi Murai *wp++ = fcs >> 8; 208af57ed9fSAtsushi Murai mwp->cnt = wp - MBUF_CTOP(mwp); 209dd7e2610SBrian Somers hdlc_Output(l, PRI_NORMAL, ccp_Proto(ccp), mwp); 2100053cc58SBrian Somers return 1; 211af57ed9fSAtsushi Murai } 212af57ed9fSAtsushi Murai 2130053cc58SBrian Somers static struct mbuf * 21403036ec7SBrian Somers Pred1Input(void *v, struct ccp *ccp, u_short *proto, struct mbuf *bp) 215af57ed9fSAtsushi Murai { 21603036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 217af57ed9fSAtsushi Murai u_char *cp, *pp; 218af57ed9fSAtsushi Murai int len, olen, len1; 219af57ed9fSAtsushi Murai struct mbuf *wp; 220af57ed9fSAtsushi Murai u_char *bufp; 2210053cc58SBrian Somers u_short fcs; 222af57ed9fSAtsushi Murai 223dd7e2610SBrian Somers wp = mbuf_Alloc(MAX_MTU + 2, MB_IPIN); 224af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 225dd7e2610SBrian Somers olen = mbuf_Length(bp); 226af57ed9fSAtsushi Murai pp = bufp = MBUF_CTOP(wp); 227af57ed9fSAtsushi Murai *pp++ = *cp & 0177; 228af57ed9fSAtsushi Murai len = *cp++ << 8; 229af57ed9fSAtsushi Murai *pp++ = *cp; 230af57ed9fSAtsushi Murai len += *cp++; 231f4768038SBrian Somers ccp->uncompin += len & 0x7fff; 232af57ed9fSAtsushi Murai if (len & 0x8000) { 23303036ec7SBrian Somers len1 = decompress(state, cp, pp, olen - 4); 234f4768038SBrian Somers ccp->compin += olen; 235af57ed9fSAtsushi Murai len &= 0x7fff; 236af57ed9fSAtsushi Murai if (len != len1) { /* Error is detected. Send reset request */ 237a36ca3ccSBrian Somers log_Printf(LogCCP, "Pred1: Length error (got %d, not %d)\n", len1, len); 238a36ca3ccSBrian Somers fsm_Reopen(&ccp->fsm); 239dd7e2610SBrian Somers mbuf_Free(bp); 240dd7e2610SBrian Somers mbuf_Free(wp); 2410053cc58SBrian Somers return NULL; 242af57ed9fSAtsushi Murai } 243af57ed9fSAtsushi Murai cp += olen - 4; 244af57ed9fSAtsushi Murai pp += len1; 245af57ed9fSAtsushi Murai } else { 246f4768038SBrian Somers ccp->compin += len; 24703036ec7SBrian Somers SyncTable(state, cp, pp, len); 248af57ed9fSAtsushi Murai cp += len; 249af57ed9fSAtsushi Murai pp += len; 250af57ed9fSAtsushi Murai } 251af57ed9fSAtsushi Murai *pp++ = *cp++; /* CRC */ 252af57ed9fSAtsushi Murai *pp++ = *cp++; 253dd7e2610SBrian Somers fcs = hdlc_Fcs(INITFCS, bufp, wp->cnt = pp - bufp); 25476bd0c0aSDoug Rabson if (fcs != GOODFCS) 255dd7e2610SBrian Somers log_Printf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%s), len = 0x%x," 256927145beSBrian Somers " olen = 0x%x\n", fcs, (fcs == GOODFCS) ? "good" : "bad", 257927145beSBrian Somers len, olen); 258af57ed9fSAtsushi Murai if (fcs == GOODFCS) { 259af57ed9fSAtsushi Murai wp->offset += 2; /* skip length */ 260af57ed9fSAtsushi Murai wp->cnt -= 4; /* skip length & CRC */ 261af57ed9fSAtsushi Murai pp = MBUF_CTOP(wp); 2620053cc58SBrian Somers *proto = *pp++; 2630053cc58SBrian Somers if (*proto & 1) { 264af57ed9fSAtsushi Murai wp->offset++; 265af57ed9fSAtsushi Murai wp->cnt--; 266af57ed9fSAtsushi Murai } else { 267af57ed9fSAtsushi Murai wp->offset += 2; 268af57ed9fSAtsushi Murai wp->cnt -= 2; 2690053cc58SBrian Somers *proto = (*proto << 8) | *pp++; 270af57ed9fSAtsushi Murai } 271dd7e2610SBrian Somers mbuf_Free(bp); 2720053cc58SBrian Somers return wp; 273944f7098SBrian Somers } else { 274a36ca3ccSBrian Somers log_Printf(LogCCP, "%s: Bad CRC-16\n", ccp->fsm.link->name); 275a36ca3ccSBrian Somers fsm_Reopen(&ccp->fsm); 276dd7e2610SBrian Somers mbuf_Free(wp); 27776bd0c0aSDoug Rabson } 278dd7e2610SBrian Somers mbuf_Free(bp); 2790053cc58SBrian Somers return NULL; 280af57ed9fSAtsushi Murai } 2810053cc58SBrian Somers 2820053cc58SBrian Somers static void 28303036ec7SBrian Somers Pred1DictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf * bp) 2840053cc58SBrian Somers { 2850053cc58SBrian Somers } 2860053cc58SBrian Somers 2870053cc58SBrian Somers static const char * 2880053cc58SBrian Somers Pred1DispOpts(struct lcp_opt *o) 2890053cc58SBrian Somers { 2900053cc58SBrian Somers return NULL; 2910053cc58SBrian Somers } 2920053cc58SBrian Somers 2930053cc58SBrian Somers static void 29403036ec7SBrian Somers Pred1InitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg) 2950053cc58SBrian Somers { 2960053cc58SBrian Somers o->len = 2; 2970053cc58SBrian Somers } 2980053cc58SBrian Somers 2990053cc58SBrian Somers static int 30003036ec7SBrian Somers Pred1SetOptsOutput(struct lcp_opt *o) 3010053cc58SBrian Somers { 30203036ec7SBrian Somers if (o->len != 2) { 30303036ec7SBrian Somers o->len = 2; 3040053cc58SBrian Somers return MODE_NAK; 3050053cc58SBrian Somers } 3060053cc58SBrian Somers return MODE_ACK; 3070053cc58SBrian Somers } 3080053cc58SBrian Somers 30903036ec7SBrian Somers static int 31003036ec7SBrian Somers Pred1SetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg) 31103036ec7SBrian Somers { 31203036ec7SBrian Somers return Pred1SetOptsOutput(o); 31303036ec7SBrian Somers } 31403036ec7SBrian Somers 3150053cc58SBrian Somers const struct ccp_algorithm Pred1Algorithm = { 3160053cc58SBrian Somers TY_PRED1, 3171342caedSBrian Somers CCP_NEG_PRED1, 3180053cc58SBrian Somers Pred1DispOpts, 3190053cc58SBrian Somers { 32003036ec7SBrian Somers Pred1SetOptsInput, 3210053cc58SBrian Somers Pred1InitInput, 32203036ec7SBrian Somers Pred1Term, 3230053cc58SBrian Somers Pred1ResetInput, 3240053cc58SBrian Somers Pred1Input, 3250053cc58SBrian Somers Pred1DictSetup 3260053cc58SBrian Somers }, 3270053cc58SBrian Somers { 32803036ec7SBrian Somers Pred1InitOptsOutput, 32903036ec7SBrian Somers Pred1SetOptsOutput, 3300053cc58SBrian Somers Pred1InitOutput, 33103036ec7SBrian Somers Pred1Term, 3320053cc58SBrian Somers Pred1ResetOutput, 3330053cc58SBrian Somers Pred1Output 3340053cc58SBrian Somers }, 3350053cc58SBrian Somers }; 336