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 * 2997d92980SPeter Wemm * $FreeBSD$ 30af57ed9fSAtsushi Murai */ 31af57ed9fSAtsushi Murai 322764b86aSBrian Somers #include <sys/types.h> 3375240ed1SBrian Somers 340053cc58SBrian Somers #include <stdlib.h> 3575240ed1SBrian Somers #include <string.h> 365d9e6103SBrian Somers #include <termios.h> 3775240ed1SBrian Somers 3892b09558SBrian Somers #include "defs.h" 395d9e6103SBrian Somers #include "layer.h" 4075240ed1SBrian Somers #include "mbuf.h" 4175240ed1SBrian Somers #include "log.h" 4275240ed1SBrian Somers #include "timer.h" 4375240ed1SBrian Somers #include "fsm.h" 44879ed6faSBrian Somers #include "lqr.h" 4575240ed1SBrian Somers #include "hdlc.h" 460053cc58SBrian Somers #include "lcp.h" 4775240ed1SBrian Somers #include "ccp.h" 48a36ca3ccSBrian Somers #include "throughput.h" 49a36ca3ccSBrian Somers #include "link.h" 5075240ed1SBrian Somers #include "pred.h" 5175240ed1SBrian Somers 52af57ed9fSAtsushi Murai /* The following hash code is the heart of the algorithm: 53af57ed9fSAtsushi Murai * It builds a sliding hash sum of the previous 3-and-a-bit characters 54af57ed9fSAtsushi Murai * which will be used to index the guess table. 55af57ed9fSAtsushi Murai * A better hash function would result in additional compression, 56af57ed9fSAtsushi Murai * at the expense of time. 57af57ed9fSAtsushi Murai */ 5803036ec7SBrian Somers #define HASH(state, x) state->hash = (state->hash << 4) ^ (x) 590053cc58SBrian Somers #define GUESS_TABLE_SIZE 65536 60af57ed9fSAtsushi Murai 6103036ec7SBrian Somers struct pred1_state { 6203036ec7SBrian Somers u_short hash; 6303036ec7SBrian Somers u_char dict[GUESS_TABLE_SIZE]; 6403036ec7SBrian Somers }; 65af57ed9fSAtsushi Murai 66af57ed9fSAtsushi Murai static int 6703036ec7SBrian Somers compress(struct pred1_state *state, u_char *source, u_char *dest, int len) 68af57ed9fSAtsushi Murai { 69af57ed9fSAtsushi Murai int i, bitmask; 70af57ed9fSAtsushi Murai unsigned char *flagdest, flags, *orgdest; 71af57ed9fSAtsushi Murai 72af57ed9fSAtsushi Murai orgdest = dest; 73af57ed9fSAtsushi Murai while (len) { 74944f7098SBrian Somers flagdest = dest++; 75944f7098SBrian Somers flags = 0; /* All guess wrong initially */ 76af57ed9fSAtsushi Murai for (bitmask = 1, i = 0; i < 8 && len; i++, bitmask <<= 1) { 7703036ec7SBrian Somers if (state->dict[state->hash] == *source) { 78af57ed9fSAtsushi Murai flags |= bitmask; /* Guess was right - don't output */ 79af57ed9fSAtsushi Murai } else { 8003036ec7SBrian Somers state->dict[state->hash] = *source; 81af57ed9fSAtsushi Murai *dest++ = *source; /* Guess wrong, output char */ 82af57ed9fSAtsushi Murai } 8303036ec7SBrian Somers HASH(state, *source++); 84944f7098SBrian Somers len--; 85af57ed9fSAtsushi Murai } 86af57ed9fSAtsushi Murai *flagdest = flags; 87af57ed9fSAtsushi Murai } 88af57ed9fSAtsushi Murai return (dest - orgdest); 89af57ed9fSAtsushi Murai } 90af57ed9fSAtsushi Murai 91af57ed9fSAtsushi Murai static void 9203036ec7SBrian Somers SyncTable(struct pred1_state *state, u_char *source, u_char *dest, int len) 93af57ed9fSAtsushi Murai { 94af57ed9fSAtsushi Murai while (len--) { 95615beb1fSBrian Somers *dest++ = state->dict[state->hash] = *source; 96615beb1fSBrian Somers HASH(state, *source++); 97af57ed9fSAtsushi Murai } 98af57ed9fSAtsushi Murai } 99af57ed9fSAtsushi Murai 100af57ed9fSAtsushi Murai static int 10103036ec7SBrian Somers decompress(struct pred1_state *state, u_char *source, u_char *dest, int len) 102af57ed9fSAtsushi Murai { 103af57ed9fSAtsushi Murai int i, bitmask; 104af57ed9fSAtsushi Murai unsigned char flags, *orgdest; 105af57ed9fSAtsushi Murai 106af57ed9fSAtsushi Murai orgdest = dest; 107af57ed9fSAtsushi Murai while (len) { 108af57ed9fSAtsushi Murai flags = *source++; 109af57ed9fSAtsushi Murai len--; 110af57ed9fSAtsushi Murai for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) { 111af57ed9fSAtsushi Murai if (flags & bitmask) { 11203036ec7SBrian Somers *dest = state->dict[state->hash]; /* Guess correct */ 113af57ed9fSAtsushi Murai } else { 114af57ed9fSAtsushi Murai if (!len) 115af57ed9fSAtsushi Murai break; /* we seem to be really done -- cabo */ 11603036ec7SBrian Somers state->dict[state->hash] = *source; /* Guess wrong */ 117af57ed9fSAtsushi Murai *dest = *source++; /* Read from source */ 118af57ed9fSAtsushi Murai len--; 119af57ed9fSAtsushi Murai } 12003036ec7SBrian Somers HASH(state, *dest++); 121af57ed9fSAtsushi Murai } 122af57ed9fSAtsushi Murai } 123af57ed9fSAtsushi Murai return (dest - orgdest); 124af57ed9fSAtsushi Murai } 125af57ed9fSAtsushi Murai 1260053cc58SBrian Somers static void 12703036ec7SBrian Somers Pred1Term(void *v) 128af57ed9fSAtsushi Murai { 12903036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 13003036ec7SBrian Somers free(state); 131af57ed9fSAtsushi Murai } 132af57ed9fSAtsushi Murai 1330053cc58SBrian Somers static void 13403036ec7SBrian Somers Pred1ResetInput(void *v) 1350053cc58SBrian Somers { 13603036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 13703036ec7SBrian Somers state->hash = 0; 13803036ec7SBrian Somers memset(state->dict, '\0', sizeof state->dict); 139dd7e2610SBrian Somers log_Printf(LogCCP, "Predictor1: Input channel reset\n"); 1400053cc58SBrian Somers } 1410053cc58SBrian Somers 1426cf6ee76SBrian Somers static int 14303036ec7SBrian Somers Pred1ResetOutput(void *v) 1440053cc58SBrian Somers { 14503036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 14603036ec7SBrian Somers state->hash = 0; 14703036ec7SBrian Somers memset(state->dict, '\0', sizeof state->dict); 148dd7e2610SBrian Somers log_Printf(LogCCP, "Predictor1: Output channel reset\n"); 1496cf6ee76SBrian Somers 1506cf6ee76SBrian Somers return 1; /* Ask FSM to ACK */ 1510053cc58SBrian Somers } 1520053cc58SBrian Somers 15303036ec7SBrian Somers static void * 15403036ec7SBrian Somers Pred1InitInput(struct lcp_opt *o) 1550053cc58SBrian Somers { 15603036ec7SBrian Somers struct pred1_state *state; 15703036ec7SBrian Somers state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); 15803036ec7SBrian Somers if (state != NULL) 15903036ec7SBrian Somers Pred1ResetInput(state); 16003036ec7SBrian Somers return state; 16103036ec7SBrian Somers } 16203036ec7SBrian Somers 16303036ec7SBrian Somers static void * 16403036ec7SBrian Somers Pred1InitOutput(struct lcp_opt *o) 16503036ec7SBrian Somers { 16603036ec7SBrian Somers struct pred1_state *state; 16703036ec7SBrian Somers state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); 16803036ec7SBrian Somers if (state != NULL) 16903036ec7SBrian Somers Pred1ResetOutput(state); 17003036ec7SBrian Somers return state; 1710053cc58SBrian Somers } 1720053cc58SBrian Somers 1735d9e6103SBrian Somers static struct mbuf * 1745d9e6103SBrian Somers Pred1Output(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto, 175f4768038SBrian Somers struct mbuf *bp) 1760053cc58SBrian Somers { 17703036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 178af57ed9fSAtsushi Murai struct mbuf *mwp; 179af57ed9fSAtsushi Murai u_char *cp, *wp, *hp; 180af57ed9fSAtsushi Murai int orglen, len; 181e979ce38SBrian Somers u_char bufp[MAX_MTU + 2]; 182af57ed9fSAtsushi Murai u_short fcs; 183af57ed9fSAtsushi Murai 18426af0ae9SBrian Somers orglen = m_length(bp) + 2; /* add count of proto */ 18526af0ae9SBrian Somers mwp = m_get((orglen + 2) / 8 * 9 + 12, MB_CCPOUT); 186af57ed9fSAtsushi Murai hp = wp = MBUF_CTOP(mwp); 187af57ed9fSAtsushi Murai cp = bufp; 188af57ed9fSAtsushi Murai *wp++ = *cp++ = orglen >> 8; 189af57ed9fSAtsushi Murai *wp++ = *cp++ = orglen & 0377; 1905d9e6103SBrian Somers *cp++ = *proto >> 8; 1915d9e6103SBrian Somers *cp++ = *proto & 0377; 192dd7e2610SBrian Somers mbuf_Read(bp, cp, orglen - 2); 1935d9e6103SBrian Somers fcs = hdlc_Fcs(bufp, 2 + orglen); 194af57ed9fSAtsushi Murai fcs = ~fcs; 195af57ed9fSAtsushi Murai 19603036ec7SBrian Somers len = compress(state, bufp + 2, wp, orglen); 197dd7e2610SBrian Somers log_Printf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len); 198f4768038SBrian Somers ccp->uncompout += orglen; 199af57ed9fSAtsushi Murai if (len < orglen) { 200af57ed9fSAtsushi Murai *hp |= 0x80; 201af57ed9fSAtsushi Murai wp += len; 202f4768038SBrian Somers ccp->compout += len; 203af57ed9fSAtsushi Murai } else { 20475240ed1SBrian Somers memcpy(wp, bufp + 2, orglen); 205af57ed9fSAtsushi Murai wp += orglen; 206f4768038SBrian Somers ccp->compout += orglen; 207af57ed9fSAtsushi Murai } 208af57ed9fSAtsushi Murai 209af57ed9fSAtsushi Murai *wp++ = fcs & 0377; 210af57ed9fSAtsushi Murai *wp++ = fcs >> 8; 21126af0ae9SBrian Somers mwp->m_len = wp - MBUF_CTOP(mwp); 2125d9e6103SBrian Somers *proto = ccp_Proto(ccp); 2135d9e6103SBrian Somers return mwp; 214af57ed9fSAtsushi Murai } 215af57ed9fSAtsushi Murai 2160053cc58SBrian Somers static struct mbuf * 21703036ec7SBrian Somers Pred1Input(void *v, struct ccp *ccp, u_short *proto, struct mbuf *bp) 218af57ed9fSAtsushi Murai { 21903036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 220af57ed9fSAtsushi Murai u_char *cp, *pp; 221af57ed9fSAtsushi Murai int len, olen, len1; 222af57ed9fSAtsushi Murai struct mbuf *wp; 223af57ed9fSAtsushi Murai u_char *bufp; 2240053cc58SBrian Somers u_short fcs; 225af57ed9fSAtsushi Murai 22626af0ae9SBrian Somers wp = m_get(MAX_MRU + 2, MB_CCPIN); 227af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 22826af0ae9SBrian Somers olen = m_length(bp); 229af57ed9fSAtsushi Murai pp = bufp = MBUF_CTOP(wp); 230af57ed9fSAtsushi Murai *pp++ = *cp & 0177; 231af57ed9fSAtsushi Murai len = *cp++ << 8; 232af57ed9fSAtsushi Murai *pp++ = *cp; 233af57ed9fSAtsushi Murai len += *cp++; 234f4768038SBrian Somers ccp->uncompin += len & 0x7fff; 235af57ed9fSAtsushi Murai if (len & 0x8000) { 23603036ec7SBrian Somers len1 = decompress(state, cp, pp, olen - 4); 237f4768038SBrian Somers ccp->compin += olen; 238af57ed9fSAtsushi Murai len &= 0x7fff; 239af57ed9fSAtsushi Murai if (len != len1) { /* Error is detected. Send reset request */ 240a36ca3ccSBrian Somers log_Printf(LogCCP, "Pred1: Length error (got %d, not %d)\n", len1, len); 241a36ca3ccSBrian Somers fsm_Reopen(&ccp->fsm); 24226af0ae9SBrian Somers m_freem(bp); 24326af0ae9SBrian Somers m_freem(wp); 2440053cc58SBrian Somers return NULL; 245af57ed9fSAtsushi Murai } 246af57ed9fSAtsushi Murai cp += olen - 4; 247af57ed9fSAtsushi Murai pp += len1; 248615beb1fSBrian Somers } else if (len + 4 != olen) { 249615beb1fSBrian Somers log_Printf(LogCCP, "Pred1: Length error (got %d, not %d)\n", len + 4, olen); 250615beb1fSBrian Somers fsm_Reopen(&ccp->fsm); 25126af0ae9SBrian Somers m_freem(wp); 25226af0ae9SBrian Somers m_freem(bp); 253615beb1fSBrian Somers return NULL; 254af57ed9fSAtsushi Murai } else { 255f4768038SBrian Somers ccp->compin += len; 25603036ec7SBrian Somers SyncTable(state, cp, pp, len); 257af57ed9fSAtsushi Murai cp += len; 258af57ed9fSAtsushi Murai pp += len; 259af57ed9fSAtsushi Murai } 260af57ed9fSAtsushi Murai *pp++ = *cp++; /* CRC */ 261af57ed9fSAtsushi Murai *pp++ = *cp++; 26226af0ae9SBrian Somers fcs = hdlc_Fcs(bufp, wp->m_len = pp - bufp); 263af57ed9fSAtsushi Murai if (fcs == GOODFCS) { 26426af0ae9SBrian Somers wp->m_offset += 2; /* skip length */ 26526af0ae9SBrian Somers wp->m_len -= 4; /* skip length & CRC */ 266af57ed9fSAtsushi Murai pp = MBUF_CTOP(wp); 2670053cc58SBrian Somers *proto = *pp++; 2680053cc58SBrian Somers if (*proto & 1) { 26926af0ae9SBrian Somers wp->m_offset++; 27026af0ae9SBrian Somers wp->m_len--; 271af57ed9fSAtsushi Murai } else { 27226af0ae9SBrian Somers wp->m_offset += 2; 27326af0ae9SBrian Somers wp->m_len -= 2; 2740053cc58SBrian Somers *proto = (*proto << 8) | *pp++; 275af57ed9fSAtsushi Murai } 27626af0ae9SBrian Somers m_freem(bp); 2770053cc58SBrian Somers return wp; 278944f7098SBrian Somers } else { 279615beb1fSBrian Somers const char *pre = *MBUF_CTOP(bp) & 0x80 ? "" : "un"; 280615beb1fSBrian Somers log_Printf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%scompressed), len = 0x%x," 281615beb1fSBrian Somers " olen = 0x%x\n", fcs, pre, len, olen); 282615beb1fSBrian Somers log_Printf(LogCCP, "%s: Bad %scompressed CRC-16\n", 283615beb1fSBrian Somers ccp->fsm.link->name, pre); 284a36ca3ccSBrian Somers fsm_Reopen(&ccp->fsm); 28526af0ae9SBrian Somers m_freem(wp); 28676bd0c0aSDoug Rabson } 28726af0ae9SBrian Somers m_freem(bp); 2880053cc58SBrian Somers return NULL; 289af57ed9fSAtsushi Murai } 2900053cc58SBrian Somers 2910053cc58SBrian Somers static void 29203036ec7SBrian Somers Pred1DictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *bp) 2930053cc58SBrian Somers { 2940053cc58SBrian Somers } 2950053cc58SBrian Somers 2960053cc58SBrian Somers static const char * 2970053cc58SBrian Somers Pred1DispOpts(struct lcp_opt *o) 2980053cc58SBrian Somers { 2990053cc58SBrian Somers return NULL; 3000053cc58SBrian Somers } 3010053cc58SBrian Somers 3020053cc58SBrian Somers static void 30303036ec7SBrian Somers Pred1InitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg) 3040053cc58SBrian Somers { 3050053cc58SBrian Somers o->len = 2; 3060053cc58SBrian Somers } 3070053cc58SBrian Somers 3080053cc58SBrian Somers static int 3096cf6ee76SBrian Somers Pred1SetOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg) 3100053cc58SBrian Somers { 31103036ec7SBrian Somers if (o->len != 2) { 31203036ec7SBrian Somers o->len = 2; 3130053cc58SBrian Somers return MODE_NAK; 3140053cc58SBrian Somers } 3150053cc58SBrian Somers return MODE_ACK; 3160053cc58SBrian Somers } 3170053cc58SBrian Somers 31803036ec7SBrian Somers static int 31903036ec7SBrian Somers Pred1SetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg) 32003036ec7SBrian Somers { 3216cf6ee76SBrian Somers if (o->len != 2) { 3226cf6ee76SBrian Somers o->len = 2; 3236cf6ee76SBrian Somers return MODE_NAK; 3246cf6ee76SBrian Somers } 3256cf6ee76SBrian Somers return MODE_ACK; 32603036ec7SBrian Somers } 32703036ec7SBrian Somers 3280053cc58SBrian Somers const struct ccp_algorithm Pred1Algorithm = { 3290053cc58SBrian Somers TY_PRED1, 3301342caedSBrian Somers CCP_NEG_PRED1, 3310053cc58SBrian Somers Pred1DispOpts, 3326cf6ee76SBrian Somers ccp_DefaultUsable, 3336cf6ee76SBrian Somers ccp_DefaultRequired, 3340053cc58SBrian Somers { 33503036ec7SBrian Somers Pred1SetOptsInput, 3360053cc58SBrian Somers Pred1InitInput, 33703036ec7SBrian Somers Pred1Term, 3380053cc58SBrian Somers Pred1ResetInput, 3390053cc58SBrian Somers Pred1Input, 3400053cc58SBrian Somers Pred1DictSetup 3410053cc58SBrian Somers }, 3420053cc58SBrian Somers { 34303036ec7SBrian Somers Pred1InitOptsOutput, 34403036ec7SBrian Somers Pred1SetOptsOutput, 3450053cc58SBrian Somers Pred1InitOutput, 34603036ec7SBrian Somers Pred1Term, 3470053cc58SBrian Somers Pred1ResetOutput, 3480053cc58SBrian Somers Pred1Output 3490053cc58SBrian Somers }, 3500053cc58SBrian Somers }; 351