xref: /freebsd/usr.sbin/ppp/pred.c (revision f4768038f0d8815ef8b67f823150ddd10a48c165)
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