Index: head/usr.sbin/ppp/ccp.c =================================================================== --- head/usr.sbin/ppp/ccp.c (revision 44649) +++ head/usr.sbin/ppp/ccp.c (revision 44650) @@ -1,637 +1,637 @@ /* * PPP Compression Control Protocol (CCP) Module * * Written by Toshiharu OHNO (tony-o@iij.ad.jp) * * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the Internet Initiative Japan, Inc. The name of the * IIJ may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: ccp.c,v 1.42 1999/02/06 02:54:44 brian Exp $ + * $Id: ccp.c,v 1.43 1999/02/26 21:28:07 brian Exp $ * * TODO: * o Support other compression protocols */ #include #include #include #include #include #include #include #include #include "defs.h" #include "command.h" #include "mbuf.h" #include "log.h" #include "timer.h" #include "fsm.h" #include "lcpproto.h" #include "lcp.h" #include "ccp.h" #include "pred.h" #include "deflate.h" #include "throughput.h" #include "iplist.h" #include "slcompress.h" #include "lqr.h" #include "hdlc.h" #include "ipcp.h" #include "filter.h" #include "descriptor.h" #include "prompt.h" #include "link.h" #include "mp.h" #include "async.h" #include "physical.h" #ifndef NORADIUS #include "radius.h" #endif #include "bundle.h" static void CcpSendConfigReq(struct fsm *); static void CcpSentTerminateReq(struct fsm *); static void CcpSendTerminateAck(struct fsm *, u_char); static void CcpDecodeConfig(struct fsm *, u_char *, int, int, struct fsm_decode *); static void CcpLayerStart(struct fsm *); static void CcpLayerFinish(struct fsm *); static int CcpLayerUp(struct fsm *); static void CcpLayerDown(struct fsm *); static void CcpInitRestartCounter(struct fsm *, int); static void CcpRecvResetReq(struct fsm *); static void CcpRecvResetAck(struct fsm *, u_char); static struct fsm_callbacks ccp_Callbacks = { CcpLayerUp, CcpLayerDown, CcpLayerStart, CcpLayerFinish, CcpInitRestartCounter, CcpSendConfigReq, CcpSentTerminateReq, CcpSendTerminateAck, CcpDecodeConfig, CcpRecvResetReq, CcpRecvResetAck }; static const char *ccp_TimerNames[] = {"CCP restart", "CCP openmode", "CCP stopped"}; static char const *cftypes[] = { /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ "OUI", /* 0: OUI */ "PRED1", /* 1: Predictor type 1 */ "PRED2", /* 2: Predictor type 2 */ "PUDDLE", /* 3: Puddle Jumber */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "HWPPC", /* 16: Hewlett-Packard PPC */ "STAC", /* 17: Stac Electronics LZS (rfc1974) */ "MPPC", /* 18: Microsoft PPC (rfc2118) */ "GAND", /* 19: Gandalf FZA (rfc1993) */ "V42BIS", /* 20: ARG->DATA.42bis compression */ "BSD", /* 21: BSD LZW Compress */ "???", "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ /* 24: Deflate (according to pppd-2.3.*) */ "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ "DEFLATE", /* 26: Deflate (rfc1979) */ }; #define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) static const char * protoname(int proto) { if (proto < 0 || proto > NCFTYPES) return "none"; return cftypes[proto]; } /* We support these algorithms, and Req them in the given order */ static const struct ccp_algorithm *algorithm[] = { &DeflateAlgorithm, &Pred1Algorithm, &PppdDeflateAlgorithm }; #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) int ccp_ReportStatus(struct cmdargs const *arg) { struct link *l; struct ccp *ccp; l = command_ChooseLink(arg); ccp = &l->ccp; prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name, State2Nam(ccp->fsm.state)); prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n", protoname(ccp->my_proto), protoname(ccp->his_proto)); prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n", ccp->uncompout, ccp->compout, ccp->compin, ccp->uncompin); prompt_Printf(arg->prompt, "\n Defaults: "); prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config" " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout, ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s", ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s"); prompt_Printf(arg->prompt, " deflate windows: "); prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize); prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize); prompt_Printf(arg->prompt, " DEFLATE: %s\n", command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE])); prompt_Printf(arg->prompt, " PREDICTOR1: %s\n", command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1])); prompt_Printf(arg->prompt, " DEFLATE24: %s\n", command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24])); return 0; } void ccp_SetupCallbacks(struct ccp *ccp) { ccp->fsm.fn = &ccp_Callbacks; ccp->fsm.FsmTimer.name = ccp_TimerNames[0]; ccp->fsm.OpenTimer.name = ccp_TimerNames[1]; ccp->fsm.StoppedTimer.name = ccp_TimerNames[2]; } void ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l, const struct fsm_parent *parent) { /* Initialise ourselves */ fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP, bundle, l, parent, &ccp_Callbacks, ccp_TimerNames); ccp->cfg.deflate.in.winsize = 0; ccp->cfg.deflate.out.winsize = 15; ccp->cfg.fsm.timeout = DEF_FSMRETRY; ccp->cfg.fsm.maxreq = DEF_FSMTRIES; ccp->cfg.fsm.maxtrm = DEF_FSMTRIES; ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED; ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED; ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0; ccp_Setup(ccp); } void ccp_Setup(struct ccp *ccp) { /* Set ourselves up for a startup */ ccp->fsm.open_mode = 0; ccp->his_proto = ccp->my_proto = -1; ccp->reset_sent = ccp->last_reset = -1; ccp->in.algorithm = ccp->out.algorithm = -1; ccp->in.state = ccp->out.state = NULL; ccp->in.opt.id = -1; ccp->out.opt = NULL; ccp->his_reject = ccp->my_reject = 0; ccp->uncompout = ccp->compout = 0; ccp->uncompin = ccp->compin = 0; } static void CcpInitRestartCounter(struct fsm *fp, int what) { /* Set fsm timer load */ struct ccp *ccp = fsm2ccp(fp); fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS; switch (what) { case FSM_REQ_TIMER: fp->restart = ccp->cfg.fsm.maxreq; break; case FSM_TRM_TIMER: fp->restart = ccp->cfg.fsm.maxtrm; break; default: fp->restart = 1; break; } } static void CcpSendConfigReq(struct fsm *fp) { /* Send config REQ please */ struct ccp *ccp = fsm2ccp(fp); struct ccp_opt **o; u_char *cp, buff[100]; int f, alloc; cp = buff; o = &ccp->out.opt; alloc = ccp->his_reject == 0 && ccp->out.opt == NULL; ccp->my_proto = -1; ccp->out.algorithm = -1; for (f = 0; f < NALGORITHMS; f++) if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && !REJECTED(ccp, algorithm[f]->id)) { if (!alloc) for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next) if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f) break; if (alloc || *o == NULL) { *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt)); (*o)->val.id = algorithm[f]->id; (*o)->val.len = 2; (*o)->next = NULL; (*o)->algorithm = f; (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg); } if (cp + (*o)->val.len > buff + sizeof buff) { log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name); break; } memcpy(cp, &(*o)->val, (*o)->val.len); cp += (*o)->val.len; ccp->my_proto = (*o)->val.id; ccp->out.algorithm = f; if (alloc) o = &(*o)->next; } fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff); } void ccp_SendResetReq(struct fsm *fp) { /* We can't read our input - ask peer to reset */ struct ccp *ccp = fsm2ccp(fp); ccp->reset_sent = fp->reqid; ccp->last_reset = -1; fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0); } static void CcpSentTerminateReq(struct fsm *fp) { /* Term REQ just sent by FSM */ } static void CcpSendTerminateAck(struct fsm *fp, u_char id) { /* Send Term ACK please */ fsm_Output(fp, CODE_TERMACK, id, NULL, 0); } static void CcpRecvResetReq(struct fsm *fp) { /* Got a reset REQ, reset outgoing dictionary */ struct ccp *ccp = fsm2ccp(fp); if (ccp->out.state != NULL) (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state); } static void CcpLayerStart(struct fsm *fp) { /* We're about to start up ! */ struct ccp *ccp = fsm2ccp(fp); log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name); fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3; } static void CcpLayerDown(struct fsm *fp) { /* About to come down */ struct ccp *ccp = fsm2ccp(fp); struct ccp_opt *next; log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name); if (ccp->in.state != NULL) { (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state); ccp->in.state = NULL; ccp->in.algorithm = -1; } if (ccp->out.state != NULL) { (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state); ccp->out.state = NULL; ccp->out.algorithm = -1; } ccp->his_reject = ccp->my_reject = 0; while (ccp->out.opt) { next = ccp->out.opt->next; free(ccp->out.opt); ccp->out.opt = next; } ccp_Setup(ccp); } static void CcpLayerFinish(struct fsm *fp) { /* We're now down */ log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name); } /* * Called when CCP has reached the OPEN state */ static int CcpLayerUp(struct fsm *fp) { /* We're now up */ struct ccp *ccp = fsm2ccp(fp); log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name); if (ccp->in.state == NULL && ccp->in.algorithm >= 0 && ccp->in.algorithm < NALGORITHMS) { ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt); if (ccp->in.state == NULL) { log_Printf(LogERROR, "%s: %s (in) initialisation failure\n", fp->link->name, protoname(ccp->his_proto)); ccp->his_proto = ccp->my_proto = -1; fsm_Close(fp); return 0; } } if (ccp->out.state == NULL && ccp->out.algorithm >= 0 && ccp->out.algorithm < NALGORITHMS) { ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init) (&ccp->out.opt->val); if (ccp->out.state == NULL) { log_Printf(LogERROR, "%s: %s (out) initialisation failure\n", fp->link->name, protoname(ccp->my_proto)); ccp->his_proto = ccp->my_proto = -1; fsm_Close(fp); return 0; } } fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3; log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n", fp->link->name, protoname(ccp->my_proto), ccp->my_proto, protoname(ccp->his_proto), ccp->his_proto); return 1; } static void CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, struct fsm_decode *dec) { /* Deal with incoming data */ struct ccp *ccp = fsm2ccp(fp); int type, length; int f; const char *end; while (plen >= sizeof(struct fsmconfig)) { type = *cp; length = cp[1]; if (length == 0) { log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name); break; } if (length > sizeof(struct lcp_opt)) { length = sizeof(struct lcp_opt); log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n", fp->link->name, length); } for (f = NALGORITHMS-1; f > -1; f--) if (algorithm[f]->id == type) break; end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp); if (end == NULL) end = ""; if (type < NCFTYPES) log_Printf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end); else log_Printf(LogCCP, " ???[%d] %s\n", length, end); if (f == -1) { /* Don't understand that :-( */ if (mode_type == MODE_REQ) { ccp->my_reject |= (1 << type); memcpy(dec->rejend, cp, length); dec->rejend += length; } } else { struct ccp_opt *o; switch (mode_type) { case MODE_REQ: if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && ccp->in.algorithm == -1) { memcpy(&ccp->in.opt, cp, length); switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) { case MODE_REJ: memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len); dec->rejend += ccp->in.opt.len; break; case MODE_NAK: memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len); dec->nakend += ccp->in.opt.len; break; case MODE_ACK: memcpy(dec->ackend, cp, length); dec->ackend += length; ccp->his_proto = type; ccp->in.algorithm = f; /* This one'll do :-) */ break; } } else { memcpy(dec->rejend, cp, length); dec->rejend += length; } break; case MODE_NAK: for (o = ccp->out.opt; o != NULL; o = o->next) if (o->val.id == cp[0]) break; if (o == NULL) log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n", fp->link->name); else { memcpy(&o->val, cp, length); if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK) ccp->my_proto = algorithm[f]->id; else { ccp->his_reject |= (1 << type); ccp->my_proto = -1; } } break; case MODE_REJ: ccp->his_reject |= (1 << type); ccp->my_proto = -1; break; } } plen -= cp[1]; cp += cp[1]; } if (mode_type != MODE_NOP) { if (dec->rejend != dec->rej) { /* rejects are preferred */ dec->ackend = dec->ack; dec->nakend = dec->nak; if (ccp->in.state == NULL) { ccp->his_proto = -1; ccp->in.algorithm = -1; } } else if (dec->nakend != dec->nak) { /* then NAKs */ dec->ackend = dec->ack; if (ccp->in.state == NULL) { ccp->his_proto = -1; ccp->in.algorithm = -1; } } } } void ccp_Input(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp) { /* Got PROTO_CCP from link */ if (bundle_Phase(bundle) == PHASE_NETWORK) fsm_Input(&ccp->fsm, bp); else { if (bundle_Phase(bundle) < PHASE_NETWORK) log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n", ccp->fsm.link->name, bundle_PhaseName(bundle)); mbuf_Free(bp); } } static void CcpRecvResetAck(struct fsm *fp, u_char id) { /* Got a reset ACK, reset incoming dictionary */ struct ccp *ccp = fsm2ccp(fp); if (ccp->reset_sent != -1) { if (id != ccp->reset_sent) { - log_Printf(LogWARN, "CCP: %s: Incorrect ResetAck (id %d, not %d)" + log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)" " ignored\n", fp->link->name, id, ccp->reset_sent); return; } /* Whaddaya know - a correct reset ack */ } else if (id == ccp->last_reset) log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n", - fp->link->name); + fp->link->name); else { - log_Printf(LogWARN, "CCP: %s: Unexpected ResetAck (id %d) ignored\n", - fp->link->name, id); + log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n", + fp->link->name, id); return; } ccp->last_reset = ccp->reset_sent; ccp->reset_sent = -1; if (ccp->in.state != NULL) (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); } int ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto, struct mbuf *m) { /* * Compress outgoing data. It's already deemed to be suitable Network * Layer data. */ if (ccp->fsm.state == ST_OPENED && ccp->out.state != NULL) return (*algorithm[ccp->out.algorithm]->o.Write) (ccp->out.state, ccp, l, pri, proto, m); return 0; } struct mbuf * ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp) { /* * If proto isn't PROTO_[I]COMPD, we still want to pass it to the * decompression routines so that the dictionary's updated */ if (ccp->fsm.state == ST_OPENED) { if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { /* Decompress incoming data */ if (ccp->reset_sent != -1) /* Send another REQ and put the packet in the bit bucket */ fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0); else if (ccp->in.state != NULL) return (*algorithm[ccp->in.algorithm]->i.Read) (ccp->in.state, ccp, proto, bp); mbuf_Free(bp); bp = NULL; } else if (PROTO_COMPRESSIBLE(*proto) && ccp->in.state != NULL) /* Add incoming Network Layer traffic to our dictionary */ (*algorithm[ccp->in.algorithm]->i.DictSetup) (ccp->in.state, ccp, *proto, bp); } return bp; } u_short ccp_Proto(struct ccp *ccp) { return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? PROTO_COMPD : PROTO_ICOMPD; } int ccp_SetOpenMode(struct ccp *ccp) { int f; for (f = 0; f < CCP_NEG_TOTAL; f++) if (IsEnabled(ccp->cfg.neg[f])) { ccp->fsm.open_mode = 0; return 1; } ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED ? */ for (f = 0; f < CCP_NEG_TOTAL; f++) if (IsAccepted(ccp->cfg.neg[f])) return 1; return 0; /* No CCP at all */ } Index: head/usr.sbin/ppp/deflate.c =================================================================== --- head/usr.sbin/ppp/deflate.c (revision 44649) +++ head/usr.sbin/ppp/deflate.c (revision 44650) @@ -1,593 +1,593 @@ /*- * Copyright (c) 1997 Brian Somers * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: deflate.c,v 1.10 1998/06/16 19:40:36 brian Exp $ + * $Id: deflate.c,v 1.11 1998/08/07 18:42:48 brian Exp $ */ #include #include #include #include #include "defs.h" #include "mbuf.h" #include "log.h" #include "timer.h" #include "lqr.h" #include "hdlc.h" #include "fsm.h" #include "lcp.h" #include "ccp.h" #include "deflate.h" /* Our state */ struct deflate_state { u_short seqno; int uncomp_rec; int winsize; z_stream cx; }; static char garbage[10]; static u_char EMPTY_BLOCK[4] = { 0x00, 0x00, 0xff, 0xff }; #define DEFLATE_CHUNK_LEN 1024 /* Allocate mbufs this size */ static void DeflateResetOutput(void *v) { struct deflate_state *state = (struct deflate_state *)v; state->seqno = 0; state->uncomp_rec = 0; deflateReset(&state->cx); log_Printf(LogCCP, "Deflate: Output channel reset\n"); } static int DeflateOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short proto, struct mbuf *mp) { struct deflate_state *state = (struct deflate_state *)v; u_char *wp, *rp; int olen, ilen, len, res, flush; struct mbuf *mo_head, *mo, *mi_head, *mi; ilen = mbuf_Length(mp); log_Printf(LogDEBUG, "DeflateOutput: Proto %02x (%d bytes)\n", proto, ilen); log_DumpBp(LogDEBUG, "DeflateOutput: Compress packet:", mp); /* Stuff the protocol in front of the input */ mi_head = mi = mbuf_Alloc(2, MB_HDLCOUT); mi->next = mp; rp = MBUF_CTOP(mi); if (proto < 0x100) { /* Compress the protocol */ rp[0] = proto & 0377; mi->cnt = 1; } else { /* Don't compress the protocol */ rp[0] = proto >> 8; rp[1] = proto & 0377; mi->cnt = 2; } /* Allocate the initial output mbuf */ mo_head = mo = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_HDLCOUT); mo->cnt = 2; wp = MBUF_CTOP(mo); *wp++ = state->seqno >> 8; *wp++ = state->seqno & 0377; log_Printf(LogDEBUG, "DeflateOutput: Seq %d\n", state->seqno); state->seqno++; /* Set up the deflation context */ state->cx.next_out = wp; state->cx.avail_out = DEFLATE_CHUNK_LEN - 2; state->cx.next_in = MBUF_CTOP(mi); state->cx.avail_in = mi->cnt; flush = Z_NO_FLUSH; olen = 0; while (1) { if ((res = deflate(&state->cx, flush)) != Z_OK) { if (res == Z_STREAM_END) break; /* Done */ log_Printf(LogWARN, "DeflateOutput: deflate returned %d (%s)\n", res, state->cx.msg ? state->cx.msg : ""); mbuf_Free(mo_head); mbuf_FreeSeg(mi_head); state->seqno--; return 1; /* packet dropped */ } if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) break; if (state->cx.avail_in == 0 && mi->next != NULL) { mi = mi->next; state->cx.next_in = MBUF_CTOP(mi); state->cx.avail_in = mi->cnt; if (mi->next == NULL) flush = Z_SYNC_FLUSH; } if (state->cx.avail_out == 0) { mo->next = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_HDLCOUT); olen += (mo->cnt = DEFLATE_CHUNK_LEN); mo = mo->next; mo->cnt = 0; state->cx.next_out = MBUF_CTOP(mo); state->cx.avail_out = DEFLATE_CHUNK_LEN; } } olen += (mo->cnt = DEFLATE_CHUNK_LEN - state->cx.avail_out); olen -= 4; /* exclude the trailing EMPTY_BLOCK */ /* * If the output packet (including seqno and excluding the EMPTY_BLOCK) * got bigger, send the original. */ if (olen >= ilen) { mbuf_Free(mo_head); mbuf_FreeSeg(mi_head); log_Printf(LogDEBUG, "DeflateOutput: %d => %d: Uncompressible (0x%04x)\n", ilen, olen, proto); ccp->uncompout += ilen; ccp->compout += ilen; /* We measure this stuff too */ return 0; } mbuf_Free(mi_head); /* * Lose the last four bytes of our output. * XXX: We should probably assert that these are the same as the * contents of EMPTY_BLOCK. */ for (mo = mo_head, len = mo->cnt; len < olen; mo = mo->next, len += mo->cnt) ; mo->cnt -= len - olen; if (mo->next != NULL) { mbuf_Free(mo->next); mo->next = NULL; } ccp->uncompout += ilen; ccp->compout += olen; log_Printf(LogDEBUG, "DeflateOutput: %d => %d bytes, proto 0x%04x\n", ilen, olen, proto); hdlc_Output(l, PRI_NORMAL, ccp_Proto(ccp), mo_head); return 1; } static void DeflateResetInput(void *v) { struct deflate_state *state = (struct deflate_state *)v; state->seqno = 0; state->uncomp_rec = 0; inflateReset(&state->cx); log_Printf(LogCCP, "Deflate: Input channel reset\n"); } static struct mbuf * DeflateInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mi) { struct deflate_state *state = (struct deflate_state *)v; struct mbuf *mo, *mo_head, *mi_head; u_char *wp; int ilen, olen; int seq, flush, res, first; u_char hdr[2]; log_DumpBp(LogDEBUG, "DeflateInput: Decompress packet:", mi); mi_head = mi = mbuf_Read(mi, hdr, 2); ilen = 2; /* Check the sequence number. */ seq = (hdr[0] << 8) + hdr[1]; log_Printf(LogDEBUG, "DeflateInput: Seq %d\n", seq); if (seq != state->seqno) { if (seq <= state->uncomp_rec) /* * So the peer's started at zero again - fine ! If we're wrong, * inflate() will fail. This is better than getting into a loop * trying to get a ResetReq to a busy sender. */ state->seqno = seq; else { - log_Printf(LogWARN, "DeflateInput: Seq error: Got %d, expected %d\n", + log_Printf(LogCCP, "DeflateInput: Seq error: Got %d, expected %d\n", seq, state->seqno); mbuf_Free(mi_head); ccp_SendResetReq(&ccp->fsm); return NULL; } } state->seqno++; state->uncomp_rec = 0; /* Allocate an output mbuf */ mo_head = mo = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_IPIN); /* Our proto starts with 0 if it's compressed */ wp = MBUF_CTOP(mo); wp[0] = '\0'; /* * We set avail_out to 1 initially so we can look at the first * byte of the output and decide whether we have a compressed * proto field. */ state->cx.next_in = MBUF_CTOP(mi); state->cx.avail_in = mi->cnt; state->cx.next_out = wp + 1; state->cx.avail_out = 1; ilen += mi->cnt; flush = mi->next ? Z_NO_FLUSH : Z_SYNC_FLUSH; first = 1; olen = 0; while (1) { if ((res = inflate(&state->cx, flush)) != Z_OK) { if (res == Z_STREAM_END) break; /* Done */ - log_Printf(LogWARN, "DeflateInput: inflate returned %d (%s)\n", + log_Printf(LogCCP, "DeflateInput: inflate returned %d (%s)\n", res, state->cx.msg ? state->cx.msg : ""); mbuf_Free(mo_head); mbuf_Free(mi); ccp_SendResetReq(&ccp->fsm); return NULL; } if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) break; if (state->cx.avail_in == 0 && mi && (mi = mbuf_FreeSeg(mi)) != NULL) { /* underflow */ state->cx.next_in = MBUF_CTOP(mi); ilen += (state->cx.avail_in = mi->cnt); if (mi->next == NULL) flush = Z_SYNC_FLUSH; } if (state->cx.avail_out == 0) { /* overflow */ if (first) { if (!(wp[1] & 1)) { /* 2 byte proto, shuffle it back in output */ wp[0] = wp[1]; state->cx.next_out--; state->cx.avail_out = DEFLATE_CHUNK_LEN-1; } else state->cx.avail_out = DEFLATE_CHUNK_LEN-2; first = 0; } else { olen += (mo->cnt = DEFLATE_CHUNK_LEN); mo->next = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_IPIN); mo = mo->next; state->cx.next_out = MBUF_CTOP(mo); state->cx.avail_out = DEFLATE_CHUNK_LEN; } } } if (mi != NULL) mbuf_Free(mi); if (first) { - log_Printf(LogWARN, "DeflateInput: Length error\n"); + log_Printf(LogCCP, "DeflateInput: Length error\n"); mbuf_Free(mo_head); ccp_SendResetReq(&ccp->fsm); return NULL; } olen += (mo->cnt = DEFLATE_CHUNK_LEN - state->cx.avail_out); *proto = ((u_short)wp[0] << 8) | wp[1]; mo_head->offset += 2; mo_head->cnt -= 2; olen -= 2; ccp->compin += ilen; ccp->uncompin += olen; log_Printf(LogDEBUG, "DeflateInput: %d => %d bytes, proto 0x%04x\n", ilen, olen, *proto); /* * Simulate an EMPTY_BLOCK so that our dictionary stays in sync. * The peer will have silently removed this! */ state->cx.next_out = garbage; state->cx.avail_out = sizeof garbage; state->cx.next_in = EMPTY_BLOCK; state->cx.avail_in = sizeof EMPTY_BLOCK; inflate(&state->cx, Z_SYNC_FLUSH); return mo_head; } static void DeflateDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi) { struct deflate_state *state = (struct deflate_state *)v; int res, flush, expect_error; u_char *rp; struct mbuf *mi_head; short len; log_Printf(LogDEBUG, "DeflateDictSetup: Got seq %d\n", state->seqno); /* * Stuff an ``uncompressed data'' block header followed by the * protocol in front of the input */ mi_head = mbuf_Alloc(7, MB_HDLCOUT); mi_head->next = mi; len = mbuf_Length(mi); mi = mi_head; rp = MBUF_CTOP(mi); if (proto < 0x100) { /* Compress the protocol */ rp[5] = proto & 0377; mi->cnt = 6; len++; } else { /* Don't compress the protocol */ rp[5] = proto >> 8; rp[6] = proto & 0377; mi->cnt = 7; len += 2; } rp[0] = 0x80; /* BITS: 100xxxxx */ rp[1] = len & 0377; /* The length */ rp[2] = len >> 8; rp[3] = (~len) & 0377; /* One's compliment of the length */ rp[4] = (~len) >> 8; state->cx.next_in = rp; state->cx.avail_in = mi->cnt; state->cx.next_out = garbage; state->cx.avail_out = sizeof garbage; flush = Z_NO_FLUSH; expect_error = 0; while (1) { if ((res = inflate(&state->cx, flush)) != Z_OK) { if (res == Z_STREAM_END) break; /* Done */ if (expect_error && res == Z_BUF_ERROR) break; - log_Printf(LogERROR, "DeflateDictSetup: inflate returned %d (%s)\n", + log_Printf(LogCCP, "DeflateDictSetup: inflate returned %d (%s)\n", res, state->cx.msg ? state->cx.msg : ""); - log_Printf(LogERROR, "DeflateDictSetup: avail_in %d, avail_out %d\n", + log_Printf(LogCCP, "DeflateDictSetup: avail_in %d, avail_out %d\n", state->cx.avail_in, state->cx.avail_out); ccp_SendResetReq(&ccp->fsm); mbuf_FreeSeg(mi_head); /* lose our allocated ``head'' buf */ return; } if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) break; if (state->cx.avail_in == 0 && mi && (mi = mi->next) != NULL) { /* underflow */ state->cx.next_in = MBUF_CTOP(mi); state->cx.avail_in = mi->cnt; if (mi->next == NULL) flush = Z_SYNC_FLUSH; } if (state->cx.avail_out == 0) { if (state->cx.avail_in == 0) /* * This seems to be a bug in libz ! If inflate() finished * with 0 avail_in and 0 avail_out *and* this is the end of * our input *and* inflate() *has* actually written all the * output it's going to, it *doesn't* return Z_STREAM_END ! * When we subsequently call it with no more input, it gives * us Z_BUF_ERROR :-( It seems pretty safe to ignore this * error (the dictionary seems to stay in sync). In the worst * case, we'll drop the next compressed packet and do a * CcpReset() then. */ expect_error = 1; /* overflow */ state->cx.next_out = garbage; state->cx.avail_out = sizeof garbage; } } ccp->compin += len; ccp->uncompin += len; state->seqno++; state->uncomp_rec++; mbuf_FreeSeg(mi_head); /* lose our allocated ``head'' buf */ } static const char * DeflateDispOpts(struct lcp_opt *o) { static char disp[7]; /* Must be used immediately */ sprintf(disp, "win %d", (o->data[0]>>4) + 8); return disp; } static void DeflateInitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg) { o->len = 4; o->data[0] = ((cfg->deflate.out.winsize - 8) << 4) + 8; o->data[1] = '\0'; } static int DeflateSetOptsOutput(struct lcp_opt *o) { if (o->len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0') return MODE_REJ; if ((o->data[0] >> 4) + 8 > 15) { o->data[0] = ((15 - 8) << 4) + 8; return MODE_NAK; } return MODE_ACK; } static int DeflateSetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg) { int want; if (o->len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0') return MODE_REJ; want = (o->data[0] >> 4) + 8; if (cfg->deflate.in.winsize == 0) { if (want < 8 || want > 15) { o->data[0] = ((15 - 8) << 4) + 8; } } else if (want != cfg->deflate.in.winsize) { o->data[0] = ((cfg->deflate.in.winsize - 8) << 4) + 8; return MODE_NAK; } return MODE_ACK; } static void * DeflateInitInput(struct lcp_opt *o) { struct deflate_state *state; state = (struct deflate_state *)malloc(sizeof(struct deflate_state)); if (state != NULL) { state->winsize = (o->data[0] >> 4) + 8; state->cx.zalloc = NULL; state->cx.opaque = NULL; state->cx.zfree = NULL; state->cx.next_out = NULL; if (inflateInit2(&state->cx, -state->winsize) == Z_OK) DeflateResetInput(state); else { free(state); state = NULL; } } return state; } static void * DeflateInitOutput(struct lcp_opt *o) { struct deflate_state *state; state = (struct deflate_state *)malloc(sizeof(struct deflate_state)); if (state != NULL) { state->winsize = (o->data[0] >> 4) + 8; state->cx.zalloc = NULL; state->cx.opaque = NULL; state->cx.zfree = NULL; state->cx.next_in = NULL; if (deflateInit2(&state->cx, Z_DEFAULT_COMPRESSION, 8, -state->winsize, 8, Z_DEFAULT_STRATEGY) == Z_OK) DeflateResetOutput(state); else { free(state); state = NULL; } } return state; } static void DeflateTermInput(void *v) { struct deflate_state *state = (struct deflate_state *)v; inflateEnd(&state->cx); free(state); } static void DeflateTermOutput(void *v) { struct deflate_state *state = (struct deflate_state *)v; deflateEnd(&state->cx); free(state); } const struct ccp_algorithm PppdDeflateAlgorithm = { TY_PPPD_DEFLATE, /* pppd (wrongly) expects this ``type'' field */ CCP_NEG_DEFLATE24, DeflateDispOpts, { DeflateSetOptsInput, DeflateInitInput, DeflateTermInput, DeflateResetInput, DeflateInput, DeflateDictSetup }, { DeflateInitOptsOutput, DeflateSetOptsOutput, DeflateInitOutput, DeflateTermOutput, DeflateResetOutput, DeflateOutput }, }; const struct ccp_algorithm DeflateAlgorithm = { TY_DEFLATE, /* rfc 1979 */ CCP_NEG_DEFLATE, DeflateDispOpts, { DeflateSetOptsInput, DeflateInitInput, DeflateTermInput, DeflateResetInput, DeflateInput, DeflateDictSetup }, { DeflateInitOptsOutput, DeflateSetOptsOutput, DeflateInitOutput, DeflateTermOutput, DeflateResetOutput, DeflateOutput }, }; Index: head/usr.sbin/ppp/pred.c =================================================================== --- head/usr.sbin/ppp/pred.c (revision 44649) +++ head/usr.sbin/ppp/pred.c (revision 44650) @@ -1,333 +1,335 @@ /*- * Copyright (c) 1997 Brian Somers * Ian Donaldson * Carsten Bormann * Dave Rand / * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: pred.c,v 1.21 1998/05/21 21:47:53 brian Exp $ + * $Id: pred.c,v 1.22 1998/08/07 18:42:50 brian Exp $ */ #include #include #include #include "defs.h" #include "mbuf.h" #include "log.h" #include "timer.h" #include "fsm.h" #include "lqr.h" #include "hdlc.h" #include "lcp.h" #include "ccp.h" +#include "throughput.h" +#include "link.h" #include "pred.h" /* The following hash code is the heart of the algorithm: * It builds a sliding hash sum of the previous 3-and-a-bit characters * which will be used to index the guess table. * A better hash function would result in additional compression, * at the expense of time. */ #define HASH(state, x) state->hash = (state->hash << 4) ^ (x) #define GUESS_TABLE_SIZE 65536 struct pred1_state { u_short hash; u_char dict[GUESS_TABLE_SIZE]; }; static int compress(struct pred1_state *state, u_char *source, u_char *dest, int len) { int i, bitmask; unsigned char *flagdest, flags, *orgdest; orgdest = dest; while (len) { flagdest = dest++; flags = 0; /* All guess wrong initially */ for (bitmask = 1, i = 0; i < 8 && len; i++, bitmask <<= 1) { if (state->dict[state->hash] == *source) { flags |= bitmask; /* Guess was right - don't output */ } else { state->dict[state->hash] = *source; *dest++ = *source; /* Guess wrong, output char */ } HASH(state, *source++); len--; } *flagdest = flags; } return (dest - orgdest); } static void SyncTable(struct pred1_state *state, u_char * source, u_char * dest, int len) { while (len--) { if (state->dict[state->hash] != *source) state->dict[state->hash] = *source; HASH(state, *dest++ = *source++); } } static int decompress(struct pred1_state *state, u_char * source, u_char * dest, int len) { int i, bitmask; unsigned char flags, *orgdest; orgdest = dest; while (len) { flags = *source++; len--; for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) { if (flags & bitmask) { *dest = state->dict[state->hash]; /* Guess correct */ } else { if (!len) break; /* we seem to be really done -- cabo */ state->dict[state->hash] = *source; /* Guess wrong */ *dest = *source++; /* Read from source */ len--; } HASH(state, *dest++); } } return (dest - orgdest); } static void Pred1Term(void *v) { struct pred1_state *state = (struct pred1_state *)v; free(state); } static void Pred1ResetInput(void *v) { struct pred1_state *state = (struct pred1_state *)v; state->hash = 0; memset(state->dict, '\0', sizeof state->dict); log_Printf(LogCCP, "Predictor1: Input channel reset\n"); } static void Pred1ResetOutput(void *v) { struct pred1_state *state = (struct pred1_state *)v; state->hash = 0; memset(state->dict, '\0', sizeof state->dict); log_Printf(LogCCP, "Predictor1: Output channel reset\n"); } static void * Pred1InitInput(struct lcp_opt *o) { struct pred1_state *state; state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); if (state != NULL) Pred1ResetInput(state); return state; } static void * Pred1InitOutput(struct lcp_opt *o) { struct pred1_state *state; state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); if (state != NULL) Pred1ResetOutput(state); return state; } static int Pred1Output(void *v, struct ccp *ccp, struct link *l, int pri, u_short proto, struct mbuf *bp) { struct pred1_state *state = (struct pred1_state *)v; struct mbuf *mwp; u_char *cp, *wp, *hp; int orglen, len; u_char bufp[MAX_MTU + 2]; u_short fcs; orglen = mbuf_Length(bp) + 2; /* add count of proto */ mwp = mbuf_Alloc((orglen + 2) / 8 * 9 + 12, MB_HDLCOUT); hp = wp = MBUF_CTOP(mwp); cp = bufp; *wp++ = *cp++ = orglen >> 8; *wp++ = *cp++ = orglen & 0377; *cp++ = proto >> 8; *cp++ = proto & 0377; mbuf_Read(bp, cp, orglen - 2); fcs = hdlc_Fcs(INITFCS, bufp, 2 + orglen); fcs = ~fcs; len = compress(state, bufp + 2, wp, orglen); log_Printf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len); ccp->uncompout += orglen; if (len < orglen) { *hp |= 0x80; wp += len; ccp->compout += len; } else { memcpy(wp, bufp + 2, orglen); wp += orglen; ccp->compout += orglen; } *wp++ = fcs & 0377; *wp++ = fcs >> 8; mwp->cnt = wp - MBUF_CTOP(mwp); hdlc_Output(l, PRI_NORMAL, ccp_Proto(ccp), mwp); return 1; } static struct mbuf * Pred1Input(void *v, struct ccp *ccp, u_short *proto, struct mbuf *bp) { struct pred1_state *state = (struct pred1_state *)v; u_char *cp, *pp; int len, olen, len1; struct mbuf *wp; u_char *bufp; u_short fcs; wp = mbuf_Alloc(MAX_MTU + 2, MB_IPIN); cp = MBUF_CTOP(bp); olen = mbuf_Length(bp); pp = bufp = MBUF_CTOP(wp); *pp++ = *cp & 0177; len = *cp++ << 8; *pp++ = *cp; len += *cp++; ccp->uncompin += len & 0x7fff; if (len & 0x8000) { len1 = decompress(state, cp, pp, olen - 4); ccp->compin += olen; len &= 0x7fff; if (len != len1) { /* Error is detected. Send reset request */ - log_Printf(LogCCP, "Pred1: Length error\n"); - ccp_SendResetReq(&ccp->fsm); + log_Printf(LogCCP, "Pred1: Length error (got %d, not %d)\n", len1, len); + fsm_Reopen(&ccp->fsm); mbuf_Free(bp); mbuf_Free(wp); return NULL; } cp += olen - 4; pp += len1; } else { ccp->compin += len; SyncTable(state, cp, pp, len); cp += len; pp += len; } *pp++ = *cp++; /* CRC */ *pp++ = *cp++; fcs = hdlc_Fcs(INITFCS, bufp, wp->cnt = pp - bufp); if (fcs != GOODFCS) log_Printf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%s), len = 0x%x," " olen = 0x%x\n", fcs, (fcs == GOODFCS) ? "good" : "bad", len, olen); if (fcs == GOODFCS) { wp->offset += 2; /* skip length */ wp->cnt -= 4; /* skip length & CRC */ pp = MBUF_CTOP(wp); *proto = *pp++; if (*proto & 1) { wp->offset++; wp->cnt--; } else { wp->offset += 2; wp->cnt -= 2; *proto = (*proto << 8) | *pp++; } mbuf_Free(bp); return wp; } else { - log_DumpBp(LogHDLC, "Bad FCS", wp); - ccp_SendResetReq(&ccp->fsm); + log_Printf(LogCCP, "%s: Bad CRC-16\n", ccp->fsm.link->name); + fsm_Reopen(&ccp->fsm); mbuf_Free(wp); } mbuf_Free(bp); return NULL; } static void Pred1DictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf * bp) { } static const char * Pred1DispOpts(struct lcp_opt *o) { return NULL; } static void Pred1InitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg) { o->len = 2; } static int Pred1SetOptsOutput(struct lcp_opt *o) { if (o->len != 2) { o->len = 2; return MODE_NAK; } return MODE_ACK; } static int Pred1SetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg) { return Pred1SetOptsOutput(o); } const struct ccp_algorithm Pred1Algorithm = { TY_PRED1, CCP_NEG_PRED1, Pred1DispOpts, { Pred1SetOptsInput, Pred1InitInput, Pred1Term, Pred1ResetInput, Pred1Input, Pred1DictSetup }, { Pred1InitOptsOutput, Pred1SetOptsOutput, Pred1InitOutput, Pred1Term, Pred1ResetOutput, Pred1Output }, };