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 * 29615beb1fSBrian Somers * $Id: pred.c,v 1.23 1999/03/11 01:49:15 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--) { 93615beb1fSBrian Somers *dest++ = state->dict[state->hash] = *source; 94615beb1fSBrian Somers HASH(state, *source++); 95af57ed9fSAtsushi Murai } 96af57ed9fSAtsushi Murai } 97af57ed9fSAtsushi Murai 98af57ed9fSAtsushi Murai static int 9903036ec7SBrian Somers decompress(struct pred1_state *state, u_char *source, u_char *dest, int len) 100af57ed9fSAtsushi Murai { 101af57ed9fSAtsushi Murai int i, bitmask; 102af57ed9fSAtsushi Murai unsigned char flags, *orgdest; 103af57ed9fSAtsushi Murai 104af57ed9fSAtsushi Murai orgdest = dest; 105af57ed9fSAtsushi Murai while (len) { 106af57ed9fSAtsushi Murai flags = *source++; 107af57ed9fSAtsushi Murai len--; 108af57ed9fSAtsushi Murai for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) { 109af57ed9fSAtsushi Murai if (flags & bitmask) { 11003036ec7SBrian Somers *dest = state->dict[state->hash]; /* Guess correct */ 111af57ed9fSAtsushi Murai } else { 112af57ed9fSAtsushi Murai if (!len) 113af57ed9fSAtsushi Murai break; /* we seem to be really done -- cabo */ 11403036ec7SBrian Somers state->dict[state->hash] = *source; /* Guess wrong */ 115af57ed9fSAtsushi Murai *dest = *source++; /* Read from source */ 116af57ed9fSAtsushi Murai len--; 117af57ed9fSAtsushi Murai } 11803036ec7SBrian Somers HASH(state, *dest++); 119af57ed9fSAtsushi Murai } 120af57ed9fSAtsushi Murai } 121af57ed9fSAtsushi Murai return (dest - orgdest); 122af57ed9fSAtsushi Murai } 123af57ed9fSAtsushi Murai 1240053cc58SBrian Somers static void 12503036ec7SBrian Somers Pred1Term(void *v) 126af57ed9fSAtsushi Murai { 12703036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 12803036ec7SBrian Somers free(state); 129af57ed9fSAtsushi Murai } 130af57ed9fSAtsushi Murai 1310053cc58SBrian Somers static void 13203036ec7SBrian Somers Pred1ResetInput(void *v) 1330053cc58SBrian Somers { 13403036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 13503036ec7SBrian Somers state->hash = 0; 13603036ec7SBrian Somers memset(state->dict, '\0', sizeof state->dict); 137dd7e2610SBrian Somers log_Printf(LogCCP, "Predictor1: Input channel reset\n"); 1380053cc58SBrian Somers } 1390053cc58SBrian Somers 1400053cc58SBrian Somers static void 14103036ec7SBrian Somers Pred1ResetOutput(void *v) 1420053cc58SBrian Somers { 14303036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 14403036ec7SBrian Somers state->hash = 0; 14503036ec7SBrian Somers memset(state->dict, '\0', sizeof state->dict); 146dd7e2610SBrian Somers log_Printf(LogCCP, "Predictor1: Output channel reset\n"); 1470053cc58SBrian Somers } 1480053cc58SBrian Somers 14903036ec7SBrian Somers static void * 15003036ec7SBrian Somers Pred1InitInput(struct lcp_opt *o) 1510053cc58SBrian Somers { 15203036ec7SBrian Somers struct pred1_state *state; 15303036ec7SBrian Somers state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); 15403036ec7SBrian Somers if (state != NULL) 15503036ec7SBrian Somers Pred1ResetInput(state); 15603036ec7SBrian Somers return state; 15703036ec7SBrian Somers } 15803036ec7SBrian Somers 15903036ec7SBrian Somers static void * 16003036ec7SBrian Somers Pred1InitOutput(struct lcp_opt *o) 16103036ec7SBrian Somers { 16203036ec7SBrian Somers struct pred1_state *state; 16303036ec7SBrian Somers state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); 16403036ec7SBrian Somers if (state != NULL) 16503036ec7SBrian Somers Pred1ResetOutput(state); 16603036ec7SBrian Somers return state; 1670053cc58SBrian Somers } 1680053cc58SBrian Somers 1690053cc58SBrian Somers static int 17003036ec7SBrian Somers Pred1Output(void *v, struct ccp *ccp, struct link *l, int pri, u_short proto, 171f4768038SBrian Somers struct mbuf *bp) 1720053cc58SBrian Somers { 17303036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 174af57ed9fSAtsushi Murai struct mbuf *mwp; 175af57ed9fSAtsushi Murai u_char *cp, *wp, *hp; 176af57ed9fSAtsushi Murai int orglen, len; 177e979ce38SBrian Somers u_char bufp[MAX_MTU + 2]; 178af57ed9fSAtsushi Murai u_short fcs; 179af57ed9fSAtsushi Murai 180dd7e2610SBrian Somers orglen = mbuf_Length(bp) + 2; /* add count of proto */ 181dd7e2610SBrian Somers mwp = mbuf_Alloc((orglen + 2) / 8 * 9 + 12, MB_HDLCOUT); 182af57ed9fSAtsushi Murai hp = wp = MBUF_CTOP(mwp); 183af57ed9fSAtsushi Murai cp = bufp; 184af57ed9fSAtsushi Murai *wp++ = *cp++ = orglen >> 8; 185af57ed9fSAtsushi Murai *wp++ = *cp++ = orglen & 0377; 186af57ed9fSAtsushi Murai *cp++ = proto >> 8; 187af57ed9fSAtsushi Murai *cp++ = proto & 0377; 188dd7e2610SBrian Somers mbuf_Read(bp, cp, orglen - 2); 189dd7e2610SBrian Somers fcs = hdlc_Fcs(INITFCS, bufp, 2 + orglen); 190af57ed9fSAtsushi Murai fcs = ~fcs; 191af57ed9fSAtsushi Murai 19203036ec7SBrian Somers len = compress(state, bufp + 2, wp, orglen); 193dd7e2610SBrian Somers log_Printf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len); 194f4768038SBrian Somers ccp->uncompout += orglen; 195af57ed9fSAtsushi Murai if (len < orglen) { 196af57ed9fSAtsushi Murai *hp |= 0x80; 197af57ed9fSAtsushi Murai wp += len; 198f4768038SBrian Somers ccp->compout += len; 199af57ed9fSAtsushi Murai } else { 20075240ed1SBrian Somers memcpy(wp, bufp + 2, orglen); 201af57ed9fSAtsushi Murai wp += orglen; 202f4768038SBrian Somers ccp->compout += orglen; 203af57ed9fSAtsushi Murai } 204af57ed9fSAtsushi Murai 205af57ed9fSAtsushi Murai *wp++ = fcs & 0377; 206af57ed9fSAtsushi Murai *wp++ = fcs >> 8; 207af57ed9fSAtsushi Murai mwp->cnt = wp - MBUF_CTOP(mwp); 208dd7e2610SBrian Somers hdlc_Output(l, PRI_NORMAL, ccp_Proto(ccp), mwp); 2090053cc58SBrian Somers return 1; 210af57ed9fSAtsushi Murai } 211af57ed9fSAtsushi Murai 2120053cc58SBrian Somers static struct mbuf * 21303036ec7SBrian Somers Pred1Input(void *v, struct ccp *ccp, u_short *proto, struct mbuf *bp) 214af57ed9fSAtsushi Murai { 21503036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 216af57ed9fSAtsushi Murai u_char *cp, *pp; 217af57ed9fSAtsushi Murai int len, olen, len1; 218af57ed9fSAtsushi Murai struct mbuf *wp; 219af57ed9fSAtsushi Murai u_char *bufp; 2200053cc58SBrian Somers u_short fcs; 221af57ed9fSAtsushi Murai 222615beb1fSBrian Somers wp = mbuf_Alloc(MAX_MRU + 2, MB_IPIN); 223af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 224dd7e2610SBrian Somers olen = mbuf_Length(bp); 225af57ed9fSAtsushi Murai pp = bufp = MBUF_CTOP(wp); 226af57ed9fSAtsushi Murai *pp++ = *cp & 0177; 227af57ed9fSAtsushi Murai len = *cp++ << 8; 228af57ed9fSAtsushi Murai *pp++ = *cp; 229af57ed9fSAtsushi Murai len += *cp++; 230f4768038SBrian Somers ccp->uncompin += len & 0x7fff; 231af57ed9fSAtsushi Murai if (len & 0x8000) { 23203036ec7SBrian Somers len1 = decompress(state, cp, pp, olen - 4); 233f4768038SBrian Somers ccp->compin += olen; 234af57ed9fSAtsushi Murai len &= 0x7fff; 235af57ed9fSAtsushi Murai if (len != len1) { /* Error is detected. Send reset request */ 236a36ca3ccSBrian Somers log_Printf(LogCCP, "Pred1: Length error (got %d, not %d)\n", len1, len); 237a36ca3ccSBrian Somers fsm_Reopen(&ccp->fsm); 238dd7e2610SBrian Somers mbuf_Free(bp); 239dd7e2610SBrian Somers mbuf_Free(wp); 2400053cc58SBrian Somers return NULL; 241af57ed9fSAtsushi Murai } 242af57ed9fSAtsushi Murai cp += olen - 4; 243af57ed9fSAtsushi Murai pp += len1; 244615beb1fSBrian Somers } else if (len + 4 != olen) { 245615beb1fSBrian Somers log_Printf(LogCCP, "Pred1: Length error (got %d, not %d)\n", len + 4, olen); 246615beb1fSBrian Somers fsm_Reopen(&ccp->fsm); 247615beb1fSBrian Somers mbuf_Free(wp); 248615beb1fSBrian Somers mbuf_Free(bp); 249615beb1fSBrian Somers return NULL; 250af57ed9fSAtsushi Murai } else { 251f4768038SBrian Somers ccp->compin += len; 25203036ec7SBrian Somers SyncTable(state, cp, pp, len); 253af57ed9fSAtsushi Murai cp += len; 254af57ed9fSAtsushi Murai pp += len; 255af57ed9fSAtsushi Murai } 256af57ed9fSAtsushi Murai *pp++ = *cp++; /* CRC */ 257af57ed9fSAtsushi Murai *pp++ = *cp++; 258dd7e2610SBrian Somers fcs = hdlc_Fcs(INITFCS, bufp, wp->cnt = pp - bufp); 259af57ed9fSAtsushi Murai if (fcs == GOODFCS) { 260af57ed9fSAtsushi Murai wp->offset += 2; /* skip length */ 261af57ed9fSAtsushi Murai wp->cnt -= 4; /* skip length & CRC */ 262af57ed9fSAtsushi Murai pp = MBUF_CTOP(wp); 2630053cc58SBrian Somers *proto = *pp++; 2640053cc58SBrian Somers if (*proto & 1) { 265af57ed9fSAtsushi Murai wp->offset++; 266af57ed9fSAtsushi Murai wp->cnt--; 267af57ed9fSAtsushi Murai } else { 268af57ed9fSAtsushi Murai wp->offset += 2; 269af57ed9fSAtsushi Murai wp->cnt -= 2; 2700053cc58SBrian Somers *proto = (*proto << 8) | *pp++; 271af57ed9fSAtsushi Murai } 272dd7e2610SBrian Somers mbuf_Free(bp); 2730053cc58SBrian Somers return wp; 274944f7098SBrian Somers } else { 275615beb1fSBrian Somers const char *pre = *MBUF_CTOP(bp) & 0x80 ? "" : "un"; 276615beb1fSBrian Somers log_Printf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%scompressed), len = 0x%x," 277615beb1fSBrian Somers " olen = 0x%x\n", fcs, pre, len, olen); 278615beb1fSBrian Somers log_Printf(LogCCP, "%s: Bad %scompressed CRC-16\n", 279615beb1fSBrian Somers ccp->fsm.link->name, pre); 280a36ca3ccSBrian Somers fsm_Reopen(&ccp->fsm); 281dd7e2610SBrian Somers mbuf_Free(wp); 28276bd0c0aSDoug Rabson } 283dd7e2610SBrian Somers mbuf_Free(bp); 2840053cc58SBrian Somers return NULL; 285af57ed9fSAtsushi Murai } 2860053cc58SBrian Somers 2870053cc58SBrian Somers static void 28803036ec7SBrian Somers Pred1DictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf * bp) 2890053cc58SBrian Somers { 2900053cc58SBrian Somers } 2910053cc58SBrian Somers 2920053cc58SBrian Somers static const char * 2930053cc58SBrian Somers Pred1DispOpts(struct lcp_opt *o) 2940053cc58SBrian Somers { 2950053cc58SBrian Somers return NULL; 2960053cc58SBrian Somers } 2970053cc58SBrian Somers 2980053cc58SBrian Somers static void 29903036ec7SBrian Somers Pred1InitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg) 3000053cc58SBrian Somers { 3010053cc58SBrian Somers o->len = 2; 3020053cc58SBrian Somers } 3030053cc58SBrian Somers 3040053cc58SBrian Somers static int 30503036ec7SBrian Somers Pred1SetOptsOutput(struct lcp_opt *o) 3060053cc58SBrian Somers { 30703036ec7SBrian Somers if (o->len != 2) { 30803036ec7SBrian Somers o->len = 2; 3090053cc58SBrian Somers return MODE_NAK; 3100053cc58SBrian Somers } 3110053cc58SBrian Somers return MODE_ACK; 3120053cc58SBrian Somers } 3130053cc58SBrian Somers 31403036ec7SBrian Somers static int 31503036ec7SBrian Somers Pred1SetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg) 31603036ec7SBrian Somers { 31703036ec7SBrian Somers return Pred1SetOptsOutput(o); 31803036ec7SBrian Somers } 31903036ec7SBrian Somers 3200053cc58SBrian Somers const struct ccp_algorithm Pred1Algorithm = { 3210053cc58SBrian Somers TY_PRED1, 3221342caedSBrian Somers CCP_NEG_PRED1, 3230053cc58SBrian Somers Pred1DispOpts, 3240053cc58SBrian Somers { 32503036ec7SBrian Somers Pred1SetOptsInput, 3260053cc58SBrian Somers Pred1InitInput, 32703036ec7SBrian Somers Pred1Term, 3280053cc58SBrian Somers Pred1ResetInput, 3290053cc58SBrian Somers Pred1Input, 3300053cc58SBrian Somers Pred1DictSetup 3310053cc58SBrian Somers }, 3320053cc58SBrian Somers { 33303036ec7SBrian Somers Pred1InitOptsOutput, 33403036ec7SBrian Somers Pred1SetOptsOutput, 3350053cc58SBrian Somers Pred1InitOutput, 33603036ec7SBrian Somers Pred1Term, 3370053cc58SBrian Somers Pred1ResetOutput, 3380053cc58SBrian Somers Pred1Output 3390053cc58SBrian Somers }, 3400053cc58SBrian Somers }; 341