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 * 29c39934eaSBrian Somers * $Id$ 30af57ed9fSAtsushi Murai */ 31af57ed9fSAtsushi Murai 320053cc58SBrian Somers #include <sys/param.h> 3375240ed1SBrian Somers #include <netinet/in.h> 3475240ed1SBrian Somers 355106c671SBrian Somers #include <stdio.h> 360053cc58SBrian Somers #include <stdlib.h> 3775240ed1SBrian Somers #include <string.h> 3875240ed1SBrian Somers 39b6e82f33SBrian Somers #include "command.h" 4075240ed1SBrian Somers #include "mbuf.h" 4175240ed1SBrian Somers #include "log.h" 4275240ed1SBrian Somers #include "defs.h" 430053cc58SBrian Somers #include "loadalias.h" 440053cc58SBrian Somers #include "vars.h" 4575240ed1SBrian Somers #include "timer.h" 4675240ed1SBrian Somers #include "fsm.h" 4775240ed1SBrian Somers #include "hdlc.h" 4875240ed1SBrian Somers #include "lcpproto.h" 490053cc58SBrian Somers #include "lcp.h" 5075240ed1SBrian Somers #include "ccp.h" 5175240ed1SBrian Somers #include "pred.h" 5275240ed1SBrian Somers 53af57ed9fSAtsushi Murai /* The following hash code is the heart of the algorithm: 54af57ed9fSAtsushi Murai * It builds a sliding hash sum of the previous 3-and-a-bit characters 55af57ed9fSAtsushi Murai * which will be used to index the guess table. 56af57ed9fSAtsushi Murai * A better hash function would result in additional compression, 57af57ed9fSAtsushi Murai * at the expense of time. 58af57ed9fSAtsushi Murai */ 59274e766cSBrian Somers #define IHASH(x) do {iHash = (iHash << 4) ^ (x);} while(0) 60274e766cSBrian Somers #define OHASH(x) do {oHash = (oHash << 4) ^ (x);} while(0) 610053cc58SBrian Somers #define GUESS_TABLE_SIZE 65536 62af57ed9fSAtsushi Murai 63af57ed9fSAtsushi Murai static unsigned short int iHash, oHash; 640053cc58SBrian Somers static unsigned char *InputGuessTable; 650053cc58SBrian Somers static unsigned char *OutputGuessTable; 66af57ed9fSAtsushi Murai 67af57ed9fSAtsushi Murai static int 68944f7098SBrian Somers compress(u_char * source, u_char * dest, int len) 69af57ed9fSAtsushi Murai { 70af57ed9fSAtsushi Murai int i, bitmask; 71af57ed9fSAtsushi Murai unsigned char *flagdest, flags, *orgdest; 72af57ed9fSAtsushi Murai 73af57ed9fSAtsushi Murai orgdest = dest; 74af57ed9fSAtsushi Murai while (len) { 75944f7098SBrian Somers flagdest = dest++; 76944f7098SBrian Somers flags = 0; /* All guess wrong initially */ 77af57ed9fSAtsushi Murai for (bitmask = 1, i = 0; i < 8 && len; i++, bitmask <<= 1) { 78af57ed9fSAtsushi Murai if (OutputGuessTable[oHash] == *source) { 79af57ed9fSAtsushi Murai flags |= bitmask; /* Guess was right - don't output */ 80af57ed9fSAtsushi Murai } else { 81af57ed9fSAtsushi Murai OutputGuessTable[oHash] = *source; 82af57ed9fSAtsushi Murai *dest++ = *source; /* Guess wrong, output char */ 83af57ed9fSAtsushi Murai } 84944f7098SBrian Somers OHASH(*source++); 85944f7098SBrian Somers len--; 86af57ed9fSAtsushi Murai } 87af57ed9fSAtsushi Murai *flagdest = flags; 88af57ed9fSAtsushi Murai } 89af57ed9fSAtsushi Murai return (dest - orgdest); 90af57ed9fSAtsushi Murai } 91af57ed9fSAtsushi Murai 92af57ed9fSAtsushi Murai static void 93944f7098SBrian Somers SyncTable(u_char * source, u_char * dest, int len) 94af57ed9fSAtsushi Murai { 95af57ed9fSAtsushi Murai 96af57ed9fSAtsushi Murai while (len--) { 97af57ed9fSAtsushi Murai if (InputGuessTable[iHash] != *source) { 98af57ed9fSAtsushi Murai InputGuessTable[iHash] = *source; 99af57ed9fSAtsushi Murai } 100af57ed9fSAtsushi Murai IHASH(*dest++ = *source++); 101af57ed9fSAtsushi Murai } 102af57ed9fSAtsushi Murai } 103af57ed9fSAtsushi Murai 104af57ed9fSAtsushi Murai static int 105944f7098SBrian Somers decompress(u_char * source, u_char * dest, int len) 106af57ed9fSAtsushi Murai { 107af57ed9fSAtsushi Murai int i, bitmask; 108af57ed9fSAtsushi Murai unsigned char flags, *orgdest; 109af57ed9fSAtsushi Murai 110af57ed9fSAtsushi Murai orgdest = dest; 111af57ed9fSAtsushi Murai while (len) { 112af57ed9fSAtsushi Murai flags = *source++; 113af57ed9fSAtsushi Murai len--; 114af57ed9fSAtsushi Murai for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) { 115af57ed9fSAtsushi Murai if (flags & bitmask) { 116af57ed9fSAtsushi Murai *dest = InputGuessTable[iHash]; /* Guess correct */ 117af57ed9fSAtsushi Murai } else { 118af57ed9fSAtsushi Murai if (!len) 119af57ed9fSAtsushi Murai break; /* we seem to be really done -- cabo */ 120af57ed9fSAtsushi Murai InputGuessTable[iHash] = *source; /* Guess wrong */ 121af57ed9fSAtsushi Murai *dest = *source++; /* Read from source */ 122af57ed9fSAtsushi Murai len--; 123af57ed9fSAtsushi Murai } 124af57ed9fSAtsushi Murai IHASH(*dest++); 125af57ed9fSAtsushi Murai } 126af57ed9fSAtsushi Murai } 127af57ed9fSAtsushi Murai return (dest - orgdest); 128af57ed9fSAtsushi Murai } 129af57ed9fSAtsushi Murai 1300053cc58SBrian Somers static void 1310053cc58SBrian Somers Pred1TermInput(void) 132af57ed9fSAtsushi Murai { 1330053cc58SBrian Somers if (InputGuessTable != NULL) { 1340053cc58SBrian Somers free(InputGuessTable); 1350053cc58SBrian Somers InputGuessTable = NULL; 136af57ed9fSAtsushi Murai } 137af57ed9fSAtsushi Murai } 138af57ed9fSAtsushi Murai 1390053cc58SBrian Somers static void 1400053cc58SBrian Somers Pred1TermOutput(void) 1410053cc58SBrian Somers { 1420053cc58SBrian Somers if (OutputGuessTable != NULL) { 1430053cc58SBrian Somers free(OutputGuessTable); 1440053cc58SBrian Somers OutputGuessTable = NULL; 1450053cc58SBrian Somers } 1460053cc58SBrian Somers } 1470053cc58SBrian Somers 1480053cc58SBrian Somers static void 1490053cc58SBrian Somers Pred1ResetInput(void) 1500053cc58SBrian Somers { 1510053cc58SBrian Somers iHash = 0; 1520053cc58SBrian Somers memset(InputGuessTable, '\0', GUESS_TABLE_SIZE); 1530053cc58SBrian Somers LogPrintf(LogCCP, "Predictor1: Input channel reset\n"); 1540053cc58SBrian Somers } 1550053cc58SBrian Somers 1560053cc58SBrian Somers static void 1570053cc58SBrian Somers Pred1ResetOutput(void) 1580053cc58SBrian Somers { 1590053cc58SBrian Somers oHash = 0; 1600053cc58SBrian Somers memset(OutputGuessTable, '\0', GUESS_TABLE_SIZE); 1610053cc58SBrian Somers LogPrintf(LogCCP, "Predictor1: Output channel reset\n"); 1620053cc58SBrian Somers } 1630053cc58SBrian Somers 1640053cc58SBrian Somers static int 1650053cc58SBrian Somers Pred1InitInput(void) 1660053cc58SBrian Somers { 1670053cc58SBrian Somers if (InputGuessTable == NULL) 1680053cc58SBrian Somers if ((InputGuessTable = malloc(GUESS_TABLE_SIZE)) == NULL) 1690053cc58SBrian Somers return 0; 1700053cc58SBrian Somers Pred1ResetInput(); 1710053cc58SBrian Somers return 1; 1720053cc58SBrian Somers } 1730053cc58SBrian Somers 1740053cc58SBrian Somers static int 1750053cc58SBrian Somers Pred1InitOutput(void) 1760053cc58SBrian Somers { 1770053cc58SBrian Somers if (OutputGuessTable == NULL) 1780053cc58SBrian Somers if ((OutputGuessTable = malloc(GUESS_TABLE_SIZE)) == NULL) 1790053cc58SBrian Somers return 0; 1800053cc58SBrian Somers Pred1ResetOutput(); 1810053cc58SBrian Somers return 1; 1820053cc58SBrian Somers } 1830053cc58SBrian Somers 1840053cc58SBrian Somers static int 185274e766cSBrian Somers Pred1Output(int pri, u_short proto, struct mbuf * bp) 186af57ed9fSAtsushi Murai { 187af57ed9fSAtsushi Murai struct mbuf *mwp; 188af57ed9fSAtsushi Murai u_char *cp, *wp, *hp; 189af57ed9fSAtsushi Murai int orglen, len; 190e979ce38SBrian Somers u_char bufp[MAX_MTU + 2]; 191af57ed9fSAtsushi Murai u_short fcs; 192af57ed9fSAtsushi Murai 193af57ed9fSAtsushi Murai orglen = plength(bp) + 2; /* add count of proto */ 194af57ed9fSAtsushi Murai mwp = mballoc((orglen + 2) / 8 * 9 + 12, MB_HDLCOUT); 195af57ed9fSAtsushi Murai hp = wp = MBUF_CTOP(mwp); 196af57ed9fSAtsushi Murai cp = bufp; 197af57ed9fSAtsushi Murai *wp++ = *cp++ = orglen >> 8; 198af57ed9fSAtsushi Murai *wp++ = *cp++ = orglen & 0377; 199af57ed9fSAtsushi Murai *cp++ = proto >> 8; 200af57ed9fSAtsushi Murai *cp++ = proto & 0377; 201af57ed9fSAtsushi Murai mbread(bp, cp, orglen - 2); 202af57ed9fSAtsushi Murai fcs = HdlcFcs(INITFCS, bufp, 2 + orglen); 203af57ed9fSAtsushi Murai fcs = ~fcs; 204af57ed9fSAtsushi Murai 205af57ed9fSAtsushi Murai len = compress(bufp + 2, wp, orglen); 206927145beSBrian Somers LogPrintf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len); 2070053cc58SBrian Somers CcpInfo.uncompout += orglen; 208af57ed9fSAtsushi Murai if (len < orglen) { 209af57ed9fSAtsushi Murai *hp |= 0x80; 210af57ed9fSAtsushi Murai wp += len; 211af57ed9fSAtsushi Murai CcpInfo.compout += len; 212af57ed9fSAtsushi Murai } else { 21375240ed1SBrian Somers memcpy(wp, bufp + 2, orglen); 214af57ed9fSAtsushi Murai wp += orglen; 215af57ed9fSAtsushi Murai CcpInfo.compout += orglen; 216af57ed9fSAtsushi Murai } 217af57ed9fSAtsushi Murai 218af57ed9fSAtsushi Murai *wp++ = fcs & 0377; 219af57ed9fSAtsushi Murai *wp++ = fcs >> 8; 220af57ed9fSAtsushi Murai mwp->cnt = wp - MBUF_CTOP(mwp); 22176bd0c0aSDoug Rabson HdlcOutput(PRI_NORMAL, PROTO_COMPD, mwp); 2220053cc58SBrian Somers return 1; 223af57ed9fSAtsushi Murai } 224af57ed9fSAtsushi Murai 2250053cc58SBrian Somers static struct mbuf * 2260053cc58SBrian Somers Pred1Input(u_short *proto, struct mbuf *bp) 227af57ed9fSAtsushi Murai { 228af57ed9fSAtsushi Murai u_char *cp, *pp; 229af57ed9fSAtsushi Murai int len, olen, len1; 230af57ed9fSAtsushi Murai struct mbuf *wp; 231af57ed9fSAtsushi Murai u_char *bufp; 2320053cc58SBrian Somers u_short fcs; 233af57ed9fSAtsushi Murai 234e979ce38SBrian Somers wp = mballoc(MAX_MTU + 2, MB_IPIN); 235af57ed9fSAtsushi Murai cp = MBUF_CTOP(bp); 236af57ed9fSAtsushi Murai olen = plength(bp); 237af57ed9fSAtsushi Murai pp = bufp = MBUF_CTOP(wp); 238af57ed9fSAtsushi Murai *pp++ = *cp & 0177; 239af57ed9fSAtsushi Murai len = *cp++ << 8; 240af57ed9fSAtsushi Murai *pp++ = *cp; 241af57ed9fSAtsushi Murai len += *cp++; 2420053cc58SBrian Somers CcpInfo.uncompin += len & 0x7fff; 243af57ed9fSAtsushi Murai if (len & 0x8000) { 244af57ed9fSAtsushi Murai len1 = decompress(cp, pp, olen - 4); 245af57ed9fSAtsushi Murai CcpInfo.compin += olen; 246af57ed9fSAtsushi Murai len &= 0x7fff; 247af57ed9fSAtsushi Murai if (len != len1) { /* Error is detected. Send reset request */ 2480053cc58SBrian Somers LogPrintf(LogCCP, "Pred1: Length error\n"); 249af57ed9fSAtsushi Murai CcpSendResetReq(&CcpFsm); 250af57ed9fSAtsushi Murai pfree(bp); 25176bd0c0aSDoug Rabson pfree(wp); 2520053cc58SBrian Somers return NULL; 253af57ed9fSAtsushi Murai } 254af57ed9fSAtsushi Murai cp += olen - 4; 255af57ed9fSAtsushi Murai pp += len1; 256af57ed9fSAtsushi Murai } else { 257af57ed9fSAtsushi Murai CcpInfo.compin += len; 258af57ed9fSAtsushi Murai SyncTable(cp, pp, len); 259af57ed9fSAtsushi Murai cp += len; 260af57ed9fSAtsushi Murai pp += len; 261af57ed9fSAtsushi Murai } 262af57ed9fSAtsushi Murai *pp++ = *cp++; /* CRC */ 263af57ed9fSAtsushi Murai *pp++ = *cp++; 264af57ed9fSAtsushi Murai fcs = HdlcFcs(INITFCS, bufp, wp->cnt = pp - bufp); 26576bd0c0aSDoug Rabson if (fcs != GOODFCS) 266927145beSBrian Somers LogPrintf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%s), len = 0x%x," 267927145beSBrian Somers " olen = 0x%x\n", fcs, (fcs == GOODFCS) ? "good" : "bad", 268927145beSBrian Somers len, olen); 269af57ed9fSAtsushi Murai if (fcs == GOODFCS) { 270af57ed9fSAtsushi Murai wp->offset += 2; /* skip length */ 271af57ed9fSAtsushi Murai wp->cnt -= 4; /* skip length & CRC */ 272af57ed9fSAtsushi Murai pp = MBUF_CTOP(wp); 2730053cc58SBrian Somers *proto = *pp++; 2740053cc58SBrian Somers if (*proto & 1) { 275af57ed9fSAtsushi Murai wp->offset++; 276af57ed9fSAtsushi Murai wp->cnt--; 277af57ed9fSAtsushi Murai } else { 278af57ed9fSAtsushi Murai wp->offset += 2; 279af57ed9fSAtsushi Murai wp->cnt -= 2; 2800053cc58SBrian Somers *proto = (*proto << 8) | *pp++; 281af57ed9fSAtsushi Murai } 2820053cc58SBrian Somers return wp; 283944f7098SBrian Somers } else { 284927145beSBrian Somers LogDumpBp(LogHDLC, "Bad FCS", wp); 2855a927655SPoul-Henning Kamp CcpSendResetReq(&CcpFsm); 28676bd0c0aSDoug Rabson pfree(wp); 28776bd0c0aSDoug Rabson } 288af57ed9fSAtsushi Murai pfree(bp); 2890053cc58SBrian Somers return NULL; 290af57ed9fSAtsushi Murai } 2910053cc58SBrian Somers 2920053cc58SBrian Somers static void 2930053cc58SBrian Somers Pred1DictSetup(u_short proto, struct mbuf * bp) 2940053cc58SBrian Somers { 2950053cc58SBrian Somers } 2960053cc58SBrian Somers 2970053cc58SBrian Somers static const char * 2980053cc58SBrian Somers Pred1DispOpts(struct lcp_opt *o) 2990053cc58SBrian Somers { 3000053cc58SBrian Somers return NULL; 3010053cc58SBrian Somers } 3020053cc58SBrian Somers 3030053cc58SBrian Somers static void 3040053cc58SBrian Somers Pred1GetOpts(struct lcp_opt *o) 3050053cc58SBrian Somers { 3060053cc58SBrian Somers o->id = TY_PRED1; 3070053cc58SBrian Somers o->len = 2; 3080053cc58SBrian Somers } 3090053cc58SBrian Somers 3100053cc58SBrian Somers static int 3110053cc58SBrian Somers Pred1SetOpts(struct lcp_opt *o) 3120053cc58SBrian Somers { 3130053cc58SBrian Somers if (o->id != TY_PRED1 || o->len != 2) { 3140053cc58SBrian Somers Pred1GetOpts(o); 3150053cc58SBrian Somers return MODE_NAK; 3160053cc58SBrian Somers } 3170053cc58SBrian Somers return MODE_ACK; 3180053cc58SBrian Somers } 3190053cc58SBrian Somers 3200053cc58SBrian Somers const struct ccp_algorithm Pred1Algorithm = { 3210053cc58SBrian Somers TY_PRED1, 3220053cc58SBrian Somers ConfPred1, 3230053cc58SBrian Somers Pred1DispOpts, 3240053cc58SBrian Somers { 3250053cc58SBrian Somers Pred1GetOpts, 3260053cc58SBrian Somers Pred1SetOpts, 3270053cc58SBrian Somers Pred1InitInput, 3280053cc58SBrian Somers Pred1TermInput, 3290053cc58SBrian Somers Pred1ResetInput, 3300053cc58SBrian Somers Pred1Input, 3310053cc58SBrian Somers Pred1DictSetup 3320053cc58SBrian Somers }, 3330053cc58SBrian Somers { 3340053cc58SBrian Somers Pred1GetOpts, 3350053cc58SBrian Somers Pred1SetOpts, 3360053cc58SBrian Somers Pred1InitOutput, 3370053cc58SBrian Somers Pred1TermOutput, 3380053cc58SBrian Somers Pred1ResetOutput, 3390053cc58SBrian Somers Pred1Output 3400053cc58SBrian Somers }, 3410053cc58SBrian Somers }; 342