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 * 2903036ec7SBrian Somers * $Id: pred.c,v 1.20.2.5 1998/03/13 00:44:22 brian Exp $ 301ae349f5Scvs2svn */ 311ae349f5Scvs2svn 321ae349f5Scvs2svn #include <sys/param.h> 331ae349f5Scvs2svn #include <netinet/in.h> 341ae349f5Scvs2svn 351ae349f5Scvs2svn #include <stdio.h> 361ae349f5Scvs2svn #include <stdlib.h> 371ae349f5Scvs2svn #include <string.h> 381ae349f5Scvs2svn 391ae349f5Scvs2svn #include "command.h" 401ae349f5Scvs2svn #include "mbuf.h" 411ae349f5Scvs2svn #include "log.h" 421ae349f5Scvs2svn #include "defs.h" 431ae349f5Scvs2svn #include "loadalias.h" 441ae349f5Scvs2svn #include "vars.h" 451ae349f5Scvs2svn #include "timer.h" 461ae349f5Scvs2svn #include "fsm.h" 47879ed6faSBrian Somers #include "lqr.h" 481ae349f5Scvs2svn #include "hdlc.h" 491ae349f5Scvs2svn #include "lcpproto.h" 501ae349f5Scvs2svn #include "lcp.h" 511ae349f5Scvs2svn #include "ccp.h" 528c07a7b2SBrian Somers #include "throughput.h" 538c07a7b2SBrian Somers #include "link.h" 541ae349f5Scvs2svn #include "pred.h" 551ae349f5Scvs2svn 561ae349f5Scvs2svn /* The following hash code is the heart of the algorithm: 571ae349f5Scvs2svn * It builds a sliding hash sum of the previous 3-and-a-bit characters 581ae349f5Scvs2svn * which will be used to index the guess table. 591ae349f5Scvs2svn * A better hash function would result in additional compression, 601ae349f5Scvs2svn * at the expense of time. 611ae349f5Scvs2svn */ 6203036ec7SBrian Somers #define HASH(state, x) state->hash = (state->hash << 4) ^ (x) 631ae349f5Scvs2svn #define GUESS_TABLE_SIZE 65536 641ae349f5Scvs2svn 6503036ec7SBrian Somers struct pred1_state { 6603036ec7SBrian Somers u_short hash; 6703036ec7SBrian Somers u_char dict[GUESS_TABLE_SIZE]; 6803036ec7SBrian Somers }; 691ae349f5Scvs2svn 701ae349f5Scvs2svn static int 7103036ec7SBrian Somers compress(struct pred1_state *state, u_char *source, u_char *dest, int len) 721ae349f5Scvs2svn { 731ae349f5Scvs2svn int i, bitmask; 741ae349f5Scvs2svn unsigned char *flagdest, flags, *orgdest; 751ae349f5Scvs2svn 761ae349f5Scvs2svn orgdest = dest; 771ae349f5Scvs2svn while (len) { 781ae349f5Scvs2svn flagdest = dest++; 791ae349f5Scvs2svn flags = 0; /* All guess wrong initially */ 801ae349f5Scvs2svn for (bitmask = 1, i = 0; i < 8 && len; i++, bitmask <<= 1) { 8103036ec7SBrian Somers if (state->dict[state->hash] == *source) { 821ae349f5Scvs2svn flags |= bitmask; /* Guess was right - don't output */ 831ae349f5Scvs2svn } else { 8403036ec7SBrian Somers state->dict[state->hash] = *source; 851ae349f5Scvs2svn *dest++ = *source; /* Guess wrong, output char */ 861ae349f5Scvs2svn } 8703036ec7SBrian Somers HASH(state, *source++); 881ae349f5Scvs2svn len--; 891ae349f5Scvs2svn } 901ae349f5Scvs2svn *flagdest = flags; 911ae349f5Scvs2svn } 921ae349f5Scvs2svn return (dest - orgdest); 931ae349f5Scvs2svn } 941ae349f5Scvs2svn 951ae349f5Scvs2svn static void 9603036ec7SBrian Somers SyncTable(struct pred1_state *state, u_char * source, u_char * dest, int len) 971ae349f5Scvs2svn { 981ae349f5Scvs2svn while (len--) { 9903036ec7SBrian Somers if (state->dict[state->hash] != *source) 10003036ec7SBrian Somers state->dict[state->hash] = *source; 10103036ec7SBrian Somers HASH(state, *dest++ = *source++); 1021ae349f5Scvs2svn } 1031ae349f5Scvs2svn } 1041ae349f5Scvs2svn 1051ae349f5Scvs2svn static int 10603036ec7SBrian Somers decompress(struct pred1_state *state, u_char * source, u_char * dest, int len) 1071ae349f5Scvs2svn { 1081ae349f5Scvs2svn int i, bitmask; 1091ae349f5Scvs2svn unsigned char flags, *orgdest; 1101ae349f5Scvs2svn 1111ae349f5Scvs2svn orgdest = dest; 1121ae349f5Scvs2svn while (len) { 1131ae349f5Scvs2svn flags = *source++; 1141ae349f5Scvs2svn len--; 1151ae349f5Scvs2svn for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) { 1161ae349f5Scvs2svn if (flags & bitmask) { 11703036ec7SBrian Somers *dest = state->dict[state->hash]; /* Guess correct */ 1181ae349f5Scvs2svn } else { 1191ae349f5Scvs2svn if (!len) 1201ae349f5Scvs2svn break; /* we seem to be really done -- cabo */ 12103036ec7SBrian Somers state->dict[state->hash] = *source; /* Guess wrong */ 1221ae349f5Scvs2svn *dest = *source++; /* Read from source */ 1231ae349f5Scvs2svn len--; 1241ae349f5Scvs2svn } 12503036ec7SBrian Somers HASH(state, *dest++); 1261ae349f5Scvs2svn } 1271ae349f5Scvs2svn } 1281ae349f5Scvs2svn return (dest - orgdest); 1291ae349f5Scvs2svn } 1301ae349f5Scvs2svn 1311ae349f5Scvs2svn static void 13203036ec7SBrian Somers Pred1Term(void *v) 1331ae349f5Scvs2svn { 13403036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 13503036ec7SBrian Somers free(state); 1361ae349f5Scvs2svn } 1371ae349f5Scvs2svn 1381ae349f5Scvs2svn static void 13903036ec7SBrian Somers Pred1ResetInput(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); 1441ae349f5Scvs2svn LogPrintf(LogCCP, "Predictor1: Input channel reset\n"); 1451ae349f5Scvs2svn } 1461ae349f5Scvs2svn 1471ae349f5Scvs2svn static void 14803036ec7SBrian Somers Pred1ResetOutput(void *v) 1491ae349f5Scvs2svn { 15003036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 15103036ec7SBrian Somers state->hash = 0; 15203036ec7SBrian Somers memset(state->dict, '\0', sizeof state->dict); 1531ae349f5Scvs2svn LogPrintf(LogCCP, "Predictor1: Output channel reset\n"); 1541ae349f5Scvs2svn } 1551ae349f5Scvs2svn 15603036ec7SBrian Somers static void * 15703036ec7SBrian Somers Pred1InitInput(struct lcp_opt *o) 1581ae349f5Scvs2svn { 15903036ec7SBrian Somers struct pred1_state *state; 16003036ec7SBrian Somers state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); 16103036ec7SBrian Somers if (state != NULL) 16203036ec7SBrian Somers Pred1ResetInput(state); 16303036ec7SBrian Somers return state; 16403036ec7SBrian Somers } 16503036ec7SBrian Somers 16603036ec7SBrian Somers static void * 16703036ec7SBrian Somers Pred1InitOutput(struct lcp_opt *o) 16803036ec7SBrian Somers { 16903036ec7SBrian Somers struct pred1_state *state; 17003036ec7SBrian Somers state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); 17103036ec7SBrian Somers if (state != NULL) 17203036ec7SBrian Somers Pred1ResetOutput(state); 17303036ec7SBrian Somers return state; 1741ae349f5Scvs2svn } 1751ae349f5Scvs2svn 1761ae349f5Scvs2svn static int 17703036ec7SBrian Somers Pred1Output(void *v, struct ccp *ccp, struct link *l, int pri, u_short proto, 178f4768038SBrian Somers struct mbuf *bp) 1791ae349f5Scvs2svn { 18003036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 1811ae349f5Scvs2svn struct mbuf *mwp; 1821ae349f5Scvs2svn u_char *cp, *wp, *hp; 1831ae349f5Scvs2svn int orglen, len; 1841ae349f5Scvs2svn u_char bufp[MAX_MTU + 2]; 1851ae349f5Scvs2svn u_short fcs; 1861ae349f5Scvs2svn 1871ae349f5Scvs2svn orglen = plength(bp) + 2; /* add count of proto */ 1881ae349f5Scvs2svn mwp = mballoc((orglen + 2) / 8 * 9 + 12, MB_HDLCOUT); 1891ae349f5Scvs2svn hp = wp = MBUF_CTOP(mwp); 1901ae349f5Scvs2svn cp = bufp; 1911ae349f5Scvs2svn *wp++ = *cp++ = orglen >> 8; 1921ae349f5Scvs2svn *wp++ = *cp++ = orglen & 0377; 1931ae349f5Scvs2svn *cp++ = proto >> 8; 1941ae349f5Scvs2svn *cp++ = proto & 0377; 1951ae349f5Scvs2svn mbread(bp, cp, orglen - 2); 1961ae349f5Scvs2svn fcs = HdlcFcs(INITFCS, bufp, 2 + orglen); 1971ae349f5Scvs2svn fcs = ~fcs; 1981ae349f5Scvs2svn 19903036ec7SBrian Somers len = compress(state, bufp + 2, wp, orglen); 2001ae349f5Scvs2svn LogPrintf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len); 201f4768038SBrian Somers ccp->uncompout += orglen; 2021ae349f5Scvs2svn if (len < orglen) { 2031ae349f5Scvs2svn *hp |= 0x80; 2041ae349f5Scvs2svn wp += len; 205f4768038SBrian Somers ccp->compout += len; 2061ae349f5Scvs2svn } else { 2071ae349f5Scvs2svn memcpy(wp, bufp + 2, orglen); 2081ae349f5Scvs2svn wp += orglen; 209f4768038SBrian Somers ccp->compout += orglen; 2101ae349f5Scvs2svn } 2111ae349f5Scvs2svn 2121ae349f5Scvs2svn *wp++ = fcs & 0377; 2131ae349f5Scvs2svn *wp++ = fcs >> 8; 2141ae349f5Scvs2svn mwp->cnt = wp - MBUF_CTOP(mwp); 2158c07a7b2SBrian Somers HdlcOutput(l, PRI_NORMAL, PROTO_COMPD, mwp); 2161ae349f5Scvs2svn return 1; 2171ae349f5Scvs2svn } 2181ae349f5Scvs2svn 2191ae349f5Scvs2svn static struct mbuf * 22003036ec7SBrian Somers Pred1Input(void *v, struct ccp *ccp, u_short *proto, struct mbuf *bp) 2211ae349f5Scvs2svn { 22203036ec7SBrian Somers struct pred1_state *state = (struct pred1_state *)v; 2231ae349f5Scvs2svn u_char *cp, *pp; 2241ae349f5Scvs2svn int len, olen, len1; 2251ae349f5Scvs2svn struct mbuf *wp; 2261ae349f5Scvs2svn u_char *bufp; 2271ae349f5Scvs2svn u_short fcs; 2281ae349f5Scvs2svn 2291ae349f5Scvs2svn wp = mballoc(MAX_MTU + 2, MB_IPIN); 2301ae349f5Scvs2svn cp = MBUF_CTOP(bp); 2311ae349f5Scvs2svn olen = plength(bp); 2321ae349f5Scvs2svn pp = bufp = MBUF_CTOP(wp); 2331ae349f5Scvs2svn *pp++ = *cp & 0177; 2341ae349f5Scvs2svn len = *cp++ << 8; 2351ae349f5Scvs2svn *pp++ = *cp; 2361ae349f5Scvs2svn len += *cp++; 237f4768038SBrian Somers ccp->uncompin += len & 0x7fff; 2381ae349f5Scvs2svn if (len & 0x8000) { 23903036ec7SBrian Somers len1 = decompress(state, cp, pp, olen - 4); 240f4768038SBrian Somers ccp->compin += olen; 2411ae349f5Scvs2svn len &= 0x7fff; 2421ae349f5Scvs2svn if (len != len1) { /* Error is detected. Send reset request */ 2431ae349f5Scvs2svn LogPrintf(LogCCP, "Pred1: Length error\n"); 244f4768038SBrian Somers CcpSendResetReq(&ccp->fsm); 2451ae349f5Scvs2svn pfree(bp); 2461ae349f5Scvs2svn pfree(wp); 2471ae349f5Scvs2svn return NULL; 2481ae349f5Scvs2svn } 2491ae349f5Scvs2svn cp += olen - 4; 2501ae349f5Scvs2svn pp += len1; 2511ae349f5Scvs2svn } else { 252f4768038SBrian Somers ccp->compin += len; 25303036ec7SBrian Somers SyncTable(state, cp, pp, len); 2541ae349f5Scvs2svn cp += len; 2551ae349f5Scvs2svn pp += len; 2561ae349f5Scvs2svn } 2571ae349f5Scvs2svn *pp++ = *cp++; /* CRC */ 2581ae349f5Scvs2svn *pp++ = *cp++; 2591ae349f5Scvs2svn fcs = HdlcFcs(INITFCS, bufp, wp->cnt = pp - bufp); 2601ae349f5Scvs2svn if (fcs != GOODFCS) 2611ae349f5Scvs2svn LogPrintf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%s), len = 0x%x," 2621ae349f5Scvs2svn " olen = 0x%x\n", fcs, (fcs == GOODFCS) ? "good" : "bad", 2631ae349f5Scvs2svn len, olen); 2641ae349f5Scvs2svn if (fcs == GOODFCS) { 2651ae349f5Scvs2svn wp->offset += 2; /* skip length */ 2661ae349f5Scvs2svn wp->cnt -= 4; /* skip length & CRC */ 2671ae349f5Scvs2svn pp = MBUF_CTOP(wp); 2681ae349f5Scvs2svn *proto = *pp++; 2691ae349f5Scvs2svn if (*proto & 1) { 2701ae349f5Scvs2svn wp->offset++; 2711ae349f5Scvs2svn wp->cnt--; 2721ae349f5Scvs2svn } else { 2731ae349f5Scvs2svn wp->offset += 2; 2741ae349f5Scvs2svn wp->cnt -= 2; 2751ae349f5Scvs2svn *proto = (*proto << 8) | *pp++; 2761ae349f5Scvs2svn } 2771ae349f5Scvs2svn pfree(bp); 2781ae349f5Scvs2svn return wp; 2791ae349f5Scvs2svn } else { 2801ae349f5Scvs2svn LogDumpBp(LogHDLC, "Bad FCS", wp); 281f4768038SBrian Somers CcpSendResetReq(&ccp->fsm); 2821ae349f5Scvs2svn pfree(wp); 2831ae349f5Scvs2svn } 2841ae349f5Scvs2svn pfree(bp); 2851ae349f5Scvs2svn return NULL; 2861ae349f5Scvs2svn } 2871ae349f5Scvs2svn 2881ae349f5Scvs2svn static void 28903036ec7SBrian Somers Pred1DictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf * bp) 2901ae349f5Scvs2svn { 2911ae349f5Scvs2svn } 2921ae349f5Scvs2svn 2931ae349f5Scvs2svn static const char * 2941ae349f5Scvs2svn Pred1DispOpts(struct lcp_opt *o) 2951ae349f5Scvs2svn { 2961ae349f5Scvs2svn return NULL; 2971ae349f5Scvs2svn } 2981ae349f5Scvs2svn 2991ae349f5Scvs2svn static void 30003036ec7SBrian Somers Pred1InitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg) 3011ae349f5Scvs2svn { 3021ae349f5Scvs2svn o->len = 2; 3031ae349f5Scvs2svn } 3041ae349f5Scvs2svn 3051ae349f5Scvs2svn static int 30603036ec7SBrian Somers Pred1SetOptsOutput(struct lcp_opt *o) 3071ae349f5Scvs2svn { 30803036ec7SBrian Somers if (o->len != 2) { 30903036ec7SBrian Somers o->len = 2; 3101ae349f5Scvs2svn return MODE_NAK; 3111ae349f5Scvs2svn } 3121ae349f5Scvs2svn return MODE_ACK; 3131ae349f5Scvs2svn } 3141ae349f5Scvs2svn 31503036ec7SBrian Somers static int 31603036ec7SBrian Somers Pred1SetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg) 31703036ec7SBrian Somers { 31803036ec7SBrian Somers return Pred1SetOptsOutput(o); 31903036ec7SBrian Somers } 32003036ec7SBrian Somers 3211ae349f5Scvs2svn const struct ccp_algorithm Pred1Algorithm = { 3221ae349f5Scvs2svn TY_PRED1, 3231ae349f5Scvs2svn ConfPred1, 3241ae349f5Scvs2svn Pred1DispOpts, 3251ae349f5Scvs2svn { 32603036ec7SBrian Somers Pred1SetOptsInput, 3271ae349f5Scvs2svn Pred1InitInput, 32803036ec7SBrian Somers Pred1Term, 3291ae349f5Scvs2svn Pred1ResetInput, 3301ae349f5Scvs2svn Pred1Input, 3311ae349f5Scvs2svn Pred1DictSetup 3321ae349f5Scvs2svn }, 3331ae349f5Scvs2svn { 33403036ec7SBrian Somers Pred1InitOptsOutput, 33503036ec7SBrian Somers Pred1SetOptsOutput, 3361ae349f5Scvs2svn Pred1InitOutput, 33703036ec7SBrian Somers Pred1Term, 3381ae349f5Scvs2svn Pred1ResetOutput, 3391ae349f5Scvs2svn Pred1Output 3401ae349f5Scvs2svn }, 3411ae349f5Scvs2svn }; 342