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 * 29f4768038SBrian Somers * $Id: pred.c,v 1.20.2.3 1998/01/31 02:48:29 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" 471ae349f5Scvs2svn #include "hdlc.h" 481ae349f5Scvs2svn #include "lcpproto.h" 491ae349f5Scvs2svn #include "lcp.h" 501ae349f5Scvs2svn #include "ccp.h" 518c07a7b2SBrian Somers #include "throughput.h" 528c07a7b2SBrian Somers #include "link.h" 531ae349f5Scvs2svn #include "pred.h" 541ae349f5Scvs2svn 551ae349f5Scvs2svn /* The following hash code is the heart of the algorithm: 561ae349f5Scvs2svn * It builds a sliding hash sum of the previous 3-and-a-bit characters 571ae349f5Scvs2svn * which will be used to index the guess table. 581ae349f5Scvs2svn * A better hash function would result in additional compression, 591ae349f5Scvs2svn * at the expense of time. 601ae349f5Scvs2svn */ 611ae349f5Scvs2svn #define IHASH(x) do {iHash = (iHash << 4) ^ (x);} while(0) 621ae349f5Scvs2svn #define OHASH(x) do {oHash = (oHash << 4) ^ (x);} while(0) 631ae349f5Scvs2svn #define GUESS_TABLE_SIZE 65536 641ae349f5Scvs2svn 651ae349f5Scvs2svn static unsigned short int iHash, oHash; 661ae349f5Scvs2svn static unsigned char *InputGuessTable; 671ae349f5Scvs2svn static unsigned char *OutputGuessTable; 681ae349f5Scvs2svn 691ae349f5Scvs2svn static int 701ae349f5Scvs2svn compress(u_char * source, u_char * dest, int len) 711ae349f5Scvs2svn { 721ae349f5Scvs2svn int i, bitmask; 731ae349f5Scvs2svn unsigned char *flagdest, flags, *orgdest; 741ae349f5Scvs2svn 751ae349f5Scvs2svn orgdest = dest; 761ae349f5Scvs2svn while (len) { 771ae349f5Scvs2svn flagdest = dest++; 781ae349f5Scvs2svn flags = 0; /* All guess wrong initially */ 791ae349f5Scvs2svn for (bitmask = 1, i = 0; i < 8 && len; i++, bitmask <<= 1) { 801ae349f5Scvs2svn if (OutputGuessTable[oHash] == *source) { 811ae349f5Scvs2svn flags |= bitmask; /* Guess was right - don't output */ 821ae349f5Scvs2svn } else { 831ae349f5Scvs2svn OutputGuessTable[oHash] = *source; 841ae349f5Scvs2svn *dest++ = *source; /* Guess wrong, output char */ 851ae349f5Scvs2svn } 861ae349f5Scvs2svn OHASH(*source++); 871ae349f5Scvs2svn len--; 881ae349f5Scvs2svn } 891ae349f5Scvs2svn *flagdest = flags; 901ae349f5Scvs2svn } 911ae349f5Scvs2svn return (dest - orgdest); 921ae349f5Scvs2svn } 931ae349f5Scvs2svn 941ae349f5Scvs2svn static void 951ae349f5Scvs2svn SyncTable(u_char * source, u_char * dest, int len) 961ae349f5Scvs2svn { 971ae349f5Scvs2svn 981ae349f5Scvs2svn while (len--) { 991ae349f5Scvs2svn if (InputGuessTable[iHash] != *source) { 1001ae349f5Scvs2svn InputGuessTable[iHash] = *source; 1011ae349f5Scvs2svn } 1021ae349f5Scvs2svn IHASH(*dest++ = *source++); 1031ae349f5Scvs2svn } 1041ae349f5Scvs2svn } 1051ae349f5Scvs2svn 1061ae349f5Scvs2svn static int 1071ae349f5Scvs2svn decompress(u_char * source, u_char * dest, int len) 1081ae349f5Scvs2svn { 1091ae349f5Scvs2svn int i, bitmask; 1101ae349f5Scvs2svn unsigned char flags, *orgdest; 1111ae349f5Scvs2svn 1121ae349f5Scvs2svn orgdest = dest; 1131ae349f5Scvs2svn while (len) { 1141ae349f5Scvs2svn flags = *source++; 1151ae349f5Scvs2svn len--; 1161ae349f5Scvs2svn for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) { 1171ae349f5Scvs2svn if (flags & bitmask) { 1181ae349f5Scvs2svn *dest = InputGuessTable[iHash]; /* Guess correct */ 1191ae349f5Scvs2svn } else { 1201ae349f5Scvs2svn if (!len) 1211ae349f5Scvs2svn break; /* we seem to be really done -- cabo */ 1221ae349f5Scvs2svn InputGuessTable[iHash] = *source; /* Guess wrong */ 1231ae349f5Scvs2svn *dest = *source++; /* Read from source */ 1241ae349f5Scvs2svn len--; 1251ae349f5Scvs2svn } 1261ae349f5Scvs2svn IHASH(*dest++); 1271ae349f5Scvs2svn } 1281ae349f5Scvs2svn } 1291ae349f5Scvs2svn return (dest - orgdest); 1301ae349f5Scvs2svn } 1311ae349f5Scvs2svn 1321ae349f5Scvs2svn static void 1331ae349f5Scvs2svn Pred1TermInput(void) 1341ae349f5Scvs2svn { 1351ae349f5Scvs2svn if (InputGuessTable != NULL) { 1361ae349f5Scvs2svn free(InputGuessTable); 1371ae349f5Scvs2svn InputGuessTable = NULL; 1381ae349f5Scvs2svn } 1391ae349f5Scvs2svn } 1401ae349f5Scvs2svn 1411ae349f5Scvs2svn static void 1421ae349f5Scvs2svn Pred1TermOutput(void) 1431ae349f5Scvs2svn { 1441ae349f5Scvs2svn if (OutputGuessTable != NULL) { 1451ae349f5Scvs2svn free(OutputGuessTable); 1461ae349f5Scvs2svn OutputGuessTable = NULL; 1471ae349f5Scvs2svn } 1481ae349f5Scvs2svn } 1491ae349f5Scvs2svn 1501ae349f5Scvs2svn static void 1511ae349f5Scvs2svn Pred1ResetInput(void) 1521ae349f5Scvs2svn { 1531ae349f5Scvs2svn iHash = 0; 1541ae349f5Scvs2svn memset(InputGuessTable, '\0', GUESS_TABLE_SIZE); 1551ae349f5Scvs2svn LogPrintf(LogCCP, "Predictor1: Input channel reset\n"); 1561ae349f5Scvs2svn } 1571ae349f5Scvs2svn 1581ae349f5Scvs2svn static void 1591ae349f5Scvs2svn Pred1ResetOutput(void) 1601ae349f5Scvs2svn { 1611ae349f5Scvs2svn oHash = 0; 1621ae349f5Scvs2svn memset(OutputGuessTable, '\0', GUESS_TABLE_SIZE); 1631ae349f5Scvs2svn LogPrintf(LogCCP, "Predictor1: Output channel reset\n"); 1641ae349f5Scvs2svn } 1651ae349f5Scvs2svn 1661ae349f5Scvs2svn static int 1671ae349f5Scvs2svn Pred1InitInput(void) 1681ae349f5Scvs2svn { 1691ae349f5Scvs2svn if (InputGuessTable == NULL) 1701ae349f5Scvs2svn if ((InputGuessTable = malloc(GUESS_TABLE_SIZE)) == NULL) 1711ae349f5Scvs2svn return 0; 1721ae349f5Scvs2svn Pred1ResetInput(); 1731ae349f5Scvs2svn return 1; 1741ae349f5Scvs2svn } 1751ae349f5Scvs2svn 1761ae349f5Scvs2svn static int 1771ae349f5Scvs2svn Pred1InitOutput(void) 1781ae349f5Scvs2svn { 1791ae349f5Scvs2svn if (OutputGuessTable == NULL) 1801ae349f5Scvs2svn if ((OutputGuessTable = malloc(GUESS_TABLE_SIZE)) == NULL) 1811ae349f5Scvs2svn return 0; 1821ae349f5Scvs2svn Pred1ResetOutput(); 1831ae349f5Scvs2svn return 1; 1841ae349f5Scvs2svn } 1851ae349f5Scvs2svn 1861ae349f5Scvs2svn static int 187f4768038SBrian Somers Pred1Output(struct ccp *ccp, struct link *l, int pri, u_short proto, 188f4768038SBrian Somers struct mbuf *bp) 1891ae349f5Scvs2svn { 1901ae349f5Scvs2svn struct mbuf *mwp; 1911ae349f5Scvs2svn u_char *cp, *wp, *hp; 1921ae349f5Scvs2svn int orglen, len; 1931ae349f5Scvs2svn u_char bufp[MAX_MTU + 2]; 1941ae349f5Scvs2svn u_short fcs; 1951ae349f5Scvs2svn 1961ae349f5Scvs2svn orglen = plength(bp) + 2; /* add count of proto */ 1971ae349f5Scvs2svn mwp = mballoc((orglen + 2) / 8 * 9 + 12, MB_HDLCOUT); 1981ae349f5Scvs2svn hp = wp = MBUF_CTOP(mwp); 1991ae349f5Scvs2svn cp = bufp; 2001ae349f5Scvs2svn *wp++ = *cp++ = orglen >> 8; 2011ae349f5Scvs2svn *wp++ = *cp++ = orglen & 0377; 2021ae349f5Scvs2svn *cp++ = proto >> 8; 2031ae349f5Scvs2svn *cp++ = proto & 0377; 2041ae349f5Scvs2svn mbread(bp, cp, orglen - 2); 2051ae349f5Scvs2svn fcs = HdlcFcs(INITFCS, bufp, 2 + orglen); 2061ae349f5Scvs2svn fcs = ~fcs; 2071ae349f5Scvs2svn 2081ae349f5Scvs2svn len = compress(bufp + 2, wp, orglen); 2091ae349f5Scvs2svn LogPrintf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len); 210f4768038SBrian Somers ccp->uncompout += orglen; 2111ae349f5Scvs2svn if (len < orglen) { 2121ae349f5Scvs2svn *hp |= 0x80; 2131ae349f5Scvs2svn wp += len; 214f4768038SBrian Somers ccp->compout += len; 2151ae349f5Scvs2svn } else { 2161ae349f5Scvs2svn memcpy(wp, bufp + 2, orglen); 2171ae349f5Scvs2svn wp += orglen; 218f4768038SBrian Somers ccp->compout += orglen; 2191ae349f5Scvs2svn } 2201ae349f5Scvs2svn 2211ae349f5Scvs2svn *wp++ = fcs & 0377; 2221ae349f5Scvs2svn *wp++ = fcs >> 8; 2231ae349f5Scvs2svn mwp->cnt = wp - MBUF_CTOP(mwp); 2248c07a7b2SBrian Somers HdlcOutput(l, PRI_NORMAL, PROTO_COMPD, mwp); 2251ae349f5Scvs2svn return 1; 2261ae349f5Scvs2svn } 2271ae349f5Scvs2svn 2281ae349f5Scvs2svn static struct mbuf * 229f4768038SBrian Somers Pred1Input(struct ccp *ccp, u_short *proto, struct mbuf *bp) 2301ae349f5Scvs2svn { 2311ae349f5Scvs2svn u_char *cp, *pp; 2321ae349f5Scvs2svn int len, olen, len1; 2331ae349f5Scvs2svn struct mbuf *wp; 2341ae349f5Scvs2svn u_char *bufp; 2351ae349f5Scvs2svn u_short fcs; 2361ae349f5Scvs2svn 2371ae349f5Scvs2svn wp = mballoc(MAX_MTU + 2, MB_IPIN); 2381ae349f5Scvs2svn cp = MBUF_CTOP(bp); 2391ae349f5Scvs2svn olen = plength(bp); 2401ae349f5Scvs2svn pp = bufp = MBUF_CTOP(wp); 2411ae349f5Scvs2svn *pp++ = *cp & 0177; 2421ae349f5Scvs2svn len = *cp++ << 8; 2431ae349f5Scvs2svn *pp++ = *cp; 2441ae349f5Scvs2svn len += *cp++; 245f4768038SBrian Somers ccp->uncompin += len & 0x7fff; 2461ae349f5Scvs2svn if (len & 0x8000) { 2471ae349f5Scvs2svn len1 = decompress(cp, pp, olen - 4); 248f4768038SBrian Somers ccp->compin += olen; 2491ae349f5Scvs2svn len &= 0x7fff; 2501ae349f5Scvs2svn if (len != len1) { /* Error is detected. Send reset request */ 2511ae349f5Scvs2svn LogPrintf(LogCCP, "Pred1: Length error\n"); 252f4768038SBrian Somers CcpSendResetReq(&ccp->fsm); 2531ae349f5Scvs2svn pfree(bp); 2541ae349f5Scvs2svn pfree(wp); 2551ae349f5Scvs2svn return NULL; 2561ae349f5Scvs2svn } 2571ae349f5Scvs2svn cp += olen - 4; 2581ae349f5Scvs2svn pp += len1; 2591ae349f5Scvs2svn } else { 260f4768038SBrian Somers ccp->compin += len; 2611ae349f5Scvs2svn SyncTable(cp, pp, len); 2621ae349f5Scvs2svn cp += len; 2631ae349f5Scvs2svn pp += len; 2641ae349f5Scvs2svn } 2651ae349f5Scvs2svn *pp++ = *cp++; /* CRC */ 2661ae349f5Scvs2svn *pp++ = *cp++; 2671ae349f5Scvs2svn fcs = HdlcFcs(INITFCS, bufp, wp->cnt = pp - bufp); 2681ae349f5Scvs2svn if (fcs != GOODFCS) 2691ae349f5Scvs2svn LogPrintf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%s), len = 0x%x," 2701ae349f5Scvs2svn " olen = 0x%x\n", fcs, (fcs == GOODFCS) ? "good" : "bad", 2711ae349f5Scvs2svn len, olen); 2721ae349f5Scvs2svn if (fcs == GOODFCS) { 2731ae349f5Scvs2svn wp->offset += 2; /* skip length */ 2741ae349f5Scvs2svn wp->cnt -= 4; /* skip length & CRC */ 2751ae349f5Scvs2svn pp = MBUF_CTOP(wp); 2761ae349f5Scvs2svn *proto = *pp++; 2771ae349f5Scvs2svn if (*proto & 1) { 2781ae349f5Scvs2svn wp->offset++; 2791ae349f5Scvs2svn wp->cnt--; 2801ae349f5Scvs2svn } else { 2811ae349f5Scvs2svn wp->offset += 2; 2821ae349f5Scvs2svn wp->cnt -= 2; 2831ae349f5Scvs2svn *proto = (*proto << 8) | *pp++; 2841ae349f5Scvs2svn } 2851ae349f5Scvs2svn pfree(bp); 2861ae349f5Scvs2svn return wp; 2871ae349f5Scvs2svn } else { 2881ae349f5Scvs2svn LogDumpBp(LogHDLC, "Bad FCS", wp); 289f4768038SBrian Somers CcpSendResetReq(&ccp->fsm); 2901ae349f5Scvs2svn pfree(wp); 2911ae349f5Scvs2svn } 2921ae349f5Scvs2svn pfree(bp); 2931ae349f5Scvs2svn return NULL; 2941ae349f5Scvs2svn } 2951ae349f5Scvs2svn 2961ae349f5Scvs2svn static void 297f4768038SBrian Somers Pred1DictSetup(struct ccp *ccp, u_short proto, struct mbuf * bp) 2981ae349f5Scvs2svn { 2991ae349f5Scvs2svn } 3001ae349f5Scvs2svn 3011ae349f5Scvs2svn static const char * 3021ae349f5Scvs2svn Pred1DispOpts(struct lcp_opt *o) 3031ae349f5Scvs2svn { 3041ae349f5Scvs2svn return NULL; 3051ae349f5Scvs2svn } 3061ae349f5Scvs2svn 3071ae349f5Scvs2svn static void 3081ae349f5Scvs2svn Pred1GetOpts(struct lcp_opt *o) 3091ae349f5Scvs2svn { 3101ae349f5Scvs2svn o->id = TY_PRED1; 3111ae349f5Scvs2svn o->len = 2; 3121ae349f5Scvs2svn } 3131ae349f5Scvs2svn 3141ae349f5Scvs2svn static int 3151ae349f5Scvs2svn Pred1SetOpts(struct lcp_opt *o) 3161ae349f5Scvs2svn { 3171ae349f5Scvs2svn if (o->id != TY_PRED1 || o->len != 2) { 3181ae349f5Scvs2svn Pred1GetOpts(o); 3191ae349f5Scvs2svn return MODE_NAK; 3201ae349f5Scvs2svn } 3211ae349f5Scvs2svn return MODE_ACK; 3221ae349f5Scvs2svn } 3231ae349f5Scvs2svn 3241ae349f5Scvs2svn const struct ccp_algorithm Pred1Algorithm = { 3251ae349f5Scvs2svn TY_PRED1, 3261ae349f5Scvs2svn ConfPred1, 3271ae349f5Scvs2svn Pred1DispOpts, 3281ae349f5Scvs2svn { 3291ae349f5Scvs2svn Pred1GetOpts, 3301ae349f5Scvs2svn Pred1SetOpts, 3311ae349f5Scvs2svn Pred1InitInput, 3321ae349f5Scvs2svn Pred1TermInput, 3331ae349f5Scvs2svn Pred1ResetInput, 3341ae349f5Scvs2svn Pred1Input, 3351ae349f5Scvs2svn Pred1DictSetup 3361ae349f5Scvs2svn }, 3371ae349f5Scvs2svn { 3381ae349f5Scvs2svn Pred1GetOpts, 3391ae349f5Scvs2svn Pred1SetOpts, 3401ae349f5Scvs2svn Pred1InitOutput, 3411ae349f5Scvs2svn Pred1TermOutput, 3421ae349f5Scvs2svn Pred1ResetOutput, 3431ae349f5Scvs2svn Pred1Output 3441ae349f5Scvs2svn }, 3451ae349f5Scvs2svn }; 346