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