ccp.c revision 32381
16059Samurai/* 26059Samurai * PPP Compression Control Protocol (CCP) Module 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan, Inc. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 198857Srgrimes * 2032381Sbrian * $Id: ccp.c,v 1.27 1998/01/04 20:25:39 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai * o Support other compression protocols 246059Samurai */ 2530715Sbrian#include <sys/param.h> 2630715Sbrian#include <netinet/in.h> 2730715Sbrian 2830715Sbrian#include <stdio.h> 2930715Sbrian#include <string.h> 3030715Sbrian 3131343Sbrian#include "command.h" 3230715Sbrian#include "mbuf.h" 3330715Sbrian#include "log.h" 3430715Sbrian#include "defs.h" 3530715Sbrian#include "timer.h" 366059Samurai#include "fsm.h" 376059Samurai#include "lcpproto.h" 386059Samurai#include "lcp.h" 396059Samurai#include "ccp.h" 406059Samurai#include "phase.h" 4126142Sbrian#include "loadalias.h" 426059Samurai#include "vars.h" 4313389Sphk#include "pred.h" 4431514Sbrian#include "deflate.h" 458857Srgrimes 4632381Sbrianstruct ccpstate CcpInfo = { -1, -1, -1, -1 }; 476059Samurai 4826516Sbrianstatic void CcpSendConfigReq(struct fsm *); 4930715Sbrianstatic void CcpSendTerminateReq(struct fsm *); 5030715Sbrianstatic void CcpSendTerminateAck(struct fsm *); 5130715Sbrianstatic void CcpDecodeConfig(u_char *, int, int); 5226516Sbrianstatic void CcpLayerStart(struct fsm *); 5326516Sbrianstatic void CcpLayerFinish(struct fsm *); 5426516Sbrianstatic void CcpLayerUp(struct fsm *); 5526516Sbrianstatic void CcpLayerDown(struct fsm *); 5626516Sbrianstatic void CcpInitRestartCounter(struct fsm *); 576059Samurai 586059Samuraistruct fsm CcpFsm = { 596059Samurai "CCP", 606059Samurai PROTO_CCP, 616059Samurai CCP_MAXCODE, 626059Samurai OPEN_ACTIVE, 636059Samurai ST_INITIAL, 646059Samurai 0, 0, 0, 656059Samurai 0, 6628679Sbrian {0, 0, 0, NULL, NULL, NULL}, 6728679Sbrian {0, 0, 0, NULL, NULL, NULL}, 6828461Sbrian LogCCP, 696059Samurai 706059Samurai CcpLayerUp, 716059Samurai CcpLayerDown, 726059Samurai CcpLayerStart, 736059Samurai CcpLayerFinish, 746059Samurai CcpInitRestartCounter, 756059Samurai CcpSendConfigReq, 766059Samurai CcpSendTerminateReq, 776059Samurai CcpSendTerminateAck, 786059Samurai CcpDecodeConfig, 796059Samurai}; 806059Samurai 8113760Sphkstatic char const *cftypes[] = { 8231171Sbrian /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ 8331518Sbrian "OUI", /* 0: OUI */ 8431518Sbrian "PRED1", /* 1: Predictor type 1 */ 8531518Sbrian "PRED2", /* 2: Predictor type 2 */ 8631518Sbrian "PUDDLE", /* 3: Puddle Jumber */ 8731518Sbrian "???", "???", "???", "???", "???", "???", 8831518Sbrian "???", "???", "???", "???", "???", "???", 8931518Sbrian "HWPPC", /* 16: Hewlett-Packard PPC */ 9031518Sbrian "STAC", /* 17: Stac Electronics LZS (rfc1974) */ 9131518Sbrian "MSPPC", /* 18: Microsoft PPC */ 9231518Sbrian "GAND", /* 19: Gandalf FZA (rfc1993) */ 9331518Sbrian "V42BIS", /* 20: ARG->DATA.42bis compression */ 9431518Sbrian "BSD", /* 21: BSD LZW Compress */ 9531518Sbrian "???", 9631518Sbrian "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ 9731518Sbrian "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ 9831518Sbrian /* 24: Deflate (according to pppd-2.3.1) */ 9931518Sbrian "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ 10031518Sbrian "DEFLATE", /* 26: Deflate (rfc1979) */ 1016059Samurai}; 1026059Samurai 10331962Sbrian#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 10431171Sbrian 10531514Sbrianstatic const char * 10631514Sbrianprotoname(int proto) 10731514Sbrian{ 10831514Sbrian if (proto < 0 || proto > NCFTYPES) 10931514Sbrian return "none"; 11031514Sbrian return cftypes[proto]; 11131514Sbrian} 11231514Sbrian 11331518Sbrian/* We support these algorithms, and Req them in the given order */ 11431514Sbrianstatic const struct ccp_algorithm *algorithm[] = { 11531518Sbrian &DeflateAlgorithm, 11631514Sbrian &Pred1Algorithm, 11731518Sbrian &PppdDeflateAlgorithm 11831514Sbrian}; 11931514Sbrian 12031514Sbrianstatic int in_algorithm = -1; 12131514Sbrianstatic int out_algorithm = -1; 12231962Sbrian#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) 12331514Sbrian 12425630Sbrianint 12531343SbrianReportCcpStatus(struct cmdargs const *arg) 1266059Samurai{ 12726516Sbrian if (VarTerm) { 12831539Sbrian fprintf(VarTerm, "%s [%s]\n", CcpFsm.name, StateNames[CcpFsm.state]); 12931514Sbrian fprintf(VarTerm, "My protocol = %s, His protocol = %s\n", 13031539Sbrian protoname(CcpInfo.my_proto), protoname(CcpInfo.his_proto)); 13131514Sbrian fprintf(VarTerm, "Output: %ld --> %ld, Input: %ld --> %ld\n", 13231539Sbrian CcpInfo.uncompout, CcpInfo.compout, 13331539Sbrian CcpInfo.compin, CcpInfo.uncompin); 13426516Sbrian } 13525630Sbrian return 0; 1366059Samurai} 1376059Samurai 13831539Sbrianstatic void 13931539SbrianccpstateInit(void) 1406059Samurai{ 14132246Sbrian if (CcpInfo.in_init) 14232246Sbrian (*algorithm[in_algorithm]->i.Term)(); 14332246Sbrian if (CcpInfo.out_init) 14432246Sbrian (*algorithm[out_algorithm]->o.Term)(); 14532246Sbrian in_algorithm = -1; 14632246Sbrian out_algorithm = -1; 14731962Sbrian memset(&CcpInfo, '\0', sizeof CcpInfo); 14831539Sbrian CcpInfo.his_proto = CcpInfo.my_proto = -1; 14932381Sbrian CcpInfo.reset_sent = CcpInfo.last_reset = -1; 15031539Sbrian} 15131539Sbrian 15231539Sbrianvoid 15331539SbrianCcpInit() 15431539Sbrian{ 15531539Sbrian FsmInit(&CcpFsm); 15631539Sbrian ccpstateInit(); 1576059Samurai CcpFsm.maxconfig = 10; 1586059Samurai} 1596059Samurai 1606059Samuraistatic void 16130715SbrianCcpInitRestartCounter(struct fsm *fp) 1626059Samurai{ 1636735Samurai fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 1646059Samurai fp->restart = 5; 1656059Samurai} 1666059Samurai 1676059Samuraistatic void 16830715SbrianCcpSendConfigReq(struct fsm *fp) 1696059Samurai{ 1706059Samurai u_char *cp; 17131514Sbrian int f; 1726059Samurai 17331514Sbrian LogPrintf(LogCCP, "CcpSendConfigReq\n"); 1746059Samurai cp = ReqBuff; 17531514Sbrian CcpInfo.my_proto = -1; 17631514Sbrian out_algorithm = -1; 17731514Sbrian for (f = 0; f < NALGORITHMS; f++) 17831539Sbrian if (Enabled(algorithm[f]->Conf) && !REJECTED(&CcpInfo, algorithm[f]->id)) { 17931514Sbrian struct lcp_opt o; 18031514Sbrian 18131514Sbrian (*algorithm[f]->o.Get)(&o); 18231514Sbrian cp += LcpPutConf(LogCCP, cp, &o, cftypes[o.id], 18331514Sbrian (*algorithm[f]->Disp)(&o)); 18431514Sbrian CcpInfo.my_proto = o.id; 18531514Sbrian out_algorithm = f; 18631514Sbrian } 1876059Samurai FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 1886059Samurai} 1896059Samurai 1906059Samuraivoid 19130715SbrianCcpSendResetReq(struct fsm *fp) 1926059Samurai{ 19332381Sbrian LogPrintf(LogCCP, "SendResetReq(%d)\n", fp->reqid); 19432381Sbrian CcpInfo.reset_sent = fp->reqid; 19532381Sbrian CcpInfo.last_reset = -1; 1966059Samurai FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0); 1976059Samurai} 1986059Samurai 1996059Samuraistatic void 20030715SbrianCcpSendTerminateReq(struct fsm *fp) 2016059Samurai{ 2026059Samurai /* XXX: No code yet */ 2036059Samurai} 2046059Samurai 2056059Samuraistatic void 20630715SbrianCcpSendTerminateAck(struct fsm *fp) 2076059Samurai{ 20828461Sbrian LogPrintf(LogCCP, "CcpSendTerminateAck\n"); 2096059Samurai FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 2106059Samurai} 2116059Samurai 2126059Samuraivoid 21330715SbrianCcpRecvResetReq(struct fsm *fp) 2146059Samurai{ 21531514Sbrian if (out_algorithm >= 0 && out_algorithm < NALGORITHMS) 21631514Sbrian (*algorithm[out_algorithm]->o.Reset)(); 2176059Samurai} 2186059Samurai 2196059Samuraistatic void 22030715SbrianCcpLayerStart(struct fsm *fp) 2216059Samurai{ 22228461Sbrian LogPrintf(LogCCP, "CcpLayerStart.\n"); 2236059Samurai} 2246059Samurai 2256059Samuraistatic void 22630715SbrianCcpLayerFinish(struct fsm *fp) 2276059Samurai{ 22828461Sbrian LogPrintf(LogCCP, "CcpLayerFinish.\n"); 22931539Sbrian ccpstateInit(); 2306059Samurai} 2316059Samurai 2326059Samuraistatic void 23330715SbrianCcpLayerDown(struct fsm *fp) 2346059Samurai{ 23528461Sbrian LogPrintf(LogCCP, "CcpLayerDown.\n"); 23631539Sbrian ccpstateInit(); 2376059Samurai} 2386059Samurai 2396059Samurai/* 24031514Sbrian * Called when CCP has reached the OPEN state 2416059Samurai */ 2426059Samuraistatic void 24330715SbrianCcpLayerUp(struct fsm *fp) 2446059Samurai{ 24528461Sbrian LogPrintf(LogCCP, "CcpLayerUp(%d).\n", fp->state); 24631514Sbrian LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n", 24731514Sbrian protoname(CcpInfo.my_proto), CcpInfo.my_proto, 24831514Sbrian protoname(CcpInfo.his_proto), CcpInfo.his_proto); 24932246Sbrian if (!CcpInfo.in_init && in_algorithm >= 0 && in_algorithm < NALGORITHMS) { 25031514Sbrian (*algorithm[in_algorithm]->i.Init)(); 25132246Sbrian CcpInfo.in_init = 1; 25232246Sbrian } 25332246Sbrian if (!CcpInfo.out_init && out_algorithm >= 0 && out_algorithm < NALGORITHMS) { 25431514Sbrian (*algorithm[out_algorithm]->o.Init)(); 25532246Sbrian CcpInfo.out_init = 1; 25632246Sbrian } 2576059Samurai} 2586059Samurai 2596059Samuraivoid 2606059SamuraiCcpUp() 2616059Samurai{ 2626059Samurai FsmUp(&CcpFsm); 26328461Sbrian LogPrintf(LogCCP, "CCP Up event!!\n"); 2646059Samurai} 2656059Samurai 2666059Samuraivoid 2676059SamuraiCcpOpen() 2686059Samurai{ 26931514Sbrian int f; 27031514Sbrian 27131514Sbrian for (f = 0; f < NALGORITHMS; f++) 27231514Sbrian if (Enabled(algorithm[f]->Conf)) { 27331514Sbrian CcpFsm.open_mode = OPEN_ACTIVE; 27431514Sbrian FsmOpen(&CcpFsm); 27531514Sbrian break; 27631514Sbrian } 27731514Sbrian 27831514Sbrian if (f == NALGORITHMS) 27931514Sbrian for (f = 0; f < NALGORITHMS; f++) 28031514Sbrian if (Acceptable(algorithm[f]->Conf)) { 28131514Sbrian CcpFsm.open_mode = OPEN_PASSIVE; 28231514Sbrian FsmOpen(&CcpFsm); 28331514Sbrian break; 28431514Sbrian } 2856059Samurai} 2866059Samurai 2876059Samuraistatic void 28831034SbrianCcpDecodeConfig(u_char *cp, int plen, int mode_type) 2896059Samurai{ 2906735Samurai int type, length; 29131514Sbrian int f; 2926059Samurai 2936059Samurai ackp = AckBuff; 2946059Samurai nakp = NakBuff; 2956059Samurai rejp = RejBuff; 2966059Samurai 2976059Samurai while (plen >= sizeof(struct fsmconfig)) { 2986059Samurai type = *cp; 2996059Samurai length = cp[1]; 30031171Sbrian if (type < NCFTYPES) 30131514Sbrian LogPrintf(LogCCP, " %s[%d]\n", cftypes[type], length); 3026059Samurai else 30331514Sbrian LogPrintf(LogCCP, " ???[%d]\n", length); 3046059Samurai 30531514Sbrian for (f = NALGORITHMS-1; f > -1; f--) 30631514Sbrian if (algorithm[f]->id == type) 30731514Sbrian break; 3086059Samurai 30931514Sbrian if (f == -1) { 31031514Sbrian /* Don't understand that :-( */ 31131514Sbrian if (mode_type == MODE_REQ) { 31231514Sbrian CcpInfo.my_reject |= (1 << type); 31331514Sbrian memcpy(rejp, cp, length); 31431514Sbrian rejp += length; 31531514Sbrian } 31631514Sbrian } else { 31731514Sbrian struct lcp_opt o; 31831514Sbrian 31931034Sbrian switch (mode_type) { 3206059Samurai case MODE_REQ: 32131514Sbrian if (Acceptable(algorithm[f]->Conf) && in_algorithm == -1) { 32231514Sbrian memcpy(&o, cp, length); 32331514Sbrian switch ((*algorithm[f]->i.Set)(&o)) { 32431514Sbrian case MODE_REJ: 32531514Sbrian memcpy(rejp, &o, o.len); 32631514Sbrian rejp += o.len; 32731514Sbrian break; 32831514Sbrian case MODE_NAK: 32931514Sbrian memcpy(nakp, &o, o.len); 33031514Sbrian nakp += o.len; 33131514Sbrian break; 33231514Sbrian case MODE_ACK: 33331514Sbrian memcpy(ackp, cp, length); 33431514Sbrian ackp += length; 33531514Sbrian CcpInfo.his_proto = type; 33631514Sbrian in_algorithm = f; /* This one'll do ! */ 33731514Sbrian break; 33831514Sbrian } 3396059Samurai } else { 34030715Sbrian memcpy(rejp, cp, length); 3416059Samurai rejp += length; 3426059Samurai } 3436059Samurai break; 3446059Samurai case MODE_NAK: 34531514Sbrian memcpy(&o, cp, length); 34631514Sbrian if ((*algorithm[f]->o.Set)(&o) == MODE_ACK) 34731514Sbrian CcpInfo.my_proto = algorithm[f]->id; 34831514Sbrian else { 34931514Sbrian CcpInfo.his_reject |= (1 << type); 35031514Sbrian CcpInfo.my_proto = -1; 35131514Sbrian } 35231514Sbrian break; 3536059Samurai case MODE_REJ: 3546059Samurai CcpInfo.his_reject |= (1 << type); 35531514Sbrian CcpInfo.my_proto = -1; 3566059Samurai break; 3576059Samurai } 3586059Samurai } 35931514Sbrian 3606059Samurai plen -= length; 3616059Samurai cp += length; 3626059Samurai } 36331514Sbrian 36431514Sbrian if (rejp != RejBuff) { 36531514Sbrian ackp = AckBuff; /* let's not send both ! */ 36631514Sbrian CcpInfo.his_proto = -1; 36731514Sbrian in_algorithm = -1; 36831514Sbrian } 3696059Samurai} 3706059Samurai 3716059Samuraivoid 37230715SbrianCcpInput(struct mbuf *bp) 3736059Samurai{ 3746059Samurai if (phase == PHASE_NETWORK) 3756059Samurai FsmInput(&CcpFsm, bp); 3766059Samurai else { 37729294Sbrian if (phase > PHASE_NETWORK) 37831690Sbrian LogPrintf(LogCCP, "Error: Unexpected CCP in phase %d\n", phase); 3796059Samurai pfree(bp); 3806059Samurai } 3816059Samurai} 38231514Sbrian 38331514Sbrianvoid 38432381SbrianCcpResetInput(u_char id) 38531514Sbrian{ 38632381Sbrian if (CcpInfo.reset_sent != -1) { 38732381Sbrian if (id != CcpInfo.reset_sent) { 38832381Sbrian LogPrintf(LogWARN, "CCP: Incorrect ResetAck (id %d, not %d) ignored\n", 38932381Sbrian id, CcpInfo.reset_sent); 39032381Sbrian return; 39132381Sbrian } 39232381Sbrian /* Whaddaya know - a correct reset ack */ 39332381Sbrian } else if (id == CcpInfo.last_reset) 39432381Sbrian LogPrintf(LogCCP, "Duplicate ResetAck (resetting again)\n"); 39532381Sbrian else { 39632381Sbrian LogPrintf(LogWARN, "CCP: Unexpected ResetAck (id %d) ignored\n", id); 39732381Sbrian return; 39832381Sbrian } 39932381Sbrian 40032381Sbrian CcpInfo.last_reset = CcpInfo.reset_sent; 40132381Sbrian CcpInfo.reset_sent = -1; 40231514Sbrian if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) 40331514Sbrian (*algorithm[in_algorithm]->i.Reset)(); 40431514Sbrian} 40531514Sbrian 40631514Sbrianint 40731514SbrianCcpOutput(int pri, u_short proto, struct mbuf *m) 40831514Sbrian{ 40931514Sbrian if (out_algorithm >= 0 && out_algorithm < NALGORITHMS) 41031514Sbrian return (*algorithm[out_algorithm]->o.Write)(pri, proto, m); 41131514Sbrian return 0; 41231514Sbrian} 41331514Sbrian 41431514Sbrianstruct mbuf * 41531514SbrianCompdInput(u_short *proto, struct mbuf *m) 41631514Sbrian{ 41732381Sbrian if (CcpInfo.reset_sent != -1) { 41832381Sbrian /* Send another REQ and put the packet in the bit bucket */ 41932381Sbrian LogPrintf(LogCCP, "ReSendResetReq(%d)\n", CcpInfo.reset_sent); 42032381Sbrian FsmOutput(&CcpFsm, CODE_RESETREQ, CcpInfo.reset_sent, NULL, 0); 42132381Sbrian pfree(m); 42232381Sbrian } else if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) 42331514Sbrian return (*algorithm[in_algorithm]->i.Read)(proto, m); 42431514Sbrian return NULL; 42531514Sbrian} 42631514Sbrian 42731514Sbrianvoid 42831514SbrianCcpDictSetup(u_short proto, struct mbuf *m) 42931514Sbrian{ 43031514Sbrian if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) 43131514Sbrian (*algorithm[in_algorithm]->i.DictSetup)(proto, m); 43231514Sbrian} 433