ccp.c revision 32381
1/* 2 * PPP Compression Control Protocol (CCP) Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: ccp.c,v 1.27 1998/01/04 20:25:39 brian Exp $ 21 * 22 * TODO: 23 * o Support other compression protocols 24 */ 25#include <sys/param.h> 26#include <netinet/in.h> 27 28#include <stdio.h> 29#include <string.h> 30 31#include "command.h" 32#include "mbuf.h" 33#include "log.h" 34#include "defs.h" 35#include "timer.h" 36#include "fsm.h" 37#include "lcpproto.h" 38#include "lcp.h" 39#include "ccp.h" 40#include "phase.h" 41#include "loadalias.h" 42#include "vars.h" 43#include "pred.h" 44#include "deflate.h" 45 46struct ccpstate CcpInfo = { -1, -1, -1, -1 }; 47 48static void CcpSendConfigReq(struct fsm *); 49static void CcpSendTerminateReq(struct fsm *); 50static void CcpSendTerminateAck(struct fsm *); 51static void CcpDecodeConfig(u_char *, int, int); 52static void CcpLayerStart(struct fsm *); 53static void CcpLayerFinish(struct fsm *); 54static void CcpLayerUp(struct fsm *); 55static void CcpLayerDown(struct fsm *); 56static void CcpInitRestartCounter(struct fsm *); 57 58struct fsm CcpFsm = { 59 "CCP", 60 PROTO_CCP, 61 CCP_MAXCODE, 62 OPEN_ACTIVE, 63 ST_INITIAL, 64 0, 0, 0, 65 0, 66 {0, 0, 0, NULL, NULL, NULL}, 67 {0, 0, 0, NULL, NULL, NULL}, 68 LogCCP, 69 70 CcpLayerUp, 71 CcpLayerDown, 72 CcpLayerStart, 73 CcpLayerFinish, 74 CcpInitRestartCounter, 75 CcpSendConfigReq, 76 CcpSendTerminateReq, 77 CcpSendTerminateAck, 78 CcpDecodeConfig, 79}; 80 81static char const *cftypes[] = { 82 /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ 83 "OUI", /* 0: OUI */ 84 "PRED1", /* 1: Predictor type 1 */ 85 "PRED2", /* 2: Predictor type 2 */ 86 "PUDDLE", /* 3: Puddle Jumber */ 87 "???", "???", "???", "???", "???", "???", 88 "???", "???", "???", "???", "???", "???", 89 "HWPPC", /* 16: Hewlett-Packard PPC */ 90 "STAC", /* 17: Stac Electronics LZS (rfc1974) */ 91 "MSPPC", /* 18: Microsoft PPC */ 92 "GAND", /* 19: Gandalf FZA (rfc1993) */ 93 "V42BIS", /* 20: ARG->DATA.42bis compression */ 94 "BSD", /* 21: BSD LZW Compress */ 95 "???", 96 "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ 97 "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ 98 /* 24: Deflate (according to pppd-2.3.1) */ 99 "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ 100 "DEFLATE", /* 26: Deflate (rfc1979) */ 101}; 102 103#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 104 105static const char * 106protoname(int proto) 107{ 108 if (proto < 0 || proto > NCFTYPES) 109 return "none"; 110 return cftypes[proto]; 111} 112 113/* We support these algorithms, and Req them in the given order */ 114static const struct ccp_algorithm *algorithm[] = { 115 &DeflateAlgorithm, 116 &Pred1Algorithm, 117 &PppdDeflateAlgorithm 118}; 119 120static int in_algorithm = -1; 121static int out_algorithm = -1; 122#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) 123 124int 125ReportCcpStatus(struct cmdargs const *arg) 126{ 127 if (VarTerm) { 128 fprintf(VarTerm, "%s [%s]\n", CcpFsm.name, StateNames[CcpFsm.state]); 129 fprintf(VarTerm, "My protocol = %s, His protocol = %s\n", 130 protoname(CcpInfo.my_proto), protoname(CcpInfo.his_proto)); 131 fprintf(VarTerm, "Output: %ld --> %ld, Input: %ld --> %ld\n", 132 CcpInfo.uncompout, CcpInfo.compout, 133 CcpInfo.compin, CcpInfo.uncompin); 134 } 135 return 0; 136} 137 138static void 139ccpstateInit(void) 140{ 141 if (CcpInfo.in_init) 142 (*algorithm[in_algorithm]->i.Term)(); 143 if (CcpInfo.out_init) 144 (*algorithm[out_algorithm]->o.Term)(); 145 in_algorithm = -1; 146 out_algorithm = -1; 147 memset(&CcpInfo, '\0', sizeof CcpInfo); 148 CcpInfo.his_proto = CcpInfo.my_proto = -1; 149 CcpInfo.reset_sent = CcpInfo.last_reset = -1; 150} 151 152void 153CcpInit() 154{ 155 FsmInit(&CcpFsm); 156 ccpstateInit(); 157 CcpFsm.maxconfig = 10; 158} 159 160static void 161CcpInitRestartCounter(struct fsm *fp) 162{ 163 fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 164 fp->restart = 5; 165} 166 167static void 168CcpSendConfigReq(struct fsm *fp) 169{ 170 u_char *cp; 171 int f; 172 173 LogPrintf(LogCCP, "CcpSendConfigReq\n"); 174 cp = ReqBuff; 175 CcpInfo.my_proto = -1; 176 out_algorithm = -1; 177 for (f = 0; f < NALGORITHMS; f++) 178 if (Enabled(algorithm[f]->Conf) && !REJECTED(&CcpInfo, algorithm[f]->id)) { 179 struct lcp_opt o; 180 181 (*algorithm[f]->o.Get)(&o); 182 cp += LcpPutConf(LogCCP, cp, &o, cftypes[o.id], 183 (*algorithm[f]->Disp)(&o)); 184 CcpInfo.my_proto = o.id; 185 out_algorithm = f; 186 } 187 FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 188} 189 190void 191CcpSendResetReq(struct fsm *fp) 192{ 193 LogPrintf(LogCCP, "SendResetReq(%d)\n", fp->reqid); 194 CcpInfo.reset_sent = fp->reqid; 195 CcpInfo.last_reset = -1; 196 FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0); 197} 198 199static void 200CcpSendTerminateReq(struct fsm *fp) 201{ 202 /* XXX: No code yet */ 203} 204 205static void 206CcpSendTerminateAck(struct fsm *fp) 207{ 208 LogPrintf(LogCCP, "CcpSendTerminateAck\n"); 209 FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 210} 211 212void 213CcpRecvResetReq(struct fsm *fp) 214{ 215 if (out_algorithm >= 0 && out_algorithm < NALGORITHMS) 216 (*algorithm[out_algorithm]->o.Reset)(); 217} 218 219static void 220CcpLayerStart(struct fsm *fp) 221{ 222 LogPrintf(LogCCP, "CcpLayerStart.\n"); 223} 224 225static void 226CcpLayerFinish(struct fsm *fp) 227{ 228 LogPrintf(LogCCP, "CcpLayerFinish.\n"); 229 ccpstateInit(); 230} 231 232static void 233CcpLayerDown(struct fsm *fp) 234{ 235 LogPrintf(LogCCP, "CcpLayerDown.\n"); 236 ccpstateInit(); 237} 238 239/* 240 * Called when CCP has reached the OPEN state 241 */ 242static void 243CcpLayerUp(struct fsm *fp) 244{ 245 LogPrintf(LogCCP, "CcpLayerUp(%d).\n", fp->state); 246 LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n", 247 protoname(CcpInfo.my_proto), CcpInfo.my_proto, 248 protoname(CcpInfo.his_proto), CcpInfo.his_proto); 249 if (!CcpInfo.in_init && in_algorithm >= 0 && in_algorithm < NALGORITHMS) { 250 (*algorithm[in_algorithm]->i.Init)(); 251 CcpInfo.in_init = 1; 252 } 253 if (!CcpInfo.out_init && out_algorithm >= 0 && out_algorithm < NALGORITHMS) { 254 (*algorithm[out_algorithm]->o.Init)(); 255 CcpInfo.out_init = 1; 256 } 257} 258 259void 260CcpUp() 261{ 262 FsmUp(&CcpFsm); 263 LogPrintf(LogCCP, "CCP Up event!!\n"); 264} 265 266void 267CcpOpen() 268{ 269 int f; 270 271 for (f = 0; f < NALGORITHMS; f++) 272 if (Enabled(algorithm[f]->Conf)) { 273 CcpFsm.open_mode = OPEN_ACTIVE; 274 FsmOpen(&CcpFsm); 275 break; 276 } 277 278 if (f == NALGORITHMS) 279 for (f = 0; f < NALGORITHMS; f++) 280 if (Acceptable(algorithm[f]->Conf)) { 281 CcpFsm.open_mode = OPEN_PASSIVE; 282 FsmOpen(&CcpFsm); 283 break; 284 } 285} 286 287static void 288CcpDecodeConfig(u_char *cp, int plen, int mode_type) 289{ 290 int type, length; 291 int f; 292 293 ackp = AckBuff; 294 nakp = NakBuff; 295 rejp = RejBuff; 296 297 while (plen >= sizeof(struct fsmconfig)) { 298 type = *cp; 299 length = cp[1]; 300 if (type < NCFTYPES) 301 LogPrintf(LogCCP, " %s[%d]\n", cftypes[type], length); 302 else 303 LogPrintf(LogCCP, " ???[%d]\n", length); 304 305 for (f = NALGORITHMS-1; f > -1; f--) 306 if (algorithm[f]->id == type) 307 break; 308 309 if (f == -1) { 310 /* Don't understand that :-( */ 311 if (mode_type == MODE_REQ) { 312 CcpInfo.my_reject |= (1 << type); 313 memcpy(rejp, cp, length); 314 rejp += length; 315 } 316 } else { 317 struct lcp_opt o; 318 319 switch (mode_type) { 320 case MODE_REQ: 321 if (Acceptable(algorithm[f]->Conf) && in_algorithm == -1) { 322 memcpy(&o, cp, length); 323 switch ((*algorithm[f]->i.Set)(&o)) { 324 case MODE_REJ: 325 memcpy(rejp, &o, o.len); 326 rejp += o.len; 327 break; 328 case MODE_NAK: 329 memcpy(nakp, &o, o.len); 330 nakp += o.len; 331 break; 332 case MODE_ACK: 333 memcpy(ackp, cp, length); 334 ackp += length; 335 CcpInfo.his_proto = type; 336 in_algorithm = f; /* This one'll do ! */ 337 break; 338 } 339 } else { 340 memcpy(rejp, cp, length); 341 rejp += length; 342 } 343 break; 344 case MODE_NAK: 345 memcpy(&o, cp, length); 346 if ((*algorithm[f]->o.Set)(&o) == MODE_ACK) 347 CcpInfo.my_proto = algorithm[f]->id; 348 else { 349 CcpInfo.his_reject |= (1 << type); 350 CcpInfo.my_proto = -1; 351 } 352 break; 353 case MODE_REJ: 354 CcpInfo.his_reject |= (1 << type); 355 CcpInfo.my_proto = -1; 356 break; 357 } 358 } 359 360 plen -= length; 361 cp += length; 362 } 363 364 if (rejp != RejBuff) { 365 ackp = AckBuff; /* let's not send both ! */ 366 CcpInfo.his_proto = -1; 367 in_algorithm = -1; 368 } 369} 370 371void 372CcpInput(struct mbuf *bp) 373{ 374 if (phase == PHASE_NETWORK) 375 FsmInput(&CcpFsm, bp); 376 else { 377 if (phase > PHASE_NETWORK) 378 LogPrintf(LogCCP, "Error: Unexpected CCP in phase %d\n", phase); 379 pfree(bp); 380 } 381} 382 383void 384CcpResetInput(u_char id) 385{ 386 if (CcpInfo.reset_sent != -1) { 387 if (id != CcpInfo.reset_sent) { 388 LogPrintf(LogWARN, "CCP: Incorrect ResetAck (id %d, not %d) ignored\n", 389 id, CcpInfo.reset_sent); 390 return; 391 } 392 /* Whaddaya know - a correct reset ack */ 393 } else if (id == CcpInfo.last_reset) 394 LogPrintf(LogCCP, "Duplicate ResetAck (resetting again)\n"); 395 else { 396 LogPrintf(LogWARN, "CCP: Unexpected ResetAck (id %d) ignored\n", id); 397 return; 398 } 399 400 CcpInfo.last_reset = CcpInfo.reset_sent; 401 CcpInfo.reset_sent = -1; 402 if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) 403 (*algorithm[in_algorithm]->i.Reset)(); 404} 405 406int 407CcpOutput(int pri, u_short proto, struct mbuf *m) 408{ 409 if (out_algorithm >= 0 && out_algorithm < NALGORITHMS) 410 return (*algorithm[out_algorithm]->o.Write)(pri, proto, m); 411 return 0; 412} 413 414struct mbuf * 415CompdInput(u_short *proto, struct mbuf *m) 416{ 417 if (CcpInfo.reset_sent != -1) { 418 /* Send another REQ and put the packet in the bit bucket */ 419 LogPrintf(LogCCP, "ReSendResetReq(%d)\n", CcpInfo.reset_sent); 420 FsmOutput(&CcpFsm, CODE_RESETREQ, CcpInfo.reset_sent, NULL, 0); 421 pfree(m); 422 } else if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) 423 return (*algorithm[in_algorithm]->i.Read)(proto, m); 424 return NULL; 425} 426 427void 428CcpDictSetup(u_short proto, struct mbuf *m) 429{ 430 if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) 431 (*algorithm[in_algorithm]->i.DictSetup)(proto, m); 432} 433